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