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