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