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