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