Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

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