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