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