import of ftp.dlink.com/GPL/DSMG-600_reB/ppclinux.tar.gz
[linux-2.4.21-pre4.git] / drivers / media / video / cpia.c
1 /*
2  * cpia CPiA driver
3  *
4  * Supports CPiA based Video Camera's.
5  *
6  * (C) Copyright 1999-2000 Peter Pregler
7  * (C) Copyright 1999-2000 Scott J. Bertin
8  * (C) Copyright 1999-2000 Johannes Erdfelt <johannes@erdfelt.com>
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23  */
24
25 /* #define _CPIA_DEBUG_         define for verbose debug output */
26 #include <linux/config.h>
27
28 #include <linux/module.h>
29 #include <linux/version.h>
30 #include <linux/init.h>
31 #include <linux/fs.h>
32 #include <linux/vmalloc.h>
33 #include <linux/delay.h>
34 #include <linux/slab.h>
35 #include <linux/proc_fs.h>
36 #include <linux/ctype.h>
37 #include <linux/pagemap.h>
38 #include <asm/io.h>
39 #include <asm/semaphore.h>
40 #include <linux/wrapper.h>
41
42 #ifdef CONFIG_KMOD
43 #include <linux/kmod.h>
44 #endif
45
46 #include "cpia.h"
47
48 #ifdef CONFIG_VIDEO_CPIA_PP
49 extern int cpia_pp_init(void);
50 #endif
51 #ifdef CONFIG_VIDEO_CPIA_USB
52 extern int cpia_usb_init(void);
53 #endif
54
55 static int video_nr = -1;
56
57 #ifdef MODULE
58 MODULE_PARM(video_nr,"i");
59 MODULE_AUTHOR("Scott J. Bertin <sbertin@securenym.net> & Peter Pregler <Peter_Pregler@email.com> & Johannes Erdfelt <johannes@erdfeld.com>");
60 MODULE_DESCRIPTION("V4L-driver for Vision CPiA based cameras");
61 MODULE_LICENSE("GPL");
62 MODULE_SUPPORTED_DEVICE("video");
63 #endif
64
65 #define ABOUT "V4L-Driver for Vision CPiA based cameras"
66
67 #ifndef VID_HARDWARE_CPIA
68 #define VID_HARDWARE_CPIA 24    /* FIXME -> from linux/videodev.h */
69 #endif
70
71 #define CPIA_MODULE_CPIA                        (0<<5)
72 #define CPIA_MODULE_SYSTEM                      (1<<5)
73 #define CPIA_MODULE_VP_CTRL                     (5<<5)
74 #define CPIA_MODULE_CAPTURE                     (6<<5)
75 #define CPIA_MODULE_DEBUG                       (7<<5)
76
77 #define INPUT (DATA_IN << 8)
78 #define OUTPUT (DATA_OUT << 8)
79
80 #define CPIA_COMMAND_GetCPIAVersion     (INPUT | CPIA_MODULE_CPIA | 1)
81 #define CPIA_COMMAND_GetPnPID           (INPUT | CPIA_MODULE_CPIA | 2)
82 #define CPIA_COMMAND_GetCameraStatus    (INPUT | CPIA_MODULE_CPIA | 3)
83 #define CPIA_COMMAND_GotoHiPower        (OUTPUT | CPIA_MODULE_CPIA | 4)
84 #define CPIA_COMMAND_GotoLoPower        (OUTPUT | CPIA_MODULE_CPIA | 5)
85 #define CPIA_COMMAND_GotoSuspend        (OUTPUT | CPIA_MODULE_CPIA | 7)
86 #define CPIA_COMMAND_GotoPassThrough    (OUTPUT | CPIA_MODULE_CPIA | 8)
87 #define CPIA_COMMAND_ModifyCameraStatus (OUTPUT | CPIA_MODULE_CPIA | 10)
88
89 #define CPIA_COMMAND_ReadVCRegs         (INPUT | CPIA_MODULE_SYSTEM | 1)
90 #define CPIA_COMMAND_WriteVCReg         (OUTPUT | CPIA_MODULE_SYSTEM | 2)
91 #define CPIA_COMMAND_ReadMCPorts        (INPUT | CPIA_MODULE_SYSTEM | 3)
92 #define CPIA_COMMAND_WriteMCPort        (OUTPUT | CPIA_MODULE_SYSTEM | 4)
93 #define CPIA_COMMAND_SetBaudRate        (OUTPUT | CPIA_MODULE_SYSTEM | 5)
94 #define CPIA_COMMAND_SetECPTiming       (OUTPUT | CPIA_MODULE_SYSTEM | 6)
95 #define CPIA_COMMAND_ReadIDATA          (INPUT | CPIA_MODULE_SYSTEM | 7)
96 #define CPIA_COMMAND_WriteIDATA         (OUTPUT | CPIA_MODULE_SYSTEM | 8)
97 #define CPIA_COMMAND_GenericCall        (OUTPUT | CPIA_MODULE_SYSTEM | 9)
98 #define CPIA_COMMAND_I2CStart           (OUTPUT | CPIA_MODULE_SYSTEM | 10)
99 #define CPIA_COMMAND_I2CStop            (OUTPUT | CPIA_MODULE_SYSTEM | 11)
100 #define CPIA_COMMAND_I2CWrite           (OUTPUT | CPIA_MODULE_SYSTEM | 12)
101 #define CPIA_COMMAND_I2CRead            (INPUT | CPIA_MODULE_SYSTEM | 13)
102
103 #define CPIA_COMMAND_GetVPVersion       (INPUT | CPIA_MODULE_VP_CTRL | 1)
104 #define CPIA_COMMAND_SetColourParams    (OUTPUT | CPIA_MODULE_VP_CTRL | 3)
105 #define CPIA_COMMAND_SetExposure        (OUTPUT | CPIA_MODULE_VP_CTRL | 4)
106 #define CPIA_COMMAND_SetColourBalance   (OUTPUT | CPIA_MODULE_VP_CTRL | 6)
107 #define CPIA_COMMAND_SetSensorFPS       (OUTPUT | CPIA_MODULE_VP_CTRL | 7)
108 #define CPIA_COMMAND_SetVPDefaults      (OUTPUT | CPIA_MODULE_VP_CTRL | 8)
109 #define CPIA_COMMAND_SetApcor           (OUTPUT | CPIA_MODULE_VP_CTRL | 9)
110 #define CPIA_COMMAND_SetFlickerCtrl     (OUTPUT | CPIA_MODULE_VP_CTRL | 10)
111 #define CPIA_COMMAND_SetVLOffset        (OUTPUT | CPIA_MODULE_VP_CTRL | 11)
112 #define CPIA_COMMAND_GetColourParams    (INPUT | CPIA_MODULE_VP_CTRL | 16)
113 #define CPIA_COMMAND_GetColourBalance   (INPUT | CPIA_MODULE_VP_CTRL | 17)
114 #define CPIA_COMMAND_GetExposure        (INPUT | CPIA_MODULE_VP_CTRL | 18)
115 #define CPIA_COMMAND_SetSensorMatrix    (OUTPUT | CPIA_MODULE_VP_CTRL | 19)
116 #define CPIA_COMMAND_ColourBars         (OUTPUT | CPIA_MODULE_VP_CTRL | 25)
117 #define CPIA_COMMAND_ReadVPRegs         (INPUT | CPIA_MODULE_VP_CTRL | 30)
118 #define CPIA_COMMAND_WriteVPReg         (OUTPUT | CPIA_MODULE_VP_CTRL | 31)
119
120 #define CPIA_COMMAND_GrabFrame          (OUTPUT | CPIA_MODULE_CAPTURE | 1)
121 #define CPIA_COMMAND_UploadFrame        (OUTPUT | CPIA_MODULE_CAPTURE | 2)
122 #define CPIA_COMMAND_SetGrabMode        (OUTPUT | CPIA_MODULE_CAPTURE | 3)
123 #define CPIA_COMMAND_InitStreamCap      (OUTPUT | CPIA_MODULE_CAPTURE | 4)
124 #define CPIA_COMMAND_FiniStreamCap      (OUTPUT | CPIA_MODULE_CAPTURE | 5)
125 #define CPIA_COMMAND_StartStreamCap     (OUTPUT | CPIA_MODULE_CAPTURE | 6)
126 #define CPIA_COMMAND_EndStreamCap       (OUTPUT | CPIA_MODULE_CAPTURE | 7)
127 #define CPIA_COMMAND_SetFormat          (OUTPUT | CPIA_MODULE_CAPTURE | 8)
128 #define CPIA_COMMAND_SetROI             (OUTPUT | CPIA_MODULE_CAPTURE | 9)
129 #define CPIA_COMMAND_SetCompression     (OUTPUT | CPIA_MODULE_CAPTURE | 10)
130 #define CPIA_COMMAND_SetCompressionTarget (OUTPUT | CPIA_MODULE_CAPTURE | 11)
131 #define CPIA_COMMAND_SetYUVThresh       (OUTPUT | CPIA_MODULE_CAPTURE | 12)
132 #define CPIA_COMMAND_SetCompressionParams (OUTPUT | CPIA_MODULE_CAPTURE | 13)
133 #define CPIA_COMMAND_DiscardFrame       (OUTPUT | CPIA_MODULE_CAPTURE | 14)
134
135 #define CPIA_COMMAND_OutputRS232        (OUTPUT | CPIA_MODULE_DEBUG | 1)
136 #define CPIA_COMMAND_AbortProcess       (OUTPUT | CPIA_MODULE_DEBUG | 4)
137 #define CPIA_COMMAND_SetDramPage        (OUTPUT | CPIA_MODULE_DEBUG | 5)
138 #define CPIA_COMMAND_StartDramUpload    (OUTPUT | CPIA_MODULE_DEBUG | 6)
139 #define CPIA_COMMAND_StartDummyDtream   (OUTPUT | CPIA_MODULE_DEBUG | 8)
140 #define CPIA_COMMAND_AbortStream        (OUTPUT | CPIA_MODULE_DEBUG | 9)
141 #define CPIA_COMMAND_DownloadDRAM       (OUTPUT | CPIA_MODULE_DEBUG | 10)
142
143 enum {
144         FRAME_READY,            /* Ready to grab into */
145         FRAME_GRABBING,         /* In the process of being grabbed into */
146         FRAME_DONE,             /* Finished grabbing, but not been synced yet */
147         FRAME_UNUSED,           /* Unused (no MCAPTURE) */
148 };
149
150 #define COMMAND_NONE                    0x0000
151 #define COMMAND_SETCOMPRESSION          0x0001
152 #define COMMAND_SETCOMPRESSIONTARGET    0x0002
153 #define COMMAND_SETCOLOURPARAMS         0x0004
154 #define COMMAND_SETFORMAT               0x0008
155 #define COMMAND_PAUSE                   0x0010
156 #define COMMAND_RESUME                  0x0020
157 #define COMMAND_SETYUVTHRESH            0x0040
158 #define COMMAND_SETECPTIMING            0x0080
159 #define COMMAND_SETCOMPRESSIONPARAMS    0x0100
160 #define COMMAND_SETEXPOSURE             0x0200
161 #define COMMAND_SETCOLOURBALANCE        0x0400
162 #define COMMAND_SETSENSORFPS            0x0800
163 #define COMMAND_SETAPCOR                0x1000
164 #define COMMAND_SETFLICKERCTRL          0x2000
165 #define COMMAND_SETVLOFFSET             0x4000
166 #define COMMAND_SETLIGHTS               0x8000
167
168 /* Developer's Guide Table 5 p 3-34
169  * indexed by [mains][sensorFps.baserate][sensorFps.divisor]*/
170 static u8 flicker_jumps[2][2][4] =
171 { { { 76, 38, 19, 9 }, { 92, 46, 23, 11 } },
172   { { 64, 32, 16, 8 }, { 76, 38, 19, 9} }
173 };
174
175 /* forward declaration of local function */
176 static void reset_camera_struct(struct cam_data *cam);
177
178 /**********************************************************************
179  *
180  * Memory management
181  *
182  **********************************************************************/
183
184 /* Here we want the physical address of the memory.
185  * This is used when initializing the contents of the area.
186  */
187 static inline unsigned long kvirt_to_pa(unsigned long adr)
188 {
189         unsigned long kva, ret;
190
191         kva = (unsigned long) page_address(vmalloc_to_page((void *)adr));
192         kva |= adr & (PAGE_SIZE-1); /* restore the offset */
193         ret = __pa(kva);
194         return ret;
195 }
196
197 static void *rvmalloc(unsigned long size)
198 {
199         void *mem;
200         unsigned long adr;
201
202         size = PAGE_ALIGN(size);
203         mem = vmalloc_32(size);
204         if (!mem)
205                 return NULL;
206
207         memset(mem, 0, size); /* Clear the ram out, no junk to the user */
208         adr = (unsigned long) mem;
209         while (size > 0) {
210                 mem_map_reserve(vmalloc_to_page((void *)adr));
211                 adr += PAGE_SIZE;
212                 size -= PAGE_SIZE;
213         }
214
215         return mem;
216 }
217
218 static void rvfree(void *mem, unsigned long size)
219 {
220         unsigned long adr;
221
222         if (!mem)
223                 return;
224
225         adr = (unsigned long) mem;
226         while ((long) size > 0) {
227                 mem_map_unreserve(vmalloc_to_page((void *)adr));
228                 adr += PAGE_SIZE;
229                 size -= PAGE_SIZE;
230         }
231         vfree(mem);
232 }
233
234 /**********************************************************************
235  *
236  * /proc interface
237  *
238  **********************************************************************/
239 #ifdef CONFIG_PROC_FS
240 static struct proc_dir_entry *cpia_proc_root=NULL;
241
242 static int cpia_read_proc(char *page, char **start, off_t off,
243                           int count, int *eof, void *data)
244 {
245         char *out = page;
246         int len, tmp;
247         struct cam_data *cam = data;
248         char tmpstr[29];
249
250         /* IMPORTANT: This output MUST be kept under PAGE_SIZE
251          *            or we need to get more sophisticated. */
252
253         out += sprintf(out, "read-only\n-----------------------\n");
254         out += sprintf(out, "V4L Driver version:       %d.%d.%d\n",
255                        CPIA_MAJ_VER, CPIA_MIN_VER, CPIA_PATCH_VER);
256         out += sprintf(out, "CPIA Version:             %d.%02d (%d.%d)\n",
257                        cam->params.version.firmwareVersion,
258                        cam->params.version.firmwareRevision,
259                        cam->params.version.vcVersion,
260                        cam->params.version.vcRevision);
261         out += sprintf(out, "CPIA PnP-ID:              %04x:%04x:%04x\n",
262                        cam->params.pnpID.vendor, cam->params.pnpID.product,
263                        cam->params.pnpID.deviceRevision);
264         out += sprintf(out, "VP-Version:               %d.%d %04x\n",
265                        cam->params.vpVersion.vpVersion,
266                        cam->params.vpVersion.vpRevision,
267                        cam->params.vpVersion.cameraHeadID);
268         
269         out += sprintf(out, "system_state:             %#04x\n",
270                        cam->params.status.systemState);
271         out += sprintf(out, "grab_state:               %#04x\n",
272                        cam->params.status.grabState);
273         out += sprintf(out, "stream_state:             %#04x\n",
274                        cam->params.status.streamState);
275         out += sprintf(out, "fatal_error:              %#04x\n",
276                        cam->params.status.fatalError);
277         out += sprintf(out, "cmd_error:                %#04x\n",
278                        cam->params.status.cmdError);
279         out += sprintf(out, "debug_flags:              %#04x\n",
280                        cam->params.status.debugFlags);
281         out += sprintf(out, "vp_status:                %#04x\n",
282                        cam->params.status.vpStatus);
283         out += sprintf(out, "error_code:               %#04x\n",
284                        cam->params.status.errorCode);
285         /* QX3 specific entries */
286         if (cam->params.qx3.qx3_detected) {
287                 out += sprintf(out, "button:                   %4d\n",
288                                cam->params.qx3.button);
289                 out += sprintf(out, "cradled:                  %4d\n",
290                                cam->params.qx3.cradled);
291         }
292         out += sprintf(out, "video_size:               %s\n",
293                        cam->params.format.videoSize == VIDEOSIZE_CIF ?
294                        "CIF " : "QCIF");
295         out += sprintf(out, "sub_sample:               %s\n",
296                        cam->params.format.subSample == SUBSAMPLE_420 ?
297                        "420" : "422");
298         out += sprintf(out, "yuv_order:                %s\n",
299                        cam->params.format.yuvOrder == YUVORDER_YUYV ?
300                        "YUYV" : "UYVY");
301         out += sprintf(out, "roi:                      (%3d, %3d) to (%3d, %3d)\n",
302                        cam->params.roi.colStart*8,
303                        cam->params.roi.rowStart*4,
304                        cam->params.roi.colEnd*8,
305                        cam->params.roi.rowEnd*4);
306         out += sprintf(out, "actual_fps:               %3d\n", cam->fps);
307         out += sprintf(out, "transfer_rate:            %4dkB/s\n",
308                        cam->transfer_rate);
309         
310         out += sprintf(out, "\nread-write\n");
311         out += sprintf(out, "-----------------------  current       min"
312                        "       max   default  comment\n");
313         out += sprintf(out, "brightness:             %8d  %8d  %8d  %8d\n",
314                        cam->params.colourParams.brightness, 0, 100, 50);
315         if (cam->params.version.firmwareVersion == 1 &&
316            cam->params.version.firmwareRevision == 2)
317                 /* 1-02 firmware limits contrast to 80 */
318                 tmp = 80;
319         else
320                 tmp = 96;
321
322         out += sprintf(out, "contrast:               %8d  %8d  %8d  %8d"
323                        "  steps of 8\n",
324                        cam->params.colourParams.contrast, 0, tmp, 48);
325         out += sprintf(out, "saturation:             %8d  %8d  %8d  %8d\n",
326                        cam->params.colourParams.saturation, 0, 100, 50);
327         tmp = (25000+5000*cam->params.sensorFps.baserate)/
328               (1<<cam->params.sensorFps.divisor);
329         out += sprintf(out, "sensor_fps:             %4d.%03d  %8d  %8d  %8d\n",
330                        tmp/1000, tmp%1000, 3, 30, 15);
331         out += sprintf(out, "stream_start_line:      %8d  %8d  %8d  %8d\n",
332                        2*cam->params.streamStartLine, 0,
333                        cam->params.format.videoSize == VIDEOSIZE_CIF ? 288:144,
334                        cam->params.format.videoSize == VIDEOSIZE_CIF ? 240:120);
335         out += sprintf(out, "ecp_timing:             %8s  %8s  %8s  %8s\n",
336                        cam->params.ecpTiming ? "slow" : "normal", "slow",
337                        "normal", "normal");
338
339         if (cam->params.colourBalance.balanceModeIsAuto) {
340                 sprintf(tmpstr, "auto");
341         } else {
342                 sprintf(tmpstr, "manual");
343         }
344         out += sprintf(out, "color_balance_mode:     %8s  %8s  %8s"
345                        "  %8s\n",  tmpstr, "manual", "auto", "auto");
346         out += sprintf(out, "red_gain:               %8d  %8d  %8d  %8d\n",
347                        cam->params.colourBalance.redGain, 0, 212, 32);
348         out += sprintf(out, "green_gain:             %8d  %8d  %8d  %8d\n",
349                        cam->params.colourBalance.greenGain, 0, 212, 6);
350         out += sprintf(out, "blue_gain:              %8d  %8d  %8d  %8d\n",
351                        cam->params.colourBalance.blueGain, 0, 212, 92);
352
353         if (cam->params.version.firmwareVersion == 1 &&
354            cam->params.version.firmwareRevision == 2)
355                 /* 1-02 firmware limits gain to 2 */
356                 sprintf(tmpstr, "%8d  %8d  %8d", 1, 2, 2);
357         else
358                 sprintf(tmpstr, "%8d  %8d  %8d", 1, 8, 2);
359
360         if (cam->params.exposure.gainMode == 0)
361                 out += sprintf(out, "max_gain:                unknown  %28s"
362                                "  powers of 2\n", tmpstr); 
363         else
364                 out += sprintf(out, "max_gain:               %8d  %28s"
365                                "  1,2,4 or 8 \n",
366                                1<<(cam->params.exposure.gainMode-1), tmpstr);
367
368         switch(cam->params.exposure.expMode) {
369         case 1:
370         case 3:
371                 sprintf(tmpstr, "manual");
372                 break;
373         case 2:
374                 sprintf(tmpstr, "auto");
375                 break;
376         default:
377                 sprintf(tmpstr, "unknown");
378                 break;
379         }
380         out += sprintf(out, "exposure_mode:          %8s  %8s  %8s"
381                        "  %8s\n",  tmpstr, "manual", "auto", "auto");
382         out += sprintf(out, "centre_weight:          %8s  %8s  %8s  %8s\n",
383                        (2-cam->params.exposure.centreWeight) ? "on" : "off",
384                        "off", "on", "on");
385         out += sprintf(out, "gain:                   %8d  %8d  max_gain  %8d  1,2,4,8 possible\n",
386                        1<<cam->params.exposure.gain, 1, 1);
387         if (cam->params.version.firmwareVersion == 1 &&
388            cam->params.version.firmwareRevision == 2)
389                 /* 1-02 firmware limits fineExp to 127 */
390                 tmp = 255;
391         else
392                 tmp = 511;
393
394         out += sprintf(out, "fine_exp:               %8d  %8d  %8d  %8d\n",
395                        cam->params.exposure.fineExp*2, 0, tmp, 0);
396         if (cam->params.version.firmwareVersion == 1 &&
397            cam->params.version.firmwareRevision == 2)
398                 /* 1-02 firmware limits coarseExpHi to 0 */
399                 tmp = 255;
400         else
401                 tmp = 65535;
402
403         out += sprintf(out, "coarse_exp:             %8d  %8d  %8d"
404                        "  %8d\n", cam->params.exposure.coarseExpLo+
405                        256*cam->params.exposure.coarseExpHi, 0, tmp, 185);
406         out += sprintf(out, "red_comp:               %8d  %8d  %8d  %8d\n",
407                        cam->params.exposure.redComp, 220, 255, 220);
408         out += sprintf(out, "green1_comp:            %8d  %8d  %8d  %8d\n",
409                        cam->params.exposure.green1Comp, 214, 255, 214);
410         out += sprintf(out, "green2_comp:            %8d  %8d  %8d  %8d\n",
411                        cam->params.exposure.green2Comp, 214, 255, 214);
412         out += sprintf(out, "blue_comp:              %8d  %8d  %8d  %8d\n",
413                        cam->params.exposure.blueComp, 230, 255, 230);
414         
415         out += sprintf(out, "apcor_gain1:            %#8x  %#8x  %#8x  %#8x\n",
416                        cam->params.apcor.gain1, 0, 0xff, 0x1c);
417         out += sprintf(out, "apcor_gain2:            %#8x  %#8x  %#8x  %#8x\n",
418                        cam->params.apcor.gain2, 0, 0xff, 0x1a);
419         out += sprintf(out, "apcor_gain4:            %#8x  %#8x  %#8x  %#8x\n",
420                        cam->params.apcor.gain4, 0, 0xff, 0x2d);
421         out += sprintf(out, "apcor_gain8:            %#8x  %#8x  %#8x  %#8x\n",
422                        cam->params.apcor.gain8, 0, 0xff, 0x2a);
423         out += sprintf(out, "vl_offset_gain1:        %8d  %8d  %8d  %8d\n",
424                        cam->params.vlOffset.gain1, 0, 255, 24);
425         out += sprintf(out, "vl_offset_gain2:        %8d  %8d  %8d  %8d\n",
426                        cam->params.vlOffset.gain2, 0, 255, 28);
427         out += sprintf(out, "vl_offset_gain4:        %8d  %8d  %8d  %8d\n",
428                        cam->params.vlOffset.gain4, 0, 255, 30);
429         out += sprintf(out, "vl_offset_gain8:        %8d  %8d  %8d  %8d\n",
430                        cam->params.vlOffset.gain8, 0, 255, 30);
431         out += sprintf(out, "flicker_control:        %8s  %8s  %8s  %8s\n",
432                        cam->params.flickerControl.flickerMode ? "on" : "off",
433                        "off", "on", "off");
434         out += sprintf(out, "mains_frequency:        %8d  %8d  %8d  %8d"
435                        " only 50/60\n",
436                        cam->mainsFreq ? 60 : 50, 50, 60, 50);
437         out += sprintf(out, "allowable_overexposure: %8d  %8d  %8d  %8d\n",
438                        cam->params.flickerControl.allowableOverExposure, 0,
439                        255, 0);
440         out += sprintf(out, "compression_mode:       ");
441         switch(cam->params.compression.mode) {
442         case CPIA_COMPRESSION_NONE:
443                 out += sprintf(out, "%8s", "none");
444                 break;
445         case CPIA_COMPRESSION_AUTO:
446                 out += sprintf(out, "%8s", "auto");
447                 break;
448         case CPIA_COMPRESSION_MANUAL:
449                 out += sprintf(out, "%8s", "manual");
450                 break;
451         default:
452                 out += sprintf(out, "%8s", "unknown");
453                 break;
454         }
455         out += sprintf(out, "    none,auto,manual      auto\n");
456         out += sprintf(out, "decimation_enable:      %8s  %8s  %8s  %8s\n",
457                        cam->params.compression.decimation == 
458                        DECIMATION_ENAB ? "on":"off", "off", "off",
459                        "off");
460         out += sprintf(out, "compression_target:    %9s %9s %9s %9s\n",
461                        cam->params.compressionTarget.frTargeting  == 
462                        CPIA_COMPRESSION_TARGET_FRAMERATE ?
463                        "framerate":"quality",
464                        "framerate", "quality", "quality");
465         out += sprintf(out, "target_framerate:       %8d  %8d  %8d  %8d\n",
466                        cam->params.compressionTarget.targetFR, 0, 30, 7);
467         out += sprintf(out, "target_quality:         %8d  %8d  %8d  %8d\n",
468                        cam->params.compressionTarget.targetQ, 0, 255, 10);
469         out += sprintf(out, "y_threshold:            %8d  %8d  %8d  %8d\n",
470                        cam->params.yuvThreshold.yThreshold, 0, 31, 15);
471         out += sprintf(out, "uv_threshold:           %8d  %8d  %8d  %8d\n",
472                        cam->params.yuvThreshold.uvThreshold, 0, 31, 15);
473         out += sprintf(out, "hysteresis:             %8d  %8d  %8d  %8d\n",
474                        cam->params.compressionParams.hysteresis, 0, 255, 3);
475         out += sprintf(out, "threshold_max:          %8d  %8d  %8d  %8d\n",
476                        cam->params.compressionParams.threshMax, 0, 255, 11);
477         out += sprintf(out, "small_step:             %8d  %8d  %8d  %8d\n",
478                        cam->params.compressionParams.smallStep, 0, 255, 1);
479         out += sprintf(out, "large_step:             %8d  %8d  %8d  %8d\n",
480                        cam->params.compressionParams.largeStep, 0, 255, 3);
481         out += sprintf(out, "decimation_hysteresis:  %8d  %8d  %8d  %8d\n",
482                        cam->params.compressionParams.decimationHysteresis,
483                        0, 255, 2);
484         out += sprintf(out, "fr_diff_step_thresh:    %8d  %8d  %8d  %8d\n",
485                        cam->params.compressionParams.frDiffStepThresh,
486                        0, 255, 5);
487         out += sprintf(out, "q_diff_step_thresh:     %8d  %8d  %8d  %8d\n",
488                        cam->params.compressionParams.qDiffStepThresh,
489                        0, 255, 3);
490         out += sprintf(out, "decimation_thresh_mod:  %8d  %8d  %8d  %8d\n",
491                        cam->params.compressionParams.decimationThreshMod,
492                        0, 255, 2);
493         /* QX3 specific entries */
494         if (cam->params.qx3.qx3_detected) {
495                 out += sprintf(out, "toplight:               %8s  %8s  %8s  %8s\n", 
496                                cam->params.qx3.toplight ? "on" : "off",
497                                "off", "on", "off");
498                 out += sprintf(out, "bottomlight:            %8s  %8s  %8s  %8s\n", 
499                                cam->params.qx3.bottomlight ? "on" : "off",
500                                "off", "on", "off");
501         }
502         
503         len = out - page;
504         len -= off;
505         if (len < count) {
506                 *eof = 1;
507                 if (len <= 0) return 0;
508         } else
509                 len = count;
510
511         *start = page + off;
512         return len;
513 }
514
515 static int cpia_write_proc(struct file *file, const char *buf,
516                            unsigned long count, void *data)
517 {
518         struct cam_data *cam = data;
519         struct cam_params new_params;
520         char *page, *buffer;
521         int retval, find_colon;
522         int size = count;
523         unsigned long val = 0;
524         u32 command_flags = 0;
525         u8 new_mains;
526
527         /*
528          * This code to copy from buf to page is shamelessly copied
529          * from the comx driver
530          */
531         if (count > PAGE_SIZE) {
532                 printk(KERN_ERR "count is %lu > %d!!!\n", count, (int)PAGE_SIZE);
533                 return -ENOSPC;
534         }
535
536         if (!(page = (char *)__get_free_page(GFP_KERNEL))) return -ENOMEM;
537
538         if(copy_from_user(page, buf, count))
539         {
540                 retval = -EFAULT;
541                 goto out;
542         }
543
544         if (page[count-1] == '\n')
545                 page[count-1] = '\0';
546         else if (count < PAGE_SIZE)
547                 page[count] = '\0';
548         else if (page[count]) {
549                 retval = -EINVAL;
550                 goto out;
551         }
552         
553         buffer = page;
554         
555         if (down_interruptible(&cam->param_lock))
556                 return -ERESTARTSYS;
557         
558         /*
559          * Skip over leading whitespace
560          */
561         while (count && isspace(*buffer)) {
562                 --count;
563                 ++buffer;
564         }
565         
566         memcpy(&new_params, &cam->params, sizeof(struct cam_params));
567         new_mains = cam->mainsFreq;
568         
569 #define MATCH(x) \
570         ({ \
571                 int _len = strlen(x), _ret, _colon_found; \
572                 _ret = (_len <= count && strncmp(buffer, x, _len) == 0); \
573                 if (_ret) { \
574                         buffer += _len; \
575                         count -= _len; \
576                         if (find_colon) { \
577                                 _colon_found = 0; \
578                                 while (count && (*buffer == ' ' || *buffer == '\t' || \
579                                        (!_colon_found && *buffer == ':'))) { \
580                                         if (*buffer == ':')  \
581                                                 _colon_found = 1; \
582                                         --count; \
583                                         ++buffer; \
584                                 } \
585                                 if (!count || !_colon_found) \
586                                         retval = -EINVAL; \
587                                 find_colon = 0; \
588                         } \
589                 } \
590                 _ret; \
591         })
592 #define FIRMWARE_VERSION(x,y) (new_params.version.firmwareVersion == (x) && \
593                                new_params.version.firmwareRevision == (y))
594 #define VALUE \
595         ({ \
596                 char *_p; \
597                 unsigned long int _ret; \
598                 _ret = simple_strtoul(buffer, &_p, 0); \
599                 if (_p == buffer) \
600                         retval = -EINVAL; \
601                 else { \
602                         count -= _p - buffer; \
603                         buffer = _p; \
604                 } \
605                 _ret; \
606         })
607
608         retval = 0;
609         while (count && !retval) {
610                 find_colon = 1;
611                 if (MATCH("brightness")) {
612                         if (!retval)
613                                 val = VALUE;
614
615                         if (!retval) {
616                                 if (val <= 100)
617                                         new_params.colourParams.brightness = val;
618                                 else
619                                         retval = -EINVAL;
620                         }
621                         command_flags |= COMMAND_SETCOLOURPARAMS;
622                 } else if (MATCH("contrast")) {
623                         if (!retval)
624                                 val = VALUE;
625
626                         if (!retval) {
627                                 if (val <= 100) {
628                                         /* contrast is in steps of 8, so round*/
629                                         val = ((val + 3) / 8) * 8;
630                                         /* 1-02 firmware limits contrast to 80*/
631                                         if (FIRMWARE_VERSION(1,2) && val > 80)
632                                                 val = 80;
633
634                                         new_params.colourParams.contrast = val;
635                                 } else
636                                         retval = -EINVAL;
637                         }
638                         command_flags |= COMMAND_SETCOLOURPARAMS;
639                 } else if (MATCH("saturation")) {
640                         if (!retval)
641                                 val = VALUE;
642
643                         if (!retval) {
644                                 if (val <= 100)
645                                         new_params.colourParams.saturation = val;
646                                 else
647                                         retval = -EINVAL;
648                         }
649                         command_flags |= COMMAND_SETCOLOURPARAMS;
650                 } else if (MATCH("sensor_fps")) {
651                         if (!retval)
652                                 val = VALUE;
653
654                         if (!retval) {
655                                 /* find values so that sensorFPS is minimized,
656                                  * but >= val */
657                                 if (val > 30)
658                                         retval = -EINVAL;
659                                 else if (val > 25) {
660                                         new_params.sensorFps.divisor = 0;
661                                         new_params.sensorFps.baserate = 1;
662                                 } else if (val > 15) {
663                                         new_params.sensorFps.divisor = 0;
664                                         new_params.sensorFps.baserate = 0;
665                                 } else if (val > 12) {
666                                         new_params.sensorFps.divisor = 1;
667                                         new_params.sensorFps.baserate = 1;
668                                 } else if (val > 7) {
669                                         new_params.sensorFps.divisor = 1;
670                                         new_params.sensorFps.baserate = 0;
671                                 } else if (val > 6) {
672                                         new_params.sensorFps.divisor = 2;
673                                         new_params.sensorFps.baserate = 1;
674                                 } else if (val > 3) {
675                                         new_params.sensorFps.divisor = 2;
676                                         new_params.sensorFps.baserate = 0;
677                                 } else {
678                                         new_params.sensorFps.divisor = 3;
679                                         /* Either base rate would work here */
680                                         new_params.sensorFps.baserate = 1;
681                                 }
682                                 new_params.flickerControl.coarseJump = 
683                                         flicker_jumps[new_mains]
684                                         [new_params.sensorFps.baserate]
685                                         [new_params.sensorFps.divisor];
686                                 if (new_params.flickerControl.flickerMode)
687                                         command_flags |= COMMAND_SETFLICKERCTRL;
688                         }
689                         command_flags |= COMMAND_SETSENSORFPS;
690                 } else if (MATCH("stream_start_line")) {
691                         if (!retval)
692                                 val = VALUE;
693
694                         if (!retval) {
695                                 int max_line = 288;
696
697                                 if (new_params.format.videoSize == VIDEOSIZE_QCIF)
698                                         max_line = 144;
699                                 if (val <= max_line)
700                                         new_params.streamStartLine = val/2;
701                                 else
702                                         retval = -EINVAL;
703                         }
704                 } else if (MATCH("ecp_timing")) {
705                         if (!retval && MATCH("normal"))
706                                 new_params.ecpTiming = 0;
707                         else if (!retval && MATCH("slow"))
708                                 new_params.ecpTiming = 1;
709                         else
710                                 retval = -EINVAL;
711
712                         command_flags |= COMMAND_SETECPTIMING;
713                 } else if (MATCH("color_balance_mode")) {
714                         if (!retval && MATCH("manual"))
715                                 new_params.colourBalance.balanceModeIsAuto = 0;
716                         else if (!retval && MATCH("auto"))
717                                 new_params.colourBalance.balanceModeIsAuto = 1;
718                         else
719                                 retval = -EINVAL;
720
721                         command_flags |= COMMAND_SETCOLOURBALANCE;
722                 } else if (MATCH("red_gain")) {
723                         if (!retval)
724                                 val = VALUE;
725
726                         if (!retval) {
727                                 if (val <= 212)
728                                         new_params.colourBalance.redGain = val;
729                                 else
730                                         retval = -EINVAL;
731                         }
732                         command_flags |= COMMAND_SETCOLOURBALANCE;
733                 } else if (MATCH("green_gain")) {
734                         if (!retval)
735                                 val = VALUE;
736
737                         if (!retval) {
738                                 if (val <= 212)
739                                         new_params.colourBalance.greenGain = val;
740                                 else
741                                         retval = -EINVAL;
742                         }
743                         command_flags |= COMMAND_SETCOLOURBALANCE;
744                 } else if (MATCH("blue_gain")) {
745                         if (!retval)
746                                 val = VALUE;
747
748                         if (!retval) {
749                                 if (val <= 212)
750                                         new_params.colourBalance.blueGain = val;
751                                 else
752                                         retval = -EINVAL;
753                         }
754                         command_flags |= COMMAND_SETCOLOURBALANCE;
755                 } else if (MATCH("max_gain")) {
756                         if (!retval)
757                                 val = VALUE;
758
759                         if (!retval) {
760                                 /* 1-02 firmware limits gain to 2 */
761                                 if (FIRMWARE_VERSION(1,2) && val > 2)
762                                         val = 2;
763                                 switch(val) {
764                                 case 1:
765                                         new_params.exposure.gainMode = 1;
766                                         break;
767                                 case 2:
768                                         new_params.exposure.gainMode = 2;
769                                         break;
770                                 case 4:
771                                         new_params.exposure.gainMode = 3;
772                                         break;
773                                 case 8:
774                                         new_params.exposure.gainMode = 4;
775                                         break;
776                                 default:
777                                         retval = -EINVAL;
778                                         break;
779                                 }
780                         }
781                         command_flags |= COMMAND_SETEXPOSURE;
782                 } else if (MATCH("exposure_mode")) {
783                         if (!retval && MATCH("auto"))
784                                 new_params.exposure.expMode = 2;
785                         else if (!retval && MATCH("manual")) {
786                                 if (new_params.exposure.expMode == 2)
787                                         new_params.exposure.expMode = 3;
788                                 new_params.flickerControl.flickerMode = 0;
789                                 command_flags |= COMMAND_SETFLICKERCTRL;
790                         } else
791                                 retval = -EINVAL;
792
793                         command_flags |= COMMAND_SETEXPOSURE;
794                 } else if (MATCH("centre_weight")) {
795                         if (!retval && MATCH("on"))
796                                 new_params.exposure.centreWeight = 1;
797                         else if (!retval && MATCH("off"))
798                                 new_params.exposure.centreWeight = 2;
799                         else
800                                 retval = -EINVAL;
801
802                         command_flags |= COMMAND_SETEXPOSURE;
803                 } else if (MATCH("gain")) {
804                         if (!retval)
805                                 val = VALUE;
806
807                         if (!retval) {
808                                 switch(val) {
809                                 case 1:
810                                         new_params.exposure.gain = 0;
811                                         new_params.exposure.expMode = 1;
812                                         new_params.flickerControl.flickerMode = 0;
813                                         command_flags |= COMMAND_SETFLICKERCTRL;
814                                         break;
815                                 case 2:
816                                         new_params.exposure.gain = 1;
817                                         new_params.exposure.expMode = 1;
818                                         new_params.flickerControl.flickerMode = 0;
819                                         command_flags |= COMMAND_SETFLICKERCTRL;
820                                         break;
821                                 case 4:
822                                         new_params.exposure.gain = 2;
823                                         new_params.exposure.expMode = 1;
824                                         new_params.flickerControl.flickerMode = 0;
825                                         command_flags |= COMMAND_SETFLICKERCTRL;
826                                         break;
827                                 case 8:
828                                         new_params.exposure.gain = 3;
829                                         new_params.exposure.expMode = 1;
830                                         new_params.flickerControl.flickerMode = 0;
831                                         command_flags |= COMMAND_SETFLICKERCTRL;
832                                         break;
833                                 default:
834                                         retval = -EINVAL;
835                                         break;
836                                 }
837                                 command_flags |= COMMAND_SETEXPOSURE;
838                                 if (new_params.exposure.gain >
839                                     new_params.exposure.gainMode-1)
840                                         retval = -EINVAL;
841                         }
842                 } else if (MATCH("fine_exp")) {
843                         if (!retval)
844                                 val = VALUE;
845
846                         if (!retval) {
847                                 if (val < 256) {
848                                         /* 1-02 firmware limits fineExp to 127*/
849                                         if (FIRMWARE_VERSION(1,2) && val > 127)
850                                                 val = 127;
851                                         new_params.exposure.fineExp = val;
852                                         new_params.exposure.expMode = 1;
853                                         command_flags |= COMMAND_SETEXPOSURE;
854                                         new_params.flickerControl.flickerMode = 0;
855                                         command_flags |= COMMAND_SETFLICKERCTRL;
856                                 } else
857                                         retval = -EINVAL;
858                         }
859                 } else if (MATCH("coarse_exp")) {
860                         if (!retval)
861                                 val = VALUE;
862
863                         if (!retval) {
864                                 if (val < 65536) {
865                                         /* 1-02 firmware limits
866                                          * coarseExp to 255 */
867                                         if (FIRMWARE_VERSION(1,2) && val > 255)
868                                                 val = 255;
869                                         new_params.exposure.coarseExpLo =
870                                                 val & 0xff;
871                                         new_params.exposure.coarseExpHi =
872                                                 val >> 8;
873                                         new_params.exposure.expMode = 1;
874                                         command_flags |= COMMAND_SETEXPOSURE;
875                                         new_params.flickerControl.flickerMode = 0;
876                                         command_flags |= COMMAND_SETFLICKERCTRL;
877                                 } else
878                                         retval = -EINVAL;
879                         }
880                 } else if (MATCH("red_comp")) {
881                         if (!retval)
882                                 val = VALUE;
883
884                         if (!retval) {
885                                 if (val >= 220 && val <= 255) {
886                                         new_params.exposure.redComp = val;
887                                         command_flags |= COMMAND_SETEXPOSURE;
888                                 } else
889                                         retval = -EINVAL;
890                         }
891                 } else if (MATCH("green1_comp")) {
892                         if (!retval)
893                                 val = VALUE;
894
895                         if (!retval) {
896                                 if (val >= 214 && val <= 255) {
897                                         new_params.exposure.green1Comp = val;
898                                         command_flags |= COMMAND_SETEXPOSURE;
899                                 } else
900                                         retval = -EINVAL;
901                         }
902                 } else if (MATCH("green2_comp")) {
903                         if (!retval)
904                                 val = VALUE;
905
906                         if (!retval) {
907                                 if (val >= 214 && val <= 255) {
908                                         new_params.exposure.green2Comp = val;
909                                         command_flags |= COMMAND_SETEXPOSURE;
910                                 } else
911                                         retval = -EINVAL;
912                         }
913                 } else if (MATCH("blue_comp")) {
914                         if (!retval)
915                                 val = VALUE;
916
917                         if (!retval) {
918                                 if (val >= 230 && val <= 255) {
919                                         new_params.exposure.blueComp = val;
920                                         command_flags |= COMMAND_SETEXPOSURE;
921                                 } else
922                                         retval = -EINVAL;
923                         }
924                 } else if (MATCH("apcor_gain1")) {
925                         if (!retval)
926                                 val = VALUE;
927
928                         if (!retval) {
929                                 command_flags |= COMMAND_SETAPCOR;
930                                 if (val <= 0xff)
931                                         new_params.apcor.gain1 = val;
932                                 else
933                                         retval = -EINVAL;
934                         }
935                 } else if (MATCH("apcor_gain2")) {
936                         if (!retval)
937                                 val = VALUE;
938
939                         if (!retval) {
940                                 command_flags |= COMMAND_SETAPCOR;
941                                 if (val <= 0xff)
942                                         new_params.apcor.gain2 = val;
943                                 else
944                                         retval = -EINVAL;
945                         }
946                 } else if (MATCH("apcor_gain4")) {
947                         if (!retval)
948                                 val = VALUE;
949
950                         if (!retval) {
951                                 command_flags |= COMMAND_SETAPCOR;
952                                 if (val <= 0xff)
953                                         new_params.apcor.gain4 = val;
954                                 else
955                                         retval = -EINVAL;
956                         }
957                 } else if (MATCH("apcor_gain8")) {
958                         if (!retval)
959                                 val = VALUE;
960
961                         if (!retval) {
962                                 command_flags |= COMMAND_SETAPCOR;
963                                 if (val <= 0xff)
964                                         new_params.apcor.gain8 = val;
965                                 else
966                                         retval = -EINVAL;
967                         }
968                 } else if (MATCH("vl_offset_gain1")) {
969                         if (!retval)
970                                 val = VALUE;
971
972                         if (!retval) {
973                                 if (val <= 0xff)
974                                         new_params.vlOffset.gain1 = val;
975                                 else
976                                         retval = -EINVAL;
977                         }
978                         command_flags |= COMMAND_SETVLOFFSET;
979                 } else if (MATCH("vl_offset_gain2")) {
980                         if (!retval)
981                                 val = VALUE;
982
983                         if (!retval) {
984                                 if (val <= 0xff)
985                                         new_params.vlOffset.gain2 = val;
986                                 else
987                                         retval = -EINVAL;
988                         }
989                         command_flags |= COMMAND_SETVLOFFSET;
990                 } else if (MATCH("vl_offset_gain4")) {
991                         if (!retval)
992                                 val = VALUE;
993
994                         if (!retval) {
995                                 if (val <= 0xff)
996                                         new_params.vlOffset.gain4 = val;
997                                 else
998                                         retval = -EINVAL;
999                         }
1000                         command_flags |= COMMAND_SETVLOFFSET;
1001                 } else if (MATCH("vl_offset_gain8")) {
1002                         if (!retval)
1003                                 val = VALUE;
1004
1005                         if (!retval) {
1006                                 if (val <= 0xff)
1007                                         new_params.vlOffset.gain8 = val;
1008                                 else
1009                                         retval = -EINVAL;
1010                         }
1011                         command_flags |= COMMAND_SETVLOFFSET;
1012                 } else if (MATCH("flicker_control")) {
1013                         if (!retval && MATCH("on")) {
1014                                 new_params.flickerControl.flickerMode = 1;
1015                                 new_params.exposure.expMode = 2;
1016                                 command_flags |= COMMAND_SETEXPOSURE;
1017                         } else if (!retval && MATCH("off"))
1018                                 new_params.flickerControl.flickerMode = 0;
1019                         else
1020                                 retval = -EINVAL;
1021
1022                         command_flags |= COMMAND_SETFLICKERCTRL;
1023                 } else if (MATCH("mains_frequency")) {
1024                         if (!retval && MATCH("50")) {
1025                                 new_mains = 0;
1026                                 new_params.flickerControl.coarseJump = 
1027                                         flicker_jumps[new_mains]
1028                                         [new_params.sensorFps.baserate]
1029                                         [new_params.sensorFps.divisor];
1030                                 if (new_params.flickerControl.flickerMode)
1031                                         command_flags |= COMMAND_SETFLICKERCTRL;
1032                         } else if (!retval && MATCH("60")) {
1033                                 new_mains = 1;
1034                                 new_params.flickerControl.coarseJump = 
1035                                         flicker_jumps[new_mains]
1036                                         [new_params.sensorFps.baserate]
1037                                         [new_params.sensorFps.divisor];
1038                                 if (new_params.flickerControl.flickerMode)
1039                                         command_flags |= COMMAND_SETFLICKERCTRL;
1040                         } else
1041                                 retval = -EINVAL;
1042                 } else if (MATCH("allowable_overexposure")) {
1043                         if (!retval)
1044                                 val = VALUE;
1045
1046                         if (!retval) {
1047                                 if (val <= 0xff) {
1048                                         new_params.flickerControl.
1049                                                 allowableOverExposure = val;
1050                                         command_flags |= COMMAND_SETFLICKERCTRL;
1051                                 } else
1052                                         retval = -EINVAL;
1053                         }
1054                 } else if (MATCH("compression_mode")) {
1055                         if (!retval && MATCH("none"))
1056                                 new_params.compression.mode =
1057                                         CPIA_COMPRESSION_NONE;
1058                         else if (!retval && MATCH("auto"))
1059                                 new_params.compression.mode =
1060                                         CPIA_COMPRESSION_AUTO;
1061                         else if (!retval && MATCH("manual"))
1062                                 new_params.compression.mode =
1063                                         CPIA_COMPRESSION_MANUAL;
1064                         else
1065                                 retval = -EINVAL;
1066
1067                         command_flags |= COMMAND_SETCOMPRESSION;
1068                 } else if (MATCH("decimation_enable")) {
1069                         if (!retval && MATCH("off"))
1070                                 new_params.compression.decimation = 0;
1071                         else
1072                                 retval = -EINVAL;
1073
1074                         command_flags |= COMMAND_SETCOMPRESSION;
1075                 } else if (MATCH("compression_target")) {
1076                         if (!retval && MATCH("quality"))
1077                                 new_params.compressionTarget.frTargeting = 
1078                                         CPIA_COMPRESSION_TARGET_QUALITY;
1079                         else if (!retval && MATCH("framerate"))
1080                                 new_params.compressionTarget.frTargeting = 
1081                                         CPIA_COMPRESSION_TARGET_FRAMERATE;
1082                         else
1083                                 retval = -EINVAL;
1084
1085                         command_flags |= COMMAND_SETCOMPRESSIONTARGET;
1086                 } else if (MATCH("target_framerate")) {
1087                         if (!retval)
1088                                 val = VALUE;
1089
1090                         if (!retval)
1091                                 new_params.compressionTarget.targetFR = val;
1092                         command_flags |= COMMAND_SETCOMPRESSIONTARGET;
1093                 } else if (MATCH("target_quality")) {
1094                         if (!retval)
1095                                 val = VALUE;
1096
1097                         if (!retval)
1098                                 new_params.compressionTarget.targetQ = val;
1099
1100                         command_flags |= COMMAND_SETCOMPRESSIONTARGET;
1101                 } else if (MATCH("y_threshold")) {
1102                         if (!retval)
1103                                 val = VALUE;
1104
1105                         if (!retval) {
1106                                 if (val < 32)
1107                                         new_params.yuvThreshold.yThreshold = val;
1108                                 else
1109                                         retval = -EINVAL;
1110                         }
1111                         command_flags |= COMMAND_SETYUVTHRESH;
1112                 } else if (MATCH("uv_threshold")) {
1113                         if (!retval)
1114                                 val = VALUE;
1115
1116                         if (!retval) {
1117                                 if (val < 32)
1118                                         new_params.yuvThreshold.uvThreshold = val;
1119                                 else
1120                                         retval = -EINVAL;
1121                         }
1122                         command_flags |= COMMAND_SETYUVTHRESH;
1123                 } else if (MATCH("hysteresis")) {
1124                         if (!retval)
1125                                 val = VALUE;
1126
1127                         if (!retval) {
1128                                 if (val <= 0xff)
1129                                         new_params.compressionParams.hysteresis = val;
1130                                 else
1131                                         retval = -EINVAL;
1132                         }
1133                         command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1134                 } else if (MATCH("threshold_max")) {
1135                         if (!retval)
1136                                 val = VALUE;
1137
1138                         if (!retval) {
1139                                 if (val <= 0xff)
1140                                         new_params.compressionParams.threshMax = val;
1141                                 else
1142                                         retval = -EINVAL;
1143                         }
1144                         command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1145                 } else if (MATCH("small_step")) {
1146                         if (!retval)
1147                                 val = VALUE;
1148
1149                         if (!retval) {
1150                                 if (val <= 0xff)
1151                                         new_params.compressionParams.smallStep = val;
1152                                 else
1153                                         retval = -EINVAL;
1154                         }
1155                         command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1156                 } else if (MATCH("large_step")) {
1157                         if (!retval)
1158                                 val = VALUE;
1159
1160                         if (!retval) {
1161                                 if (val <= 0xff)
1162                                         new_params.compressionParams.largeStep = val;
1163                                 else
1164                                         retval = -EINVAL;
1165                         }
1166                         command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1167                 } else if (MATCH("decimation_hysteresis")) {
1168                         if (!retval)
1169                                 val = VALUE;
1170
1171                         if (!retval) {
1172                                 if (val <= 0xff)
1173                                         new_params.compressionParams.decimationHysteresis = val;
1174                                 else
1175                                         retval = -EINVAL;
1176                         }
1177                         command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1178                 } else if (MATCH("fr_diff_step_thresh")) {
1179                         if (!retval)
1180                                 val = VALUE;
1181
1182                         if (!retval) {
1183                                 if (val <= 0xff)
1184                                         new_params.compressionParams.frDiffStepThresh = val;
1185                                 else
1186                                         retval = -EINVAL;
1187                         }
1188                         command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1189                 } else if (MATCH("q_diff_step_thresh")) {
1190                         if (!retval)
1191                                 val = VALUE;
1192
1193                         if (!retval) {
1194                                 if (val <= 0xff)
1195                                         new_params.compressionParams.qDiffStepThresh = val;
1196                                 else
1197                                         retval = -EINVAL;
1198                         }
1199                         command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1200                 } else if (MATCH("decimation_thresh_mod")) {
1201                         if (!retval)
1202                                 val = VALUE;
1203
1204                         if (!retval) {
1205                                 if (val <= 0xff)
1206                                         new_params.compressionParams.decimationThreshMod = val;
1207                                 else
1208                                         retval = -EINVAL;
1209                         }
1210                         command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1211                 } else if (MATCH("toplight")) {
1212                         if (!retval && MATCH("on"))
1213                                 new_params.qx3.toplight = 1;
1214                         else if (!retval && MATCH("off"))
1215                                 new_params.qx3.toplight = 0;
1216                         else 
1217                                 retval = -EINVAL;
1218                         command_flags |= COMMAND_SETLIGHTS;
1219                 } else if (MATCH("bottomlight")) {
1220                         if (!retval && MATCH("on"))
1221                                 new_params.qx3.bottomlight = 1;
1222                         else if (!retval && MATCH("off"))  
1223                                 new_params.qx3.bottomlight = 0;
1224                         else 
1225                                 retval = -EINVAL;
1226                         command_flags |= COMMAND_SETLIGHTS;
1227                 } else {
1228                         DBG("No match found\n");
1229                         retval = -EINVAL;
1230                 }
1231
1232                 if (!retval) {
1233                         while (count && isspace(*buffer) && *buffer != '\n') {
1234                                 --count;
1235                                 ++buffer;
1236                         }
1237                         if (count) {
1238                                 if (*buffer == '\0' && count != 1)
1239                                         retval = -EINVAL;
1240                                 else if (*buffer != '\n' && *buffer != ';' &&
1241                                          *buffer != '\0')
1242                                         retval = -EINVAL;
1243                                 else {
1244                                         --count;
1245                                         ++buffer;
1246                                 }
1247                         }
1248                 }
1249         }
1250 #undef MATCH    
1251 #undef FIRMWARE_VERSION
1252 #undef VALUE
1253 #undef FIND_VALUE
1254 #undef FIND_END
1255         if (!retval) {
1256                 if (command_flags & COMMAND_SETCOLOURPARAMS) {
1257                         /* Adjust cam->vp to reflect these changes */
1258                         cam->vp.brightness =
1259                                 new_params.colourParams.brightness*65535/100;
1260                         cam->vp.contrast =
1261                                 new_params.colourParams.contrast*65535/100;
1262                         cam->vp.colour =
1263                                 new_params.colourParams.saturation*65535/100;
1264                 }
1265                 
1266                 memcpy(&cam->params, &new_params, sizeof(struct cam_params));
1267                 cam->mainsFreq = new_mains;
1268                 cam->cmd_queue |= command_flags;
1269                 retval = size;
1270         } else
1271                 DBG("error: %d\n", retval);
1272         
1273         up(&cam->param_lock);
1274         
1275 out:
1276         free_page((unsigned long)page);
1277         return retval;
1278 }
1279
1280 static void create_proc_cpia_cam(struct cam_data *cam)
1281 {
1282         char name[7];
1283         struct proc_dir_entry *ent;
1284         
1285         if (!cpia_proc_root || !cam)
1286                 return;
1287
1288         sprintf(name, "video%d", cam->vdev.minor);
1289         
1290         ent = create_proc_entry(name, S_IFREG|S_IRUGO|S_IWUSR, cpia_proc_root);
1291         if (!ent)
1292                 return;
1293
1294         ent->data = cam;
1295         ent->read_proc = cpia_read_proc;
1296         ent->write_proc = cpia_write_proc;
1297         /* 
1298            size of the proc entry is 3672 bytes for the standard webcam;
1299            the extra features of the QX3 microscope add 188 bytes.
1300            (we have not yet probed the camera to see which type it is).
1301         */
1302         ent->size = 3672 + 188;
1303         cam->proc_entry = ent;
1304 }
1305
1306 static void destroy_proc_cpia_cam(struct cam_data *cam)
1307 {
1308         char name[7];
1309         
1310         if (!cam || !cam->proc_entry)
1311                 return;
1312         
1313         sprintf(name, "video%d", cam->vdev.minor);
1314         remove_proc_entry(name, cpia_proc_root);
1315         cam->proc_entry = NULL;
1316 }
1317
1318 static void proc_cpia_create(void)
1319 {
1320         cpia_proc_root = create_proc_entry("cpia", S_IFDIR, 0);
1321
1322         if (cpia_proc_root)
1323                 cpia_proc_root->owner = THIS_MODULE;
1324         else
1325                 LOG("Unable to initialise /proc/cpia\n");
1326 }
1327
1328 static void proc_cpia_destroy(void)
1329 {
1330         remove_proc_entry("cpia", 0);
1331 }
1332 #endif /* CONFIG_PROC_FS */
1333
1334 /* ----------------------- debug functions ---------------------- */
1335
1336 #define printstatus(cam) \
1337   DBG("%02x %02x %02x %02x %02x %02x %02x %02x\n",\
1338         cam->params.status.systemState, cam->params.status.grabState, \
1339         cam->params.status.streamState, cam->params.status.fatalError, \
1340         cam->params.status.cmdError, cam->params.status.debugFlags, \
1341         cam->params.status.vpStatus, cam->params.status.errorCode);
1342
1343 /* ----------------------- v4l helpers -------------------------- */
1344
1345 /* supported frame palettes and depths */
1346 static inline int valid_mode(u16 palette, u16 depth)
1347 {
1348         return (palette == VIDEO_PALETTE_GREY && depth == 8) ||
1349                (palette == VIDEO_PALETTE_RGB555 && depth == 16) ||
1350                (palette == VIDEO_PALETTE_RGB565 && depth == 16) ||
1351                (palette == VIDEO_PALETTE_RGB24 && depth == 24) ||
1352                (palette == VIDEO_PALETTE_RGB32 && depth == 32) ||
1353                (palette == VIDEO_PALETTE_YUV422 && depth == 16) ||
1354                (palette == VIDEO_PALETTE_YUYV && depth == 16) ||
1355                (palette == VIDEO_PALETTE_UYVY && depth == 16);
1356 }
1357
1358 static int match_videosize( int width, int height )
1359 {
1360         /* return the best match, where 'best' is as always
1361          * the largest that is not bigger than what is requested. */
1362         if (width>=352 && height>=288)
1363                 return VIDEOSIZE_352_288; /* CIF */
1364
1365         if (width>=320 && height>=240)
1366                 return VIDEOSIZE_320_240; /* SIF */
1367
1368         if (width>=288 && height>=216)
1369                 return VIDEOSIZE_288_216;
1370
1371         if (width>=256 && height>=192)
1372                 return VIDEOSIZE_256_192;
1373
1374         if (width>=224 && height>=168)
1375                 return VIDEOSIZE_224_168;
1376
1377         if (width>=192 && height>=144)
1378                 return VIDEOSIZE_192_144;
1379
1380         if (width>=176 && height>=144)
1381                 return VIDEOSIZE_176_144; /* QCIF */
1382
1383         if (width>=160 && height>=120)
1384                 return VIDEOSIZE_160_120; /* QSIF */
1385
1386         if (width>=128 && height>=96)
1387                 return VIDEOSIZE_128_96;
1388
1389         if (width>=88 && height>=72)
1390                 return VIDEOSIZE_88_72;
1391
1392         if (width>=64 && height>=48)
1393                 return VIDEOSIZE_64_48;
1394
1395         if (width>=48 && height>=48)
1396                 return VIDEOSIZE_48_48;
1397
1398         return -1;
1399 }
1400
1401 /* these are the capture sizes we support */
1402 static void set_vw_size(struct cam_data *cam)
1403 {
1404         /* the col/row/start/end values are the result of simple math    */
1405         /* study the SetROI-command in cpia developers guide p 2-22      */
1406         /* streamStartLine is set to the recommended value in the cpia   */
1407         /*  developers guide p 3-37                                      */
1408         switch(cam->video_size) {
1409         case VIDEOSIZE_CIF:
1410                 cam->vw.width = 352;
1411                 cam->vw.height = 288;
1412                 cam->params.format.videoSize=VIDEOSIZE_CIF;
1413                 cam->params.roi.colStart=0;
1414                 cam->params.roi.colEnd=44;
1415                 cam->params.roi.rowStart=0;
1416                 cam->params.roi.rowEnd=72;
1417                 cam->params.streamStartLine = 120;
1418                 break;
1419         case VIDEOSIZE_SIF:
1420                 cam->vw.width = 320;
1421                 cam->vw.height = 240;
1422                 cam->params.format.videoSize=VIDEOSIZE_CIF;
1423                 cam->params.roi.colStart=2;
1424                 cam->params.roi.colEnd=42;
1425                 cam->params.roi.rowStart=6;
1426                 cam->params.roi.rowEnd=66;
1427                 cam->params.streamStartLine = 120;
1428                 break;
1429         case VIDEOSIZE_288_216:
1430                 cam->vw.width = 288;
1431                 cam->vw.height = 216;
1432                 cam->params.format.videoSize=VIDEOSIZE_CIF;
1433                 cam->params.roi.colStart=4;
1434                 cam->params.roi.colEnd=40;
1435                 cam->params.roi.rowStart=9;
1436                 cam->params.roi.rowEnd=63;
1437                 cam->params.streamStartLine = 120;
1438                 break;
1439         case VIDEOSIZE_256_192:
1440                 cam->vw.width = 256;
1441                 cam->vw.height = 192;
1442                 cam->params.format.videoSize=VIDEOSIZE_CIF;
1443                 cam->params.roi.colStart=6;
1444                 cam->params.roi.colEnd=38;
1445                 cam->params.roi.rowStart=12;
1446                 cam->params.roi.rowEnd=60;
1447                 cam->params.streamStartLine = 120;
1448                 break;
1449         case VIDEOSIZE_224_168:
1450                 cam->vw.width = 224;
1451                 cam->vw.height = 168;
1452                 cam->params.format.videoSize=VIDEOSIZE_CIF;
1453                 cam->params.roi.colStart=8;
1454                 cam->params.roi.colEnd=36;
1455                 cam->params.roi.rowStart=15;
1456                 cam->params.roi.rowEnd=57;
1457                 cam->params.streamStartLine = 120;
1458                 break;
1459         case VIDEOSIZE_192_144:
1460                 cam->vw.width = 192;
1461                 cam->vw.height = 144;
1462                 cam->params.format.videoSize=VIDEOSIZE_CIF;
1463                 cam->params.roi.colStart=10;
1464                 cam->params.roi.colEnd=34;
1465                 cam->params.roi.rowStart=18;
1466                 cam->params.roi.rowEnd=54;
1467                 cam->params.streamStartLine = 120;
1468                 break;
1469         case VIDEOSIZE_QCIF:
1470                 cam->vw.width = 176;
1471                 cam->vw.height = 144;
1472                 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1473                 cam->params.roi.colStart=0;
1474                 cam->params.roi.colEnd=22;
1475                 cam->params.roi.rowStart=0;
1476                 cam->params.roi.rowEnd=36;
1477                 cam->params.streamStartLine = 60;
1478                 break;
1479         case VIDEOSIZE_QSIF:
1480                 cam->vw.width = 160;
1481                 cam->vw.height = 120;
1482                 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1483                 cam->params.roi.colStart=1;
1484                 cam->params.roi.colEnd=21;
1485                 cam->params.roi.rowStart=3;
1486                 cam->params.roi.rowEnd=33;
1487                 cam->params.streamStartLine = 60;
1488                 break;
1489         case VIDEOSIZE_128_96:
1490                 cam->vw.width = 128;
1491                 cam->vw.height = 96;
1492                 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1493                 cam->params.roi.colStart=3;
1494                 cam->params.roi.colEnd=19;
1495                 cam->params.roi.rowStart=6;
1496                 cam->params.roi.rowEnd=30;
1497                 cam->params.streamStartLine = 60;
1498                 break;
1499         case VIDEOSIZE_88_72:
1500                 cam->vw.width = 88;
1501                 cam->vw.height = 72;
1502                 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1503                 cam->params.roi.colStart=5;
1504                 cam->params.roi.colEnd=16;
1505                 cam->params.roi.rowStart=9;
1506                 cam->params.roi.rowEnd=27;
1507                 cam->params.streamStartLine = 60;
1508                 break;
1509         case VIDEOSIZE_64_48:
1510                 cam->vw.width = 64;
1511                 cam->vw.height = 48;
1512                 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1513                 cam->params.roi.colStart=7;
1514                 cam->params.roi.colEnd=15;
1515                 cam->params.roi.rowStart=12;
1516                 cam->params.roi.rowEnd=24;
1517                 cam->params.streamStartLine = 60;
1518                 break;
1519         case VIDEOSIZE_48_48:
1520                 cam->vw.width = 48;
1521                 cam->vw.height = 48;
1522                 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1523                 cam->params.roi.colStart=8;
1524                 cam->params.roi.colEnd=14;
1525                 cam->params.roi.rowStart=6;
1526                 cam->params.roi.rowEnd=30;
1527                 cam->params.streamStartLine = 60;
1528                 break;
1529         default:
1530                 LOG("bad videosize value: %d\n", cam->video_size);
1531         }
1532
1533         return;
1534 }
1535
1536 static int allocate_frame_buf(struct cam_data *cam)
1537 {
1538         int i;
1539
1540         cam->frame_buf = rvmalloc(FRAME_NUM * CPIA_MAX_FRAME_SIZE);
1541         if (!cam->frame_buf)
1542                 return -ENOBUFS;
1543
1544         for (i = 0; i < FRAME_NUM; i++)
1545                 cam->frame[i].data = cam->frame_buf + i * CPIA_MAX_FRAME_SIZE;
1546
1547         return 0;
1548 }
1549
1550 static int free_frame_buf(struct cam_data *cam)
1551 {
1552         int i;
1553         
1554         rvfree(cam->frame_buf, FRAME_NUM*CPIA_MAX_FRAME_SIZE);
1555         cam->frame_buf = 0;
1556         for (i=0; i < FRAME_NUM; i++)
1557                 cam->frame[i].data = NULL;
1558
1559         return 0;
1560 }
1561
1562
1563 static void inline free_frames(struct cpia_frame frame[FRAME_NUM])
1564 {
1565         int i;
1566
1567         for (i=0; i < FRAME_NUM; i++)
1568                 frame[i].state = FRAME_UNUSED;
1569         return;
1570 }
1571
1572 /**********************************************************************
1573  *
1574  * General functions
1575  *
1576  **********************************************************************/
1577 /* send an arbitrary command to the camera */
1578 static int do_command(struct cam_data *cam, u16 command, u8 a, u8 b, u8 c, u8 d)
1579 {
1580         int retval, datasize;
1581         u8 cmd[8], data[8];
1582
1583         switch(command) {
1584         case CPIA_COMMAND_GetCPIAVersion:
1585         case CPIA_COMMAND_GetPnPID:
1586         case CPIA_COMMAND_GetCameraStatus:
1587         case CPIA_COMMAND_GetVPVersion:
1588                 datasize=8;
1589                 break;
1590         case CPIA_COMMAND_GetColourParams:
1591         case CPIA_COMMAND_GetColourBalance:
1592         case CPIA_COMMAND_GetExposure:
1593                 down(&cam->param_lock);
1594                 datasize=8;
1595                 break;
1596         case CPIA_COMMAND_ReadMCPorts: 
1597         case CPIA_COMMAND_ReadVCRegs:
1598                 datasize = 4;
1599                 break;
1600         default:
1601                 datasize=0;
1602                 break;
1603         }
1604
1605         cmd[0] = command>>8;
1606         cmd[1] = command&0xff;
1607         cmd[2] = a;
1608         cmd[3] = b;
1609         cmd[4] = c;
1610         cmd[5] = d;
1611         cmd[6] = datasize;
1612         cmd[7] = 0;
1613
1614         retval = cam->ops->transferCmd(cam->lowlevel_data, cmd, data);
1615         if (retval) {
1616                 DBG("%x - failed, retval=%d\n", command, retval);
1617                 if (command == CPIA_COMMAND_GetColourParams ||
1618                     command == CPIA_COMMAND_GetColourBalance ||
1619                     command == CPIA_COMMAND_GetExposure)
1620                         up(&cam->param_lock);
1621         } else {
1622                 switch(command) {
1623                 case CPIA_COMMAND_GetCPIAVersion:
1624                         cam->params.version.firmwareVersion = data[0];
1625                         cam->params.version.firmwareRevision = data[1];
1626                         cam->params.version.vcVersion = data[2];
1627                         cam->params.version.vcRevision = data[3];
1628                         break;
1629                 case CPIA_COMMAND_GetPnPID:
1630                         cam->params.pnpID.vendor = data[0]+(((u16)data[1])<<8);
1631                         cam->params.pnpID.product = data[2]+(((u16)data[3])<<8);
1632                         cam->params.pnpID.deviceRevision =
1633                                 data[4]+(((u16)data[5])<<8);
1634                         break;
1635                 case CPIA_COMMAND_GetCameraStatus:
1636                         cam->params.status.systemState = data[0];
1637                         cam->params.status.grabState = data[1];
1638                         cam->params.status.streamState = data[2];
1639                         cam->params.status.fatalError = data[3];
1640                         cam->params.status.cmdError = data[4];
1641                         cam->params.status.debugFlags = data[5];
1642                         cam->params.status.vpStatus = data[6];
1643                         cam->params.status.errorCode = data[7];
1644                         break;
1645                 case CPIA_COMMAND_GetVPVersion:
1646                         cam->params.vpVersion.vpVersion = data[0];
1647                         cam->params.vpVersion.vpRevision = data[1];
1648                         cam->params.vpVersion.cameraHeadID =
1649                                 data[2]+(((u16)data[3])<<8);
1650                         break;
1651                 case CPIA_COMMAND_GetColourParams:
1652                         cam->params.colourParams.brightness = data[0];
1653                         cam->params.colourParams.contrast = data[1];
1654                         cam->params.colourParams.saturation = data[2];
1655                         up(&cam->param_lock);
1656                         break;
1657                 case CPIA_COMMAND_GetColourBalance:
1658                         cam->params.colourBalance.redGain = data[0];
1659                         cam->params.colourBalance.greenGain = data[1];
1660                         cam->params.colourBalance.blueGain = data[2];
1661                         up(&cam->param_lock);
1662                         break;
1663                 case CPIA_COMMAND_GetExposure:
1664                         cam->params.exposure.gain = data[0];
1665                         cam->params.exposure.fineExp = data[1];
1666                         cam->params.exposure.coarseExpLo = data[2];
1667                         cam->params.exposure.coarseExpHi = data[3];
1668                         cam->params.exposure.redComp = data[4];
1669                         cam->params.exposure.green1Comp = data[5];
1670                         cam->params.exposure.green2Comp = data[6];
1671                         cam->params.exposure.blueComp = data[7];
1672                         /* If the *Comp parameters are wacko, generate
1673                          * a warning, and reset them back to default
1674                          * values.             - rich@annexia.org
1675                          */
1676                         if (cam->params.exposure.redComp < 220 ||
1677                             cam->params.exposure.redComp > 255 ||
1678                             cam->params.exposure.green1Comp < 214 ||
1679                             cam->params.exposure.green1Comp > 255 ||
1680                             cam->params.exposure.green2Comp < 214 ||
1681                             cam->params.exposure.green2Comp > 255 ||
1682                             cam->params.exposure.blueComp < 230 ||
1683                             cam->params.exposure.blueComp > 255)
1684                           {
1685                             printk (KERN_WARNING "*_comp parameters have gone AWOL (%d/%d/%d/%d) - reseting them\n",
1686                                     cam->params.exposure.redComp,
1687                                     cam->params.exposure.green1Comp,
1688                                     cam->params.exposure.green2Comp,
1689                                     cam->params.exposure.blueComp);
1690                             cam->params.exposure.redComp = 220;
1691                             cam->params.exposure.green1Comp = 214;
1692                             cam->params.exposure.green2Comp = 214;
1693                             cam->params.exposure.blueComp = 230;
1694                           }
1695                         up(&cam->param_lock);
1696                         break;
1697
1698                 case CPIA_COMMAND_ReadMCPorts: 
1699                         if (!cam->params.qx3.qx3_detected) 
1700                                 break;
1701                         /* test button press */ 
1702                         cam->params.qx3.button = ((data[1] & 0x02) == 0);
1703                         if (cam->params.qx3.button) {
1704                                 /* button pressed - unlock the latch */
1705                                 do_command(cam,CPIA_COMMAND_WriteMCPort,3,0xDF,0xDF,0);
1706                                 do_command(cam,CPIA_COMMAND_WriteMCPort,3,0xFF,0xFF,0);
1707                         }
1708
1709                         /* test whether microscope is cradled */
1710                         cam->params.qx3.cradled = ((data[2] & 0x40) == 0);
1711                         break;
1712
1713                 default:
1714                         break;
1715                 }
1716         }
1717         return retval;
1718 }
1719
1720 /* send a command  to the camera with an additional data transaction */
1721 static int do_command_extended(struct cam_data *cam, u16 command,
1722                                u8 a, u8 b, u8 c, u8 d,
1723                                u8 e, u8 f, u8 g, u8 h,
1724                                u8 i, u8 j, u8 k, u8 l)
1725 {
1726         int retval;
1727         u8 cmd[8], data[8];
1728
1729         cmd[0] = command>>8;
1730         cmd[1] = command&0xff;
1731         cmd[2] = a;
1732         cmd[3] = b;
1733         cmd[4] = c;
1734         cmd[5] = d;
1735         cmd[6] = 8;
1736         cmd[7] = 0;
1737         data[0] = e;
1738         data[1] = f;
1739         data[2] = g;
1740         data[3] = h;
1741         data[4] = i;
1742         data[5] = j;
1743         data[6] = k;
1744         data[7] = l;
1745
1746         retval = cam->ops->transferCmd(cam->lowlevel_data, cmd, data);
1747         if (retval)
1748                 LOG("%x - failed\n", command);
1749
1750         return retval;
1751 }
1752
1753 /**********************************************************************
1754  *
1755  * Colorspace conversion
1756  *
1757  **********************************************************************/
1758 #define LIMIT(x) ((((x)>0xffffff)?0xff0000:(((x)<=0xffff)?0:(x)&0xff0000))>>16)
1759
1760 static int yuvconvert(unsigned char *yuv, unsigned char *rgb, int out_fmt,
1761                       int in_uyvy, int mmap_kludge)
1762 {
1763         int y, u, v, r, g, b, y1;
1764
1765         switch(out_fmt) {
1766         case VIDEO_PALETTE_RGB555:
1767         case VIDEO_PALETTE_RGB565:
1768         case VIDEO_PALETTE_RGB24:
1769         case VIDEO_PALETTE_RGB32:
1770                 if (in_uyvy) {
1771                         u = *yuv++ - 128;
1772                         y = (*yuv++ - 16) * 76310;
1773                         v = *yuv++ - 128;
1774                         y1 = (*yuv - 16) * 76310;
1775                 } else {
1776                         y = (*yuv++ - 16) * 76310;
1777                         u = *yuv++ - 128;
1778                         y1 = (*yuv++ - 16) * 76310;
1779                         v = *yuv - 128;
1780                 }
1781                 r = 104635 * v;
1782                 g = -25690 * u + -53294 * v;
1783                 b = 132278 * u;
1784                 break;
1785         default:
1786                 y = *yuv++;
1787                 u = *yuv++;
1788                 y1 = *yuv++;
1789                 v = *yuv;
1790                 /* Just to avoid compiler warnings */
1791                 r = 0;
1792                 g = 0;
1793                 b = 0;
1794                 break;
1795         }
1796         switch(out_fmt) {
1797         case VIDEO_PALETTE_RGB555:
1798                 *rgb++ = ((LIMIT(g+y) & 0xf8) << 2) | (LIMIT(b+y) >> 3);
1799                 *rgb++ = ((LIMIT(r+y) & 0xf8) >> 1) | (LIMIT(g+y) >> 6);
1800                 *rgb++ = ((LIMIT(g+y1) & 0xf8) << 2) | (LIMIT(b+y1) >> 3);
1801                 *rgb = ((LIMIT(r+y1) & 0xf8) >> 1) | (LIMIT(g+y1) >> 6);
1802                 return 4;
1803         case VIDEO_PALETTE_RGB565:
1804                 *rgb++ = ((LIMIT(g+y) & 0xfc) << 3) | (LIMIT(b+y) >> 3);
1805                 *rgb++ = (LIMIT(r+y) & 0xf8) | (LIMIT(g+y) >> 5);
1806                 *rgb++ = ((LIMIT(g+y1) & 0xfc) << 3) | (LIMIT(b+y1) >> 3);
1807                 *rgb = (LIMIT(r+y1) & 0xf8) | (LIMIT(g+y1) >> 5);
1808                 return 4;
1809         case VIDEO_PALETTE_RGB24:
1810                 if (mmap_kludge) {
1811                         *rgb++ = LIMIT(b+y);
1812                         *rgb++ = LIMIT(g+y);
1813                         *rgb++ = LIMIT(r+y);
1814                         *rgb++ = LIMIT(b+y1);
1815                         *rgb++ = LIMIT(g+y1);
1816                         *rgb = LIMIT(r+y1);
1817                 } else {
1818                         *rgb++ = LIMIT(r+y);
1819                         *rgb++ = LIMIT(g+y);
1820                         *rgb++ = LIMIT(b+y);
1821                         *rgb++ = LIMIT(r+y1);
1822                         *rgb++ = LIMIT(g+y1);
1823                         *rgb = LIMIT(b+y1);
1824                 }
1825                 return 6;
1826         case VIDEO_PALETTE_RGB32:
1827                 if (mmap_kludge) {
1828                         *rgb++ = LIMIT(b+y);
1829                         *rgb++ = LIMIT(g+y);
1830                         *rgb++ = LIMIT(r+y);
1831                         rgb++;
1832                         *rgb++ = LIMIT(b+y1);
1833                         *rgb++ = LIMIT(g+y1);
1834                         *rgb = LIMIT(r+y1);
1835                 } else {
1836                         *rgb++ = LIMIT(r+y);
1837                         *rgb++ = LIMIT(g+y);
1838                         *rgb++ = LIMIT(b+y);
1839                         rgb++;
1840                         *rgb++ = LIMIT(r+y1);
1841                         *rgb++ = LIMIT(g+y1);
1842                         *rgb = LIMIT(b+y1);
1843                 }
1844                 return 8;
1845         case VIDEO_PALETTE_GREY:
1846                 *rgb++ = y;
1847                 *rgb = y1;
1848                 return 2;
1849         case VIDEO_PALETTE_YUV422:
1850         case VIDEO_PALETTE_YUYV:
1851                 *rgb++ = y;
1852                 *rgb++ = u;
1853                 *rgb++ = y1;
1854                 *rgb = v;
1855                 return 4;
1856         case VIDEO_PALETTE_UYVY:
1857                 *rgb++ = u;
1858                 *rgb++ = y;
1859                 *rgb++ = v;
1860                 *rgb = y1;
1861                 return 4;
1862         default:
1863                 DBG("Empty: %d\n", out_fmt);
1864                 return 0;
1865         }
1866 }
1867
1868 static int skipcount(int count, int fmt)
1869 {
1870         switch(fmt) {
1871         case VIDEO_PALETTE_GREY:
1872                 return count;
1873         case VIDEO_PALETTE_RGB555:
1874         case VIDEO_PALETTE_RGB565:
1875         case VIDEO_PALETTE_YUV422:
1876         case VIDEO_PALETTE_YUYV:
1877         case VIDEO_PALETTE_UYVY:
1878                 return 2*count;
1879         case VIDEO_PALETTE_RGB24:
1880                 return 3*count;
1881         case VIDEO_PALETTE_RGB32:
1882                 return 4*count;
1883         default:
1884                 return 0;
1885         }
1886 }
1887
1888 static int parse_picture(struct cam_data *cam, int size)
1889 {
1890         u8 *obuf, *ibuf, *end_obuf;
1891         int ll, in_uyvy, compressed, origsize, out_fmt;
1892
1893         /* make sure params don't change while we are decoding */
1894         down(&cam->param_lock);
1895
1896         obuf = cam->decompressed_frame.data;
1897         end_obuf = obuf+CPIA_MAX_FRAME_SIZE;
1898         ibuf = cam->raw_image;
1899         origsize = size;
1900         out_fmt = cam->vp.palette;
1901
1902         if ((ibuf[0] != MAGIC_0) || (ibuf[1] != MAGIC_1)) {
1903                 LOG("header not found\n");
1904                 up(&cam->param_lock);
1905                 return -1;
1906         }
1907
1908         if ((ibuf[16] != VIDEOSIZE_QCIF) && (ibuf[16] != VIDEOSIZE_CIF)) {
1909                 LOG("wrong video size\n");
1910                 up(&cam->param_lock);
1911                 return -1;
1912         }
1913         
1914         if (ibuf[17] != SUBSAMPLE_422) {
1915                 LOG("illegal subtype %d\n",ibuf[17]);
1916                 up(&cam->param_lock);
1917                 return -1;
1918         }
1919         
1920         if (ibuf[18] != YUVORDER_YUYV && ibuf[18] != YUVORDER_UYVY) {
1921                 LOG("illegal yuvorder %d\n",ibuf[18]);
1922                 up(&cam->param_lock);
1923                 return -1;
1924         }
1925         in_uyvy = ibuf[18] == YUVORDER_UYVY;
1926         
1927 #if 0
1928         /* FIXME: ROI mismatch occurs when switching capture sizes */
1929         if ((ibuf[24] != cam->params.roi.colStart) ||
1930             (ibuf[25] != cam->params.roi.colEnd) ||
1931             (ibuf[26] != cam->params.roi.rowStart) ||
1932             (ibuf[27] != cam->params.roi.rowEnd)) {
1933                 LOG("ROI mismatch\n");
1934                 up(&cam->param_lock);
1935                 return -1;
1936         }
1937 #endif
1938         
1939         if ((ibuf[28] != NOT_COMPRESSED) && (ibuf[28] != COMPRESSED)) {
1940                 LOG("illegal compression %d\n",ibuf[28]);
1941                 up(&cam->param_lock);
1942                 return -1;
1943         }
1944         compressed = (ibuf[28] == COMPRESSED);
1945         
1946         if (ibuf[29] != NO_DECIMATION) {
1947                 LOG("decimation not supported\n");
1948                 up(&cam->param_lock);
1949                 return -1;
1950         }
1951         
1952         cam->params.yuvThreshold.yThreshold = ibuf[30];
1953         cam->params.yuvThreshold.uvThreshold = ibuf[31];
1954         cam->params.status.systemState = ibuf[32];
1955         cam->params.status.grabState = ibuf[33];
1956         cam->params.status.streamState = ibuf[34];
1957         cam->params.status.fatalError = ibuf[35];
1958         cam->params.status.cmdError = ibuf[36];
1959         cam->params.status.debugFlags = ibuf[37];
1960         cam->params.status.vpStatus = ibuf[38];
1961         cam->params.status.errorCode = ibuf[39];
1962         cam->fps = ibuf[41];
1963         up(&cam->param_lock);
1964         
1965         ibuf += FRAME_HEADER_SIZE;
1966         size -= FRAME_HEADER_SIZE;
1967         ll = ibuf[0] | (ibuf[1] << 8);
1968         ibuf += 2;
1969
1970         while (size > 0) {
1971                 size -= (ll+2);
1972                 if (size < 0) {
1973                         LOG("Insufficient data in buffer\n");
1974                         return -1;
1975                 }
1976
1977                 while (ll > 1) {
1978                         if (!compressed || (compressed && !(*ibuf & 1))) {
1979                                 obuf += yuvconvert(ibuf, obuf, out_fmt,
1980                                                    in_uyvy, cam->mmap_kludge);
1981                                 ibuf += 4;
1982                                 ll -= 4;
1983                         } else {
1984                                 /*skip compressed interval from previous frame*/
1985                                 int skipsize = skipcount(*ibuf >> 1, out_fmt);
1986                                 obuf += skipsize;
1987                                 if (obuf > end_obuf) {
1988                                         LOG("Insufficient data in buffer\n");
1989                                         return -1;
1990                                 }
1991                                 ++ibuf;
1992                                 ll--;
1993                         }
1994                 }
1995                 if (ll == 1) {
1996                         if (*ibuf != EOL) {
1997                                 LOG("EOL not found giving up after %d/%d"
1998                                     " bytes\n", origsize-size, origsize);
1999                                 return -1;
2000                         }
2001
2002                         ibuf++; /* skip over EOL */
2003
2004                         if ((size > 3) && (ibuf[0] == EOI) && (ibuf[1] == EOI) &&
2005                            (ibuf[2] == EOI) && (ibuf[3] == EOI)) {
2006                                 size -= 4;
2007                                 break;
2008                         }
2009
2010                         if (size > 1) {
2011                                 ll = ibuf[0] | (ibuf[1] << 8);
2012                                 ibuf += 2; /* skip over line length */
2013                         }
2014                 } else {
2015                         LOG("line length was not 1 but %d after %d/%d bytes\n",
2016                             ll, origsize-size, origsize);
2017                         return -1;
2018                 }
2019         }
2020         
2021         cam->decompressed_frame.count = obuf-cam->decompressed_frame.data;
2022
2023         return cam->decompressed_frame.count;
2024 }
2025
2026 /* InitStreamCap wrapper to select correct start line */
2027 static inline int init_stream_cap(struct cam_data *cam)
2028 {
2029         return do_command(cam, CPIA_COMMAND_InitStreamCap,
2030                           0, cam->params.streamStartLine, 0, 0);
2031 }
2032
2033 /* update various camera modes and settings */
2034 static void dispatch_commands(struct cam_data *cam)
2035 {
2036         down(&cam->param_lock);
2037         if (cam->cmd_queue==COMMAND_NONE) {
2038                 up(&cam->param_lock);
2039                 return;
2040         }
2041         DEB_BYTE(cam->cmd_queue);
2042         DEB_BYTE(cam->cmd_queue>>8);
2043         if (cam->cmd_queue & COMMAND_SETCOLOURPARAMS)
2044                 do_command(cam, CPIA_COMMAND_SetColourParams,
2045                            cam->params.colourParams.brightness,
2046                            cam->params.colourParams.contrast,
2047                            cam->params.colourParams.saturation, 0);
2048
2049         if (cam->cmd_queue & COMMAND_SETCOMPRESSION)
2050                 do_command(cam, CPIA_COMMAND_SetCompression,
2051                            cam->params.compression.mode,
2052                            cam->params.compression.decimation, 0, 0);
2053
2054         if (cam->cmd_queue & COMMAND_SETFORMAT) {
2055                 do_command(cam, CPIA_COMMAND_SetFormat,
2056                            cam->params.format.videoSize,
2057                            cam->params.format.subSample,
2058                            cam->params.format.yuvOrder, 0);
2059                 do_command(cam, CPIA_COMMAND_SetROI,
2060                            cam->params.roi.colStart, cam->params.roi.colEnd,
2061                            cam->params.roi.rowStart, cam->params.roi.rowEnd);
2062                 cam->first_frame = 1;
2063         }
2064
2065         if (cam->cmd_queue & COMMAND_SETCOMPRESSIONTARGET)
2066                 do_command(cam, CPIA_COMMAND_SetCompressionTarget,
2067                            cam->params.compressionTarget.frTargeting,
2068                            cam->params.compressionTarget.targetFR,
2069                            cam->params.compressionTarget.targetQ, 0);
2070
2071         if (cam->cmd_queue & COMMAND_SETYUVTHRESH)
2072                 do_command(cam, CPIA_COMMAND_SetYUVThresh,
2073                            cam->params.yuvThreshold.yThreshold,
2074                            cam->params.yuvThreshold.uvThreshold, 0, 0);
2075
2076         if (cam->cmd_queue & COMMAND_SETECPTIMING)
2077                 do_command(cam, CPIA_COMMAND_SetECPTiming,
2078                            cam->params.ecpTiming, 0, 0, 0);
2079
2080         if (cam->cmd_queue & COMMAND_SETCOMPRESSIONPARAMS)
2081                 do_command_extended(cam, CPIA_COMMAND_SetCompressionParams,
2082                             0, 0, 0, 0,
2083                             cam->params.compressionParams.hysteresis,
2084                             cam->params.compressionParams.threshMax,
2085                             cam->params.compressionParams.smallStep,
2086                             cam->params.compressionParams.largeStep,
2087                             cam->params.compressionParams.decimationHysteresis,
2088                             cam->params.compressionParams.frDiffStepThresh,
2089                             cam->params.compressionParams.qDiffStepThresh,
2090                             cam->params.compressionParams.decimationThreshMod);
2091
2092         if (cam->cmd_queue & COMMAND_SETEXPOSURE)
2093                 do_command_extended(cam, CPIA_COMMAND_SetExposure,
2094                                     cam->params.exposure.gainMode,
2095                                     cam->params.exposure.expMode,
2096                                     cam->params.exposure.compMode,
2097                                     cam->params.exposure.centreWeight,
2098                                     cam->params.exposure.gain,
2099                                     cam->params.exposure.fineExp,
2100                                     cam->params.exposure.coarseExpLo,
2101                                     cam->params.exposure.coarseExpHi,
2102                                     cam->params.exposure.redComp,
2103                                     cam->params.exposure.green1Comp,
2104                                     cam->params.exposure.green2Comp,
2105                                     cam->params.exposure.blueComp);
2106
2107         if (cam->cmd_queue & COMMAND_SETCOLOURBALANCE) {
2108                 if (cam->params.colourBalance.balanceModeIsAuto) {
2109                         do_command(cam, CPIA_COMMAND_SetColourBalance,
2110                                    2, 0, 0, 0);
2111                 } else {
2112                         do_command(cam, CPIA_COMMAND_SetColourBalance,
2113                                    1,
2114                                    cam->params.colourBalance.redGain,
2115                                    cam->params.colourBalance.greenGain,
2116                                    cam->params.colourBalance.blueGain);
2117                         do_command(cam, CPIA_COMMAND_SetColourBalance,
2118                                    3, 0, 0, 0);
2119                 }
2120         }
2121
2122         if (cam->cmd_queue & COMMAND_SETSENSORFPS)
2123                 do_command(cam, CPIA_COMMAND_SetSensorFPS,
2124                            cam->params.sensorFps.divisor,
2125                            cam->params.sensorFps.baserate, 0, 0);
2126
2127         if (cam->cmd_queue & COMMAND_SETAPCOR)
2128                 do_command(cam, CPIA_COMMAND_SetApcor,
2129                            cam->params.apcor.gain1,
2130                            cam->params.apcor.gain2,
2131                            cam->params.apcor.gain4,
2132                            cam->params.apcor.gain8);
2133
2134         if (cam->cmd_queue & COMMAND_SETFLICKERCTRL)
2135                 do_command(cam, CPIA_COMMAND_SetFlickerCtrl,
2136                            cam->params.flickerControl.flickerMode,
2137                            cam->params.flickerControl.coarseJump,
2138                            cam->params.flickerControl.allowableOverExposure, 0);
2139
2140         if (cam->cmd_queue & COMMAND_SETVLOFFSET)
2141                 do_command(cam, CPIA_COMMAND_SetVLOffset,
2142                            cam->params.vlOffset.gain1,
2143                            cam->params.vlOffset.gain2,
2144                            cam->params.vlOffset.gain4,
2145                            cam->params.vlOffset.gain8);
2146
2147         if (cam->cmd_queue & COMMAND_PAUSE)
2148                 do_command(cam, CPIA_COMMAND_EndStreamCap, 0, 0, 0, 0);
2149
2150         if (cam->cmd_queue & COMMAND_RESUME)
2151                 init_stream_cap(cam);
2152
2153         if (cam->cmd_queue & COMMAND_SETLIGHTS && cam->params.qx3.qx3_detected) {
2154                 int p1 = (cam->params.qx3.bottomlight == 0) << 1;
2155                 int p2 = (cam->params.qx3.toplight == 0) << 3;
2156                 do_command(cam, CPIA_COMMAND_WriteVCReg,  0x90, 0x8F, 0x50, 0);
2157                 do_command(cam, CPIA_COMMAND_WriteMCPort, 2, 0, (p1|p2|0xE0), 0);
2158         }
2159
2160         up(&cam->param_lock);
2161         cam->cmd_queue = COMMAND_NONE;
2162         return;
2163 }
2164
2165 /* kernel thread function to read image from camera */
2166 static void fetch_frame(void *data)
2167 {
2168         int image_size, retry;
2169         struct cam_data *cam = (struct cam_data *)data;
2170         unsigned long oldjif, rate, diff;
2171
2172         /* Allow up to two bad images in a row to be read and
2173          * ignored before an error is reported */
2174         for (retry = 0; retry < 3; ++retry) {
2175                 if (retry)
2176                         DBG("retry=%d\n", retry);
2177
2178                 if (!cam->ops)
2179                         continue;
2180
2181                 /* load first frame always uncompressed */
2182                 if (cam->first_frame &&
2183                     cam->params.compression.mode != CPIA_COMPRESSION_NONE)
2184                         do_command(cam, CPIA_COMMAND_SetCompression,
2185                                    CPIA_COMPRESSION_NONE,
2186                                    NO_DECIMATION, 0, 0);
2187
2188                 /* init camera upload */
2189                 if (do_command(cam, CPIA_COMMAND_SetGrabMode,
2190                                CPIA_GRAB_CONTINUOUS, 0, 0, 0))
2191                         continue;
2192
2193                 if (do_command(cam, CPIA_COMMAND_GrabFrame, 0,
2194                                cam->params.streamStartLine, 0, 0))
2195                         continue;
2196
2197                 if (cam->ops->wait_for_stream_ready) {
2198                         /* loop until image ready */
2199                         do_command(cam, CPIA_COMMAND_GetCameraStatus,0,0,0,0);
2200                         while (cam->params.status.streamState != STREAM_READY) {
2201                                 if (current->need_resched)
2202                                         schedule();
2203
2204                                 current->state = TASK_INTERRUPTIBLE;
2205
2206                                 /* sleep for 10 ms, hopefully ;) */
2207                                 schedule_timeout(10*HZ/1000);
2208                                 if (signal_pending(current))
2209                                         return;
2210
2211                                 do_command(cam, CPIA_COMMAND_GetCameraStatus,
2212                                            0, 0, 0, 0);
2213                         }
2214                 }
2215
2216                 /* grab image from camera */
2217                 if (current->need_resched)
2218                         schedule();
2219
2220                 oldjif = jiffies;
2221                 image_size = cam->ops->streamRead(cam->lowlevel_data,
2222                                                   cam->raw_image, 0);
2223                 if (image_size <= 0) {
2224                         DBG("streamRead failed: %d\n", image_size);
2225                         continue;
2226                 }
2227
2228                 rate = image_size * HZ / 1024;
2229                 diff = jiffies-oldjif;
2230                 cam->transfer_rate = diff==0 ? rate : rate/diff;
2231                         /* diff==0 ? unlikely but possible */
2232
2233                 /* camera idle now so dispatch queued commands */
2234                 dispatch_commands(cam);
2235
2236                 /* Update our knowledge of the camera state */
2237                 do_command(cam, CPIA_COMMAND_GetColourBalance, 0, 0, 0, 0);
2238                 do_command(cam, CPIA_COMMAND_GetExposure, 0, 0, 0, 0);
2239                 do_command(cam, CPIA_COMMAND_ReadMCPorts, 0, 0, 0, 0);
2240
2241                 /* decompress and convert image to by copying it from
2242                  * raw_image to decompressed_frame
2243                  */
2244                 if (current->need_resched)
2245                         schedule();
2246
2247                 cam->image_size = parse_picture(cam, image_size);
2248                 if (cam->image_size <= 0)
2249                         DBG("parse_picture failed %d\n", cam->image_size);
2250                 else
2251                         break;
2252         }
2253
2254         if (retry < 3) {
2255                 /* FIXME: this only works for double buffering */
2256                 if (cam->frame[cam->curframe].state == FRAME_READY) {
2257                         memcpy(cam->frame[cam->curframe].data,
2258                                cam->decompressed_frame.data,
2259                                cam->decompressed_frame.count);
2260                         cam->frame[cam->curframe].state = FRAME_DONE;
2261                 } else
2262                         cam->decompressed_frame.state = FRAME_DONE;
2263
2264 #if 0
2265                 if (cam->first_frame &&
2266                     cam->params.compression.mode != CPIA_COMPRESSION_NONE) {
2267                         cam->first_frame = 0;
2268                         cam->cmd_queue |= COMMAND_SETCOMPRESSION;
2269                 }
2270 #else
2271                 if (cam->first_frame) {
2272                         cam->first_frame = 0;
2273                         cam->cmd_queue |= COMMAND_SETCOMPRESSION;
2274                         cam->cmd_queue |= COMMAND_SETEXPOSURE;
2275                 }
2276 #endif
2277         }
2278 }
2279
2280 static int capture_frame(struct cam_data *cam, struct video_mmap *vm)
2281 {
2282         int retval = 0;
2283
2284         if (!cam->frame_buf) {
2285                 /* we do lazy allocation */
2286                 if ((retval = allocate_frame_buf(cam)))
2287                         return retval;
2288         }
2289         
2290         /* FIXME: the first frame seems to be captured by the camera
2291            without regards to any initial settings, so we throw away
2292            that one, the next one is generated with our settings
2293            (exposure, color balance, ...)
2294         */
2295         if (cam->first_frame) {
2296                 cam->curframe = vm->frame;
2297                 cam->frame[cam->curframe].state = FRAME_READY;
2298                 fetch_frame(cam);
2299                 if (cam->frame[cam->curframe].state != FRAME_DONE)
2300                         retval = -EIO;
2301         }
2302         cam->curframe = vm->frame;
2303         cam->frame[cam->curframe].state = FRAME_READY;
2304         fetch_frame(cam);
2305         if (cam->frame[cam->curframe].state != FRAME_DONE)
2306                 retval=-EIO;
2307
2308         return retval;
2309 }
2310   
2311 static int goto_high_power(struct cam_data *cam)
2312 {
2313         if (do_command(cam, CPIA_COMMAND_GotoHiPower, 0, 0, 0, 0))
2314                 return -1;
2315         mdelay(100);            /* windows driver does it too */
2316         if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0))
2317                 return -1;
2318         if (cam->params.status.systemState == HI_POWER_STATE) {
2319                 DBG("camera now in HIGH power state\n");
2320                 return 0;
2321         }
2322         printstatus(cam);
2323         return -1;
2324 }
2325
2326 static int goto_low_power(struct cam_data *cam)
2327 {
2328         if (do_command(cam, CPIA_COMMAND_GotoLoPower, 0, 0, 0, 0))
2329                 return -1;
2330         if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0))
2331                 return -1;
2332         if (cam->params.status.systemState == LO_POWER_STATE) {
2333                 DBG("camera now in LOW power state\n");
2334                 return 0;
2335         }
2336         printstatus(cam);
2337         return -1;
2338 }
2339
2340 static void save_camera_state(struct cam_data *cam)
2341 {
2342         do_command(cam, CPIA_COMMAND_GetColourBalance, 0, 0, 0, 0);
2343         do_command(cam, CPIA_COMMAND_GetExposure, 0, 0, 0, 0);
2344
2345         DBG("%d/%d/%d/%d/%d/%d/%d/%d\n",
2346              cam->params.exposure.gain,
2347              cam->params.exposure.fineExp,
2348              cam->params.exposure.coarseExpLo,
2349              cam->params.exposure.coarseExpHi,
2350              cam->params.exposure.redComp,
2351              cam->params.exposure.green1Comp,
2352              cam->params.exposure.green2Comp,
2353              cam->params.exposure.blueComp);
2354         DBG("%d/%d/%d\n",
2355              cam->params.colourBalance.redGain,
2356              cam->params.colourBalance.greenGain,
2357              cam->params.colourBalance.blueGain);
2358 }
2359
2360 static void set_camera_state(struct cam_data *cam)
2361 {
2362         if(cam->params.colourBalance.balanceModeIsAuto) {
2363                 do_command(cam, CPIA_COMMAND_SetColourBalance, 
2364                            2, 0, 0, 0);
2365         } else {
2366                 do_command(cam, CPIA_COMMAND_SetColourBalance, 
2367                            1,
2368                            cam->params.colourBalance.redGain,
2369                            cam->params.colourBalance.greenGain,
2370                            cam->params.colourBalance.blueGain);
2371                 do_command(cam, CPIA_COMMAND_SetColourBalance, 
2372                            3, 0, 0, 0);
2373         }
2374
2375
2376         do_command_extended(cam, CPIA_COMMAND_SetExposure,
2377                             cam->params.exposure.gainMode, 1, 1,
2378                             cam->params.exposure.centreWeight,
2379                             cam->params.exposure.gain,
2380                             cam->params.exposure.fineExp,
2381                             cam->params.exposure.coarseExpLo,
2382                             cam->params.exposure.coarseExpHi,
2383                             cam->params.exposure.redComp,
2384                             cam->params.exposure.green1Comp,
2385                             cam->params.exposure.green2Comp,
2386                             cam->params.exposure.blueComp);
2387         do_command_extended(cam, CPIA_COMMAND_SetExposure,
2388                             0, 3, 0, 0,
2389                             0, 0, 0, 0, 0, 0, 0, 0);
2390
2391         if (!cam->params.exposure.gainMode)
2392                 cam->params.exposure.gainMode = 2;
2393         if (!cam->params.exposure.expMode)
2394                 cam->params.exposure.expMode = 2;
2395         if (!cam->params.exposure.centreWeight)
2396                 cam->params.exposure.centreWeight = 1;
2397         
2398         cam->cmd_queue = COMMAND_SETCOMPRESSION |
2399                          COMMAND_SETCOMPRESSIONTARGET |
2400                          COMMAND_SETCOLOURPARAMS |
2401                          COMMAND_SETFORMAT |
2402                          COMMAND_SETYUVTHRESH |
2403                          COMMAND_SETECPTIMING |
2404                          COMMAND_SETCOMPRESSIONPARAMS |
2405 #if 0
2406                          COMMAND_SETEXPOSURE |
2407 #endif
2408                          COMMAND_SETCOLOURBALANCE |
2409                          COMMAND_SETSENSORFPS |
2410                          COMMAND_SETAPCOR |
2411                          COMMAND_SETFLICKERCTRL |
2412                          COMMAND_SETVLOFFSET;
2413         dispatch_commands(cam);
2414         save_camera_state(cam);
2415
2416         return;
2417 }
2418
2419 static void get_version_information(struct cam_data *cam)
2420 {
2421         /* GetCPIAVersion */
2422         do_command(cam, CPIA_COMMAND_GetCPIAVersion, 0, 0, 0, 0);
2423
2424         /* GetPnPID */
2425         do_command(cam, CPIA_COMMAND_GetPnPID, 0, 0, 0, 0);
2426 }
2427
2428 /* initialize camera */
2429 static int reset_camera(struct cam_data *cam)
2430 {
2431         /* Start the camera in low power mode */
2432         if (goto_low_power(cam)) {
2433                 if (cam->params.status.systemState != WARM_BOOT_STATE)
2434                         return -ENODEV;
2435
2436                 /* FIXME: this is just dirty trial and error */
2437                 reset_camera_struct(cam);
2438                 goto_high_power(cam);
2439                 do_command(cam, CPIA_COMMAND_DiscardFrame, 0, 0, 0, 0);
2440                 if (goto_low_power(cam))
2441                         return -NODEV;
2442         }
2443         
2444         /* procedure described in developer's guide p3-28 */
2445         
2446         /* Check the firmware version FIXME: should we check PNPID? */
2447         cam->params.version.firmwareVersion = 0;
2448         get_version_information(cam);
2449         if (cam->params.version.firmwareVersion != 1)
2450                 return -ENODEV;
2451
2452         /* set QX3 detected flag */
2453         cam->params.qx3.qx3_detected = (cam->params.pnpID.vendor == 0x0813 &&
2454                                         cam->params.pnpID.product == 0x0001);
2455
2456         /* The fatal error checking should be done after
2457          * the camera powers up (developer's guide p 3-38) */
2458
2459         /* Set streamState before transition to high power to avoid bug
2460          * in firmware 1-02 */
2461         do_command(cam, CPIA_COMMAND_ModifyCameraStatus, STREAMSTATE, 0,
2462                    STREAM_NOT_READY, 0);
2463         
2464         /* GotoHiPower */
2465         if (goto_high_power(cam))
2466                 return -ENODEV;
2467
2468         /* Check the camera status */
2469         if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0))
2470                 return -EIO;
2471
2472         if (cam->params.status.fatalError) {
2473                 DBG("fatal_error:              %#04x\n",
2474                     cam->params.status.fatalError);
2475                 DBG("vp_status:                %#04x\n",
2476                     cam->params.status.vpStatus);
2477                 if (cam->params.status.fatalError & ~(COM_FLAG|CPIA_FLAG)) {
2478                         /* Fatal error in camera */
2479                         return -EIO;
2480                 } else if (cam->params.status.fatalError & (COM_FLAG|CPIA_FLAG)) {
2481                         /* Firmware 1-02 may do this for parallel port cameras,
2482                          * just clear the flags (developer's guide p 3-38) */
2483                         do_command(cam, CPIA_COMMAND_ModifyCameraStatus,
2484                                    FATALERROR, ~(COM_FLAG|CPIA_FLAG), 0, 0);
2485                 }
2486         }
2487         
2488         /* Check the camera status again */
2489         if (cam->params.status.fatalError) {
2490                 if (cam->params.status.fatalError)
2491                         return -EIO;
2492         }
2493         
2494         /* VPVersion can't be retrieved before the camera is in HiPower,
2495          * so get it here instead of in get_version_information. */
2496         do_command(cam, CPIA_COMMAND_GetVPVersion, 0, 0, 0, 0);
2497
2498         /* set camera to a known state */
2499         set_camera_state(cam);
2500         
2501         return 0;
2502 }
2503
2504 /* ------------------------- V4L interface --------------------- */
2505 static int cpia_open(struct video_device *dev, int flags)
2506 {
2507         int i;
2508         struct cam_data *cam = dev->priv;
2509
2510         if (!cam) {
2511                 DBG("Internal error, cam_data not found!\n");
2512                 return -EBUSY;
2513         }
2514             
2515         if (cam->open_count > 0) {
2516                 DBG("Camera already open\n");
2517                 return -EBUSY;
2518         }
2519         
2520         if (!cam->raw_image) {
2521                 cam->raw_image = rvmalloc(CPIA_MAX_IMAGE_SIZE);
2522                 if (!cam->raw_image)
2523                         return -ENOMEM;
2524         }
2525
2526         if (!cam->decompressed_frame.data) {
2527                 cam->decompressed_frame.data = rvmalloc(CPIA_MAX_FRAME_SIZE);
2528                 if (!cam->decompressed_frame.data) {
2529                         rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
2530                         cam->raw_image = NULL;
2531                         return -ENOMEM;
2532                 }
2533         }
2534         
2535         /* open cpia */
2536         if (cam->ops->open(cam->lowlevel_data)) {
2537                 rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE);
2538                 cam->decompressed_frame.data = NULL;
2539                 rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
2540                 cam->raw_image = NULL;
2541                 return -ENODEV;
2542         }
2543         
2544         /* reset the camera */
2545         if ((i = reset_camera(cam)) != 0) {
2546                 cam->ops->close(cam->lowlevel_data);
2547                 rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE);
2548                 cam->decompressed_frame.data = NULL;
2549                 rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
2550                 cam->raw_image = NULL;
2551                 return i;
2552         }
2553         
2554         /* Set ownership of /proc/cpia/videoX to current user */
2555         if(cam->proc_entry)
2556                 cam->proc_entry->uid = current->uid;
2557
2558         /* set mark for loading first frame uncompressed */
2559         cam->first_frame = 1;
2560
2561         /* init it to something */
2562         cam->mmap_kludge = 0;
2563         
2564         ++cam->open_count;
2565         return 0;
2566 }
2567
2568 static void cpia_close(struct video_device *dev)
2569 {
2570         struct cam_data *cam;
2571
2572         cam = dev->priv;
2573
2574         if (cam->ops) {
2575                 /* Return ownership of /proc/cpia/videoX to root */
2576                 if(cam->proc_entry)
2577                         cam->proc_entry->uid = 0;
2578         
2579                 /* save camera state for later open (developers guide ch 3.5.3) */
2580                 save_camera_state(cam);
2581
2582                 /* GotoLoPower */
2583                 goto_low_power(cam);
2584
2585                 /* Update the camera status */
2586                 do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0);
2587
2588                 /* cleanup internal state stuff */
2589                 free_frames(cam->frame);
2590
2591                 /* close cpia */
2592                 cam->ops->close(cam->lowlevel_data);
2593         }
2594
2595         if (--cam->open_count == 0) {
2596                 /* clean up capture-buffers */
2597                 if (cam->raw_image) {
2598                         rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
2599                         cam->raw_image = NULL;
2600                 }
2601
2602                 if (cam->decompressed_frame.data) {
2603                         rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE);
2604                         cam->decompressed_frame.data = NULL;
2605                 }
2606
2607                 if (cam->frame_buf)
2608                         free_frame_buf(cam);
2609
2610                 if (!cam->ops) {
2611                         video_unregister_device(dev);
2612                         kfree(cam);
2613                 }
2614         }
2615         
2616
2617         return;
2618 }
2619
2620 static long cpia_read(struct video_device *dev, char *buf,
2621                       unsigned long count, int noblock)
2622 {
2623         struct cam_data *cam = dev->priv;
2624
2625         /* make this _really_ smp and multithread-safe */
2626         if (down_interruptible(&cam->busy_lock))
2627                 return -EINTR;
2628
2629         if (!buf) {
2630                 DBG("buf NULL\n");
2631                 up(&cam->busy_lock);
2632                 return -EINVAL;
2633         }
2634
2635         if (!count) {
2636                 DBG("count 0\n");
2637                 up(&cam->busy_lock);
2638                 return 0;
2639         }
2640
2641         if (!cam->ops) {
2642                 DBG("ops NULL\n");
2643                 up(&cam->busy_lock);
2644                 return -ENODEV;
2645         }
2646
2647         /* upload frame */
2648         cam->decompressed_frame.state = FRAME_READY;
2649         cam->mmap_kludge=0;
2650         fetch_frame(cam);
2651         if (cam->decompressed_frame.state != FRAME_DONE) {
2652                 DBG("upload failed %d/%d\n", cam->decompressed_frame.count,
2653                     cam->decompressed_frame.state);
2654                 up(&cam->busy_lock);
2655                 return -EIO;
2656         }
2657         cam->decompressed_frame.state = FRAME_UNUSED;
2658
2659         /* copy data to user space */
2660         if (cam->decompressed_frame.count > count) {
2661                 DBG("count wrong: %d, %lu\n", cam->decompressed_frame.count,
2662                     count);
2663                 up(&cam->busy_lock);
2664                 return -EFAULT;
2665         }
2666         if (copy_to_user(buf, cam->decompressed_frame.data,
2667                         cam->decompressed_frame.count)) {
2668                 DBG("copy_to_user failed\n");
2669                 up(&cam->busy_lock);
2670                 return -EFAULT;
2671         }
2672
2673         up(&cam->busy_lock);
2674         return cam->decompressed_frame.count;
2675 }
2676
2677 static int cpia_ioctl(struct video_device *dev, unsigned int ioctlnr, void *arg)
2678 {
2679         struct cam_data *cam = dev->priv;
2680         int retval = 0;
2681
2682         if (!cam || !cam->ops)
2683                 return -ENODEV;
2684         
2685         /* make this _really_ smp-safe */
2686         if (down_interruptible(&cam->busy_lock))
2687                 return -EINTR;
2688
2689         //DBG("cpia_ioctl: %u\n", ioctlnr);
2690
2691         switch (ioctlnr) {
2692         /* query capabilites */
2693         case VIDIOCGCAP:
2694         {
2695                 struct video_capability b;
2696
2697                 DBG("VIDIOCGCAP\n");
2698                 strcpy(b.name, "CPiA Camera");
2699                 b.type = VID_TYPE_CAPTURE;
2700                 b.channels = 1;
2701                 b.audios = 0;
2702                 b.maxwidth = 352;       /* VIDEOSIZE_CIF */
2703                 b.maxheight = 288;
2704                 b.minwidth = 48;        /* VIDEOSIZE_48_48 */
2705                 b.minheight = 48;
2706
2707                 if (copy_to_user(arg, &b, sizeof(b)))
2708                         retval = -EFAULT;
2709
2710                 break;
2711         }
2712
2713         /* get/set video source - we are a camera and nothing else */
2714         case VIDIOCGCHAN:
2715         {
2716                 struct video_channel v;
2717
2718                 DBG("VIDIOCGCHAN\n");
2719                 if (copy_from_user(&v, arg, sizeof(v))) {
2720                         retval = -EFAULT;
2721                         break;
2722                 }
2723                 if (v.channel != 0) {
2724                         retval = -EINVAL;
2725                         break;
2726                 }
2727
2728                 v.channel = 0;
2729                 strcpy(v.name, "Camera");
2730                 v.tuners = 0;
2731                 v.flags = 0;
2732                 v.type = VIDEO_TYPE_CAMERA;
2733                 v.norm = 0;
2734
2735                 if (copy_to_user(arg, &v, sizeof(v)))
2736                         retval = -EFAULT;
2737                 break;
2738         }
2739         
2740         case VIDIOCSCHAN:
2741         {
2742                 int v;
2743
2744                 DBG("VIDIOCSCHAN\n");
2745                 if (copy_from_user(&v, arg, sizeof(v)))
2746                         retval = -EFAULT;
2747
2748                 if (retval == 0 && v != 0)
2749                         retval = -EINVAL;
2750
2751                 break;
2752         }
2753
2754         /* image properties */
2755         case VIDIOCGPICT:
2756                 DBG("VIDIOCGPICT\n");
2757                 if (copy_to_user(arg, &cam->vp, sizeof(struct video_picture)))
2758                         retval = -EFAULT;
2759                 break;
2760         
2761         case VIDIOCSPICT:
2762         {
2763                 struct video_picture vp;
2764
2765                 DBG("VIDIOCSPICT\n");
2766
2767                 /* copy_from_user */
2768                 if (copy_from_user(&vp, arg, sizeof(vp))) {
2769                         retval = -EFAULT;
2770                         break;
2771                 }
2772
2773                 /* check validity */
2774                 DBG("palette: %d\n", vp.palette);
2775                 DBG("depth: %d\n", vp.depth);
2776                 if (!valid_mode(vp.palette, vp.depth)) {
2777                         retval = -EINVAL;
2778                         break;
2779                 }
2780
2781                 down(&cam->param_lock);
2782                 /* brightness, colour, contrast need no check 0-65535 */
2783                 memcpy( &cam->vp, &vp, sizeof(vp) );
2784                 /* update cam->params.colourParams */
2785                 cam->params.colourParams.brightness = vp.brightness*100/65535;
2786                 cam->params.colourParams.contrast = vp.contrast*100/65535;
2787                 cam->params.colourParams.saturation = vp.colour*100/65535;
2788                 /* contrast is in steps of 8, so round */
2789                 cam->params.colourParams.contrast =
2790                         ((cam->params.colourParams.contrast + 3) / 8) * 8;
2791                 if (cam->params.version.firmwareVersion == 1 &&
2792                     cam->params.version.firmwareRevision == 2 &&
2793                     cam->params.colourParams.contrast > 80) {
2794                         /* 1-02 firmware limits contrast to 80 */
2795                         cam->params.colourParams.contrast = 80;
2796                 }
2797
2798                 /* queue command to update camera */
2799                 cam->cmd_queue |= COMMAND_SETCOLOURPARAMS;
2800                 up(&cam->param_lock);
2801                 DBG("VIDIOCSPICT: %d / %d // %d / %d / %d / %d\n",
2802                     vp.depth, vp.palette, vp.brightness, vp.hue, vp.colour,
2803                     vp.contrast);
2804                 break;
2805         }
2806
2807         /* get/set capture window */
2808         case VIDIOCGWIN:
2809                 DBG("VIDIOCGWIN\n");
2810
2811                 if (copy_to_user(arg, &cam->vw, sizeof(struct video_window)))
2812                         retval = -EFAULT;
2813                 break;
2814         
2815         case VIDIOCSWIN:
2816         {
2817                 /* copy_from_user, check validity, copy to internal structure */
2818                 struct video_window vw;
2819                 DBG("VIDIOCSWIN\n");
2820                 if (copy_from_user(&vw, arg, sizeof(vw))) {
2821                         retval = -EFAULT;
2822                         break;
2823                 }
2824
2825                 if (vw.clipcount != 0) {    /* clipping not supported */
2826                         retval = -EINVAL;
2827                         break;
2828                 }
2829                 if (vw.clips != NULL) {     /* clipping not supported */
2830                         retval = -EINVAL;
2831                         break;
2832                 }
2833
2834                 /* we set the video window to something smaller or equal to what
2835                 * is requested by the user???
2836                 */
2837                 down(&cam->param_lock);
2838                 if (vw.width != cam->vw.width || vw.height != cam->vw.height) {
2839                         int video_size = match_videosize(vw.width, vw.height);
2840
2841                         if (video_size < 0) {
2842                                 retval = -EINVAL;
2843                                 up(&cam->param_lock);
2844                                 break;
2845                         }
2846                         cam->video_size = video_size;
2847                         set_vw_size(cam);
2848                         DBG("%d / %d\n", cam->vw.width, cam->vw.height);
2849                         cam->cmd_queue |= COMMAND_SETFORMAT;
2850                 }
2851
2852                 up(&cam->param_lock);
2853
2854                 /* setformat ignored by camera during streaming,
2855                  * so stop/dispatch/start */
2856                 if (cam->cmd_queue & COMMAND_SETFORMAT) {
2857                         DBG("\n");
2858                         dispatch_commands(cam);
2859                 }
2860                 DBG("%d/%d:%d\n", cam->video_size,
2861                     cam->vw.width, cam->vw.height);
2862                 break;
2863         }
2864
2865         /* mmap interface */
2866         case VIDIOCGMBUF:
2867         {
2868                 struct video_mbuf vm;
2869                 int i;
2870
2871                 DBG("VIDIOCGMBUF\n");
2872                 memset(&vm, 0, sizeof(vm));
2873                 vm.size = CPIA_MAX_FRAME_SIZE*FRAME_NUM;
2874                 vm.frames = FRAME_NUM;
2875                 for (i = 0; i < FRAME_NUM; i++)
2876                         vm.offsets[i] = CPIA_MAX_FRAME_SIZE * i;
2877
2878                 if (copy_to_user((void *)arg, (void *)&vm, sizeof(vm)))
2879                         retval = -EFAULT;
2880
2881                 break;
2882         }
2883         
2884         case VIDIOCMCAPTURE:
2885         {
2886                 struct video_mmap vm;
2887                 int video_size;
2888
2889                 if (copy_from_user((void *)&vm, (void *)arg, sizeof(vm))) {
2890                         retval = -EFAULT;
2891                         break;
2892                 }
2893                 DBG("VIDIOCMCAPTURE: %d / %d / %dx%d\n", vm.format, vm.frame,
2894                     vm.width, vm.height);
2895                 if (vm.frame<0||vm.frame>=FRAME_NUM) {
2896                         retval = -EINVAL;
2897                         break;
2898                 }
2899
2900                 /* set video format */
2901                 cam->vp.palette = vm.format;
2902                 switch(vm.format) {
2903                 case VIDEO_PALETTE_GREY:
2904                         cam->vp.depth=8;
2905                         break;
2906                 case VIDEO_PALETTE_RGB555:
2907                 case VIDEO_PALETTE_RGB565:
2908                 case VIDEO_PALETTE_YUV422:
2909                 case VIDEO_PALETTE_YUYV:
2910                 case VIDEO_PALETTE_UYVY:
2911                         cam->vp.depth = 16;
2912                         break;
2913                 case VIDEO_PALETTE_RGB24:
2914                         cam->vp.depth = 24;
2915                         break;
2916                 case VIDEO_PALETTE_RGB32:
2917                         cam->vp.depth = 32;
2918                         break;
2919                 default:
2920                         retval = -EINVAL;
2921                         break;
2922                 }
2923                 if (retval)
2924                         break;
2925
2926                 /* set video size */
2927                 video_size = match_videosize(vm.width, vm.height);
2928                 if (video_size < 0) {
2929                         retval = -EINVAL;
2930                         break;
2931                 }
2932                 if (video_size != cam->video_size) {
2933                         cam->video_size = video_size;
2934                         set_vw_size(cam);
2935                         cam->cmd_queue |= COMMAND_SETFORMAT;
2936                         dispatch_commands(cam);
2937                 }
2938                 /* according to v4l-spec we must start streaming here */
2939                 cam->mmap_kludge = 1;
2940                 retval = capture_frame(cam, &vm);
2941
2942                 break;
2943         }
2944         
2945         case VIDIOCSYNC:
2946         {
2947                 int frame;
2948
2949                 if (copy_from_user((void *)&frame, arg, sizeof(int))) {
2950                         retval = -EFAULT;
2951                         break;
2952                 }
2953                 //DBG("VIDIOCSYNC: %d\n", frame);
2954
2955                 if (frame<0 || frame >= FRAME_NUM) {
2956                         retval = -EINVAL;
2957                         break;
2958                 }
2959
2960                 switch (cam->frame[frame].state) {
2961                 case FRAME_UNUSED:
2962                 case FRAME_READY:
2963                 case FRAME_GRABBING:
2964                         DBG("sync to unused frame %d\n", frame);
2965                         retval = -EINVAL;
2966                         break;
2967
2968                 case FRAME_DONE:
2969                         cam->frame[frame].state = FRAME_UNUSED;
2970                         //DBG("VIDIOCSYNC: %d synced\n", frame);
2971                         break;
2972                 }
2973                 if (retval == -EINTR) {
2974                         /* FIXME - xawtv does not handle this nice */
2975                         retval = 0;
2976                 }
2977                 break;
2978         }
2979
2980         /* pointless to implement overlay with this camera */
2981         case VIDIOCCAPTURE:
2982                 retval = -EINVAL;
2983                 break;
2984         case VIDIOCGFBUF:
2985                 retval = -EINVAL;
2986                 break;
2987         case VIDIOCSFBUF:
2988                 retval = -EINVAL;
2989                 break;
2990         case VIDIOCKEY:
2991                 retval = -EINVAL;
2992                 break;
2993
2994         /* tuner interface - we have none */
2995         case VIDIOCGTUNER:
2996                 retval = -EINVAL;
2997                 break;
2998         case VIDIOCSTUNER:
2999                 retval = -EINVAL;
3000                 break;
3001         case VIDIOCGFREQ:
3002                 retval = -EINVAL;
3003                 break;
3004         case VIDIOCSFREQ:
3005                 retval = -EINVAL;
3006                 break;
3007
3008         /* audio interface - we have none */
3009         case VIDIOCGAUDIO:
3010                 retval = -EINVAL;
3011                 break;
3012         case VIDIOCSAUDIO:
3013                 retval = -EINVAL;
3014                 break;
3015         default:
3016                 retval = -ENOIOCTLCMD;
3017                 break;
3018         }
3019
3020         up(&cam->param_lock);
3021         up(&cam->busy_lock);
3022         return retval;
3023
3024
3025 /* FIXME */
3026 static int cpia_mmap(struct video_device *dev, const char *adr,
3027                      unsigned long size)
3028 {
3029         unsigned long start = (unsigned long)adr;
3030         unsigned long page, pos;
3031         struct cam_data *cam = dev->priv;
3032         int retval;
3033
3034         if (!cam || !cam->ops)
3035                 return -ENODEV;
3036         
3037         DBG("cpia_mmap: %ld\n", size);
3038
3039         if (size > FRAME_NUM*CPIA_MAX_FRAME_SIZE)
3040                 return -EINVAL;
3041
3042         if (!cam || !cam->ops)
3043                 return -ENODEV;
3044         
3045         /* make this _really_ smp-safe */
3046         if (down_interruptible(&cam->busy_lock))
3047                 return -EINTR;
3048
3049         if (!cam->frame_buf) {  /* we do lazy allocation */
3050                 if ((retval = allocate_frame_buf(cam))) {
3051                         up(&cam->busy_lock);
3052                         return retval;
3053                 }
3054         }
3055
3056         pos = (unsigned long)(cam->frame_buf);
3057         while (size > 0) {
3058                 page = kvirt_to_pa(pos);
3059                 if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) {
3060                         up(&cam->busy_lock);
3061                         return -EAGAIN;
3062                 }
3063                 start += PAGE_SIZE;
3064                 pos += PAGE_SIZE;
3065                 if (size > PAGE_SIZE)
3066                         size -= PAGE_SIZE;
3067                 else
3068                         size = 0;
3069         }
3070
3071         DBG("cpia_mmap: %ld\n", size);
3072         up(&cam->busy_lock);
3073
3074         return 0;
3075 }
3076
3077 int cpia_video_init(struct video_device *vdev)
3078 {
3079 #ifdef CONFIG_PROC_FS
3080         create_proc_cpia_cam(vdev->priv);
3081 #endif
3082         return 0;
3083 }
3084
3085 static struct video_device cpia_template = {
3086         owner:          THIS_MODULE,
3087         name:           "CPiA Camera",
3088         type:           VID_TYPE_CAPTURE,
3089         hardware:       VID_HARDWARE_CPIA,
3090         open:           cpia_open,
3091         close:          cpia_close,
3092         read:           cpia_read,
3093         ioctl:          cpia_ioctl,
3094         mmap:           cpia_mmap,
3095         initialize:     cpia_video_init,
3096         minor:          -1,
3097 };
3098
3099 /* initialise cam_data structure  */
3100 static void reset_camera_struct(struct cam_data *cam)
3101 {
3102         /* The following parameter values are the defaults from
3103          * "Software Developer's Guide for CPiA Cameras".  Any changes
3104          * to the defaults are noted in comments. */
3105         cam->params.colourParams.brightness = 50;
3106         cam->params.colourParams.contrast = 48;
3107         cam->params.colourParams.saturation = 50;
3108         cam->params.exposure.gainMode = 2;
3109         cam->params.exposure.expMode = 2;               /* AEC */
3110         cam->params.exposure.compMode = 1;
3111         cam->params.exposure.centreWeight = 1;
3112         cam->params.exposure.gain = 0;
3113         cam->params.exposure.fineExp = 0;
3114         cam->params.exposure.coarseExpLo = 185;
3115         cam->params.exposure.coarseExpHi = 0;
3116         cam->params.exposure.redComp = 220;
3117         cam->params.exposure.green1Comp = 214;
3118         cam->params.exposure.green2Comp = 214;
3119         cam->params.exposure.blueComp = 230;
3120         cam->params.colourBalance.balanceModeIsAuto = 1;
3121         cam->params.colourBalance.redGain = 32;
3122         cam->params.colourBalance.greenGain = 6;
3123         cam->params.colourBalance.blueGain = 92;
3124         cam->params.apcor.gain1 = 0x1c;
3125         cam->params.apcor.gain2 = 0x1a;
3126         cam->params.apcor.gain4 = 0x2d;
3127         cam->params.apcor.gain8 = 0x2a;
3128         cam->params.flickerControl.flickerMode = 0;
3129         cam->params.flickerControl.coarseJump = 
3130                 flicker_jumps[cam->mainsFreq]
3131                              [cam->params.sensorFps.baserate]
3132                              [cam->params.sensorFps.divisor];
3133         cam->params.vlOffset.gain1 = 24;
3134         cam->params.vlOffset.gain2 = 28;
3135         cam->params.vlOffset.gain4 = 30;
3136         cam->params.vlOffset.gain8 = 30;
3137         cam->params.compressionParams.hysteresis = 3;
3138         cam->params.compressionParams.threshMax = 11;
3139         cam->params.compressionParams.smallStep = 1;
3140         cam->params.compressionParams.largeStep = 3;
3141         cam->params.compressionParams.decimationHysteresis = 2;
3142         cam->params.compressionParams.frDiffStepThresh = 5;
3143         cam->params.compressionParams.qDiffStepThresh = 3;
3144         cam->params.compressionParams.decimationThreshMod = 2;
3145         /* End of default values from Software Developer's Guide */
3146         
3147         cam->transfer_rate = 0;
3148         
3149         /* Set Sensor FPS to 15fps. This seems better than 30fps
3150          * for indoor lighting. */
3151         cam->params.sensorFps.divisor = 1;
3152         cam->params.sensorFps.baserate = 1;
3153         
3154         cam->params.yuvThreshold.yThreshold = 6; /* From windows driver */
3155         cam->params.yuvThreshold.uvThreshold = 6; /* From windows driver */
3156         
3157         cam->params.format.subSample = SUBSAMPLE_422;
3158         cam->params.format.yuvOrder = YUVORDER_YUYV;
3159         
3160         cam->params.compression.mode = CPIA_COMPRESSION_AUTO;
3161         cam->params.compressionTarget.frTargeting =
3162                 CPIA_COMPRESSION_TARGET_QUALITY;
3163         cam->params.compressionTarget.targetFR = 15; /* From windows driver */
3164         cam->params.compressionTarget.targetQ = 5; /* From windows driver */
3165
3166         cam->params.qx3.qx3_detected = 0;
3167         cam->params.qx3.toplight = 0;
3168         cam->params.qx3.bottomlight = 0;
3169         cam->params.qx3.button = 0;
3170         cam->params.qx3.cradled = 0;
3171
3172         cam->video_size = VIDEOSIZE_CIF;
3173         
3174         cam->vp.colour = 32768;      /* 50% */
3175         cam->vp.hue = 32768;         /* 50% */
3176         cam->vp.brightness = 32768;  /* 50% */
3177         cam->vp.contrast = 32768;    /* 50% */
3178         cam->vp.whiteness = 0;       /* not used -> grayscale only */
3179         cam->vp.depth = 24;          /* to be set by user */
3180         cam->vp.palette = VIDEO_PALETTE_RGB24; /* to be set by user */
3181
3182         cam->vw.x = 0;
3183         cam->vw.y = 0;
3184         set_vw_size(cam);
3185         cam->vw.chromakey = 0;
3186         /* PP NOTE: my extension to use vw.flags for this, bear it! */
3187         cam->vw.flags = 0;
3188         cam->vw.clipcount = 0;
3189         cam->vw.clips = NULL;
3190
3191         cam->cmd_queue = COMMAND_NONE;
3192         cam->first_frame = 0;
3193
3194         return;
3195 }
3196
3197 /* initialize cam_data structure  */
3198 static void init_camera_struct(struct cam_data *cam,
3199                                struct cpia_camera_ops *ops )
3200 {
3201         int i;
3202
3203         /* Default everything to 0 */
3204         memset(cam, 0, sizeof(struct cam_data));
3205
3206         cam->ops = ops;
3207         init_MUTEX(&cam->param_lock);
3208         init_MUTEX(&cam->busy_lock);
3209
3210         reset_camera_struct(cam);
3211
3212         cam->proc_entry = NULL;
3213
3214         memcpy(&cam->vdev, &cpia_template, sizeof(cpia_template));
3215         cam->vdev.priv = cam;
3216         
3217         cam->curframe = 0;
3218         for (i = 0; i < FRAME_NUM; i++) {
3219                 cam->frame[i].width = 0;
3220                 cam->frame[i].height = 0;
3221                 cam->frame[i].state = FRAME_UNUSED;
3222                 cam->frame[i].data = NULL;
3223         }
3224         cam->decompressed_frame.width = 0;
3225         cam->decompressed_frame.height = 0;
3226         cam->decompressed_frame.state = FRAME_UNUSED;
3227         cam->decompressed_frame.data = NULL;
3228 }
3229
3230 struct cam_data *cpia_register_camera(struct cpia_camera_ops *ops, void *lowlevel)
3231 {
3232         struct cam_data *camera;
3233         
3234         /* Need a lock when adding/removing cameras.  This doesn't happen
3235          * often and doesn't take very long, so grabbing the kernel lock
3236          * should be OK. */
3237         
3238         if ((camera = kmalloc(sizeof(struct cam_data), GFP_KERNEL)) == NULL) {
3239                 unlock_kernel();
3240                 return NULL;
3241         }
3242         
3243         init_camera_struct( camera, ops );
3244         camera->lowlevel_data = lowlevel;
3245         
3246         /* register v4l device */
3247         if (video_register_device(&camera->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
3248                 kfree(camera);
3249                 unlock_kernel();
3250                 printk(KERN_DEBUG "video_register_device failed\n");
3251                 return NULL;
3252         }
3253
3254         /* get version information from camera: open/reset/close */
3255
3256         /* open cpia */
3257         if (camera->ops->open(camera->lowlevel_data))
3258                 return camera;
3259         
3260         /* reset the camera */
3261         if (reset_camera(camera) != 0) {
3262                 camera->ops->close(camera->lowlevel_data);
3263                 return camera;
3264         }
3265
3266         /* close cpia */
3267         camera->ops->close(camera->lowlevel_data);
3268
3269         printk(KERN_INFO "  CPiA Version: %d.%02d (%d.%d)\n",
3270                camera->params.version.firmwareVersion,
3271                camera->params.version.firmwareRevision,
3272                camera->params.version.vcVersion,
3273                camera->params.version.vcRevision);
3274         printk(KERN_INFO "  CPiA PnP-ID: %04x:%04x:%04x\n",
3275                camera->params.pnpID.vendor,
3276                camera->params.pnpID.product,
3277                camera->params.pnpID.deviceRevision);
3278         printk(KERN_INFO "  VP-Version: %d.%d %04x\n",
3279                camera->params.vpVersion.vpVersion,
3280                camera->params.vpVersion.vpRevision,
3281                camera->params.vpVersion.cameraHeadID);
3282
3283         return camera;
3284 }
3285
3286 void cpia_unregister_camera(struct cam_data *cam)
3287 {
3288         if (!cam->open_count) {
3289                 DBG("unregistering video\n");
3290                 video_unregister_device(&cam->vdev);
3291         } else {
3292                 LOG("/dev/video%d removed while open, "
3293                     "deferring video_unregister_device\n", cam->vdev.minor);
3294                 DBG("camera open -- setting ops to NULL\n");
3295                 cam->ops = NULL;
3296         }
3297         
3298 #ifdef CONFIG_PROC_FS
3299         DBG("destroying /proc/cpia/video%d\n", cam->vdev.minor);
3300         destroy_proc_cpia_cam(cam);
3301 #endif  
3302         if (!cam->open_count) {
3303                 DBG("freeing camera\n");
3304                 kfree(cam);
3305         }
3306 }
3307
3308 static int __init cpia_init(void)
3309 {
3310         printk(KERN_INFO "%s v%d.%d.%d\n", ABOUT,
3311                CPIA_MAJ_VER, CPIA_MIN_VER, CPIA_PATCH_VER);
3312 #ifdef CONFIG_PROC_FS
3313         proc_cpia_create();
3314 #endif
3315
3316 #ifdef CONFIG_VIDEO_CPIA_PP
3317         cpia_pp_init();
3318 #endif
3319 #ifdef CONFIG_KMOD
3320 #ifdef CONFIG_VIDEO_CPIA_PP_MODULE
3321         request_module("cpia_pp");
3322 #endif
3323
3324 #ifdef CONFIG_VIDEO_CPIA_USB_MODULE
3325         request_module("cpia_usb");
3326 #endif
3327 #endif  /* CONFIG_KMOD */
3328 #ifdef CONFIG_VIDEO_CPIA_USB
3329         cpia_usb_init();
3330 #endif
3331         return 0;
3332 }
3333
3334 static void __exit cpia_exit(void)
3335 {
3336 #ifdef CONFIG_PROC_FS
3337         proc_cpia_destroy();
3338 #endif
3339 }
3340
3341 module_init(cpia_init);
3342 module_exit(cpia_exit);
3343
3344 /* Exported symbols for modules. */
3345
3346 EXPORT_SYMBOL(cpia_register_camera);
3347 EXPORT_SYMBOL(cpia_unregister_camera);