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