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