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