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