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