~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux-2.6.17/drivers/media/video/cpia.c

Version: ~ [ 2.6.16 ] ~ [ 2.6.17 ] ~
Architecture: ~ [ ia64 ] ~ [ i386 ] ~ [ arm ] ~ [ ppc ] ~ [ sparc64 ] ~

  1 /*
  2  * cpia CPiA driver
  3  *
  4  * Supports CPiA based Video Camera's.
  5  *
  6  * (C) Copyright 1999-2000 Peter Pregler
  7  * (C) Copyright 1999-2000 Scott J. Bertin
  8  * (C) Copyright 1999-2000 Johannes Erdfelt <johannes@erdfelt.com>
  9  * (C) Copyright 2000 STMicroelectronics
 10  *
 11  * This program is free software; you can redistribute it and/or modify
 12  * it under the terms of the GNU General Public License as published by
 13  * the Free Software Foundation; either version 2 of the License, or
 14  * (at your option) any later version.
 15  *
 16  * This program is distributed in the hope that it will be useful,
 17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 19  * GNU General Public License for more details.
 20  *
 21  * You should have received a copy of the GNU General Public License
 22  * along with this program; if not, write to the Free Software
 23  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 24  */
 25 
 26 /* define _CPIA_DEBUG_ for verbose debug output (see cpia.h) */
 27 /* #define _CPIA_DEBUG_  1 */
 28 
 29 #include <linux/config.h>
 30 
 31 #include <linux/module.h>
 32 #include <linux/moduleparam.h>
 33 #include <linux/init.h>
 34 #include <linux/fs.h>
 35 #include <linux/vmalloc.h>
 36 #include <linux/slab.h>
 37 #include <linux/proc_fs.h>
 38 #include <linux/ctype.h>
 39 #include <linux/pagemap.h>
 40 #include <linux/delay.h>
 41 #include <asm/io.h>
 42 #include <linux/mutex.h>
 43 
 44 #ifdef CONFIG_KMOD
 45 #include <linux/kmod.h>
 46 #endif
 47 
 48 #include "cpia.h"
 49 
 50 #ifdef CONFIG_VIDEO_CPIA_PP
 51 extern int cpia_pp_init(void);
 52 #endif
 53 #ifdef CONFIG_VIDEO_CPIA_USB
 54 extern int cpia_usb_init(void);
 55 #endif
 56 
 57 static int video_nr = -1;
 58 
 59 #ifdef MODULE
 60 module_param(video_nr, int, 0);
 61 MODULE_AUTHOR("Scott J. Bertin <sbertin@securenym.net> & Peter Pregler <Peter_Pregler@email.com> & Johannes Erdfelt <johannes@erdfelt.com>");
 62 MODULE_DESCRIPTION("V4L-driver for Vision CPiA based cameras");
 63 MODULE_LICENSE("GPL");
 64 MODULE_SUPPORTED_DEVICE("video");
 65 #endif
 66 
 67 static unsigned short colorspace_conv;
 68 module_param(colorspace_conv, ushort, 0444);
 69 MODULE_PARM_DESC(colorspace_conv,
 70                  " Colorspace conversion:"
 71                  "\n  0 = disable, 1 = enable"
 72                  "\n  Default value is 0"
 73                  );
 74 
 75 #define ABOUT "V4L-Driver for Vision CPiA based cameras"
 76 
 77 #ifndef VID_HARDWARE_CPIA
 78 #define VID_HARDWARE_CPIA 24    /* FIXME -> from linux/videodev.h */
 79 #endif
 80 
 81 #define CPIA_MODULE_CPIA                        (0<<5)
 82 #define CPIA_MODULE_SYSTEM                      (1<<5)
 83 #define CPIA_MODULE_VP_CTRL                     (5<<5)
 84 #define CPIA_MODULE_CAPTURE                     (6<<5)
 85 #define CPIA_MODULE_DEBUG                       (7<<5)
 86 
 87 #define INPUT (DATA_IN << 8)
 88 #define OUTPUT (DATA_OUT << 8)
 89 
 90 #define CPIA_COMMAND_GetCPIAVersion     (INPUT | CPIA_MODULE_CPIA | 1)
 91 #define CPIA_COMMAND_GetPnPID           (INPUT | CPIA_MODULE_CPIA | 2)
 92 #define CPIA_COMMAND_GetCameraStatus    (INPUT | CPIA_MODULE_CPIA | 3)
 93 #define CPIA_COMMAND_GotoHiPower        (OUTPUT | CPIA_MODULE_CPIA | 4)
 94 #define CPIA_COMMAND_GotoLoPower        (OUTPUT | CPIA_MODULE_CPIA | 5)
 95 #define CPIA_COMMAND_GotoSuspend        (OUTPUT | CPIA_MODULE_CPIA | 7)
 96 #define CPIA_COMMAND_GotoPassThrough    (OUTPUT | CPIA_MODULE_CPIA | 8)
 97 #define CPIA_COMMAND_ModifyCameraStatus (OUTPUT | CPIA_MODULE_CPIA | 10)
 98 
 99 #define CPIA_COMMAND_ReadVCRegs         (INPUT | CPIA_MODULE_SYSTEM | 1)
100 #define CPIA_COMMAND_WriteVCReg         (OUTPUT | CPIA_MODULE_SYSTEM | 2)
101 #define CPIA_COMMAND_ReadMCPorts        (INPUT | CPIA_MODULE_SYSTEM | 3)
102 #define CPIA_COMMAND_WriteMCPort        (OUTPUT | CPIA_MODULE_SYSTEM | 4)
103 #define CPIA_COMMAND_SetBaudRate        (OUTPUT | CPIA_MODULE_SYSTEM | 5)
104 #define CPIA_COMMAND_SetECPTiming       (OUTPUT | CPIA_MODULE_SYSTEM | 6)
105 #define CPIA_COMMAND_ReadIDATA          (INPUT | CPIA_MODULE_SYSTEM | 7)
106 #define CPIA_COMMAND_WriteIDATA         (OUTPUT | CPIA_MODULE_SYSTEM | 8)
107 #define CPIA_COMMAND_GenericCall        (OUTPUT | CPIA_MODULE_SYSTEM | 9)
108 #define CPIA_COMMAND_I2CStart           (OUTPUT | CPIA_MODULE_SYSTEM | 10)
109 #define CPIA_COMMAND_I2CStop            (OUTPUT | CPIA_MODULE_SYSTEM | 11)
110 #define CPIA_COMMAND_I2CWrite           (OUTPUT | CPIA_MODULE_SYSTEM | 12)
111 #define CPIA_COMMAND_I2CRead            (INPUT | CPIA_MODULE_SYSTEM | 13)
112 
113 #define CPIA_COMMAND_GetVPVersion       (INPUT | CPIA_MODULE_VP_CTRL | 1)
114 #define CPIA_COMMAND_ResetFrameCounter  (INPUT | CPIA_MODULE_VP_CTRL | 2)
115 #define CPIA_COMMAND_SetColourParams    (OUTPUT | CPIA_MODULE_VP_CTRL | 3)
116 #define CPIA_COMMAND_SetExposure        (OUTPUT | CPIA_MODULE_VP_CTRL | 4)
117 #define CPIA_COMMAND_SetColourBalance   (OUTPUT | CPIA_MODULE_VP_CTRL | 6)
118 #define CPIA_COMMAND_SetSensorFPS       (OUTPUT | CPIA_MODULE_VP_CTRL | 7)
119 #define CPIA_COMMAND_SetVPDefaults      (OUTPUT | CPIA_MODULE_VP_CTRL | 8)
120 #define CPIA_COMMAND_SetApcor           (OUTPUT | CPIA_MODULE_VP_CTRL | 9)
121 #define CPIA_COMMAND_SetFlickerCtrl     (OUTPUT | CPIA_MODULE_VP_CTRL | 10)
122 #define CPIA_COMMAND_SetVLOffset        (OUTPUT | CPIA_MODULE_VP_CTRL | 11)
123 #define CPIA_COMMAND_GetColourParams    (INPUT | CPIA_MODULE_VP_CTRL | 16)
124 #define CPIA_COMMAND_GetColourBalance   (INPUT | CPIA_MODULE_VP_CTRL | 17)
125 #define CPIA_COMMAND_GetExposure        (INPUT | CPIA_MODULE_VP_CTRL | 18)
126 #define CPIA_COMMAND_SetSensorMatrix    (OUTPUT | CPIA_MODULE_VP_CTRL | 19)
127 #define CPIA_COMMAND_ColourBars         (OUTPUT | CPIA_MODULE_VP_CTRL | 25)
128 #define CPIA_COMMAND_ReadVPRegs         (INPUT | CPIA_MODULE_VP_CTRL | 30)
129 #define CPIA_COMMAND_WriteVPReg         (OUTPUT | CPIA_MODULE_VP_CTRL | 31)
130 
131 #define CPIA_COMMAND_GrabFrame          (OUTPUT | CPIA_MODULE_CAPTURE | 1)
132 #define CPIA_COMMAND_UploadFrame        (OUTPUT | CPIA_MODULE_CAPTURE | 2)
133 #define CPIA_COMMAND_SetGrabMode        (OUTPUT | CPIA_MODULE_CAPTURE | 3)
134 #define CPIA_COMMAND_InitStreamCap      (OUTPUT | CPIA_MODULE_CAPTURE | 4)
135 #define CPIA_COMMAND_FiniStreamCap      (OUTPUT | CPIA_MODULE_CAPTURE | 5)
136 #define CPIA_COMMAND_StartStreamCap     (OUTPUT | CPIA_MODULE_CAPTURE | 6)
137 #define CPIA_COMMAND_EndStreamCap       (OUTPUT | CPIA_MODULE_CAPTURE | 7)
138 #define CPIA_COMMAND_SetFormat          (OUTPUT | CPIA_MODULE_CAPTURE | 8)
139 #define CPIA_COMMAND_SetROI             (OUTPUT | CPIA_MODULE_CAPTURE | 9)
140 #define CPIA_COMMAND_SetCompression     (OUTPUT | CPIA_MODULE_CAPTURE | 10)
141 #define CPIA_COMMAND_SetCompressionTarget (OUTPUT | CPIA_MODULE_CAPTURE | 11)
142 #define CPIA_COMMAND_SetYUVThresh       (OUTPUT | CPIA_MODULE_CAPTURE | 12)
143 #define CPIA_COMMAND_SetCompressionParams (OUTPUT | CPIA_MODULE_CAPTURE | 13)
144 #define CPIA_COMMAND_DiscardFrame       (OUTPUT | CPIA_MODULE_CAPTURE | 14)
145 #define CPIA_COMMAND_GrabReset          (OUTPUT | CPIA_MODULE_CAPTURE | 15)
146 
147 #define CPIA_COMMAND_OutputRS232        (OUTPUT | CPIA_MODULE_DEBUG | 1)
148 #define CPIA_COMMAND_AbortProcess       (OUTPUT | CPIA_MODULE_DEBUG | 4)
149 #define CPIA_COMMAND_SetDramPage        (OUTPUT | CPIA_MODULE_DEBUG | 5)
150 #define CPIA_COMMAND_StartDramUpload    (OUTPUT | CPIA_MODULE_DEBUG | 6)
151 #define CPIA_COMMAND_StartDummyDtream   (OUTPUT | CPIA_MODULE_DEBUG | 8)
152 #define CPIA_COMMAND_AbortStream        (OUTPUT | CPIA_MODULE_DEBUG | 9)
153 #define CPIA_COMMAND_DownloadDRAM       (OUTPUT | CPIA_MODULE_DEBUG | 10)
154 #define CPIA_COMMAND_Null               (OUTPUT | CPIA_MODULE_DEBUG | 11)
155 
156 enum {
157         FRAME_READY,            /* Ready to grab into */
158         FRAME_GRABBING,         /* In the process of being grabbed into */
159         FRAME_DONE,             /* Finished grabbing, but not been synced yet */
160         FRAME_UNUSED,           /* Unused (no MCAPTURE) */
161 };
162 
163 #define COMMAND_NONE                    0x0000
164 #define COMMAND_SETCOMPRESSION          0x0001
165 #define COMMAND_SETCOMPRESSIONTARGET    0x0002
166 #define COMMAND_SETCOLOURPARAMS         0x0004
167 #define COMMAND_SETFORMAT               0x0008
168 #define COMMAND_PAUSE                   0x0010
169 #define COMMAND_RESUME                  0x0020
170 #define COMMAND_SETYUVTHRESH            0x0040
171 #define COMMAND_SETECPTIMING            0x0080
172 #define COMMAND_SETCOMPRESSIONPARAMS    0x0100
173 #define COMMAND_SETEXPOSURE             0x0200
174 #define COMMAND_SETCOLOURBALANCE        0x0400
175 #define COMMAND_SETSENSORFPS            0x0800
176 #define COMMAND_SETAPCOR                0x1000
177 #define COMMAND_SETFLICKERCTRL          0x2000
178 #define COMMAND_SETVLOFFSET             0x4000
179 #define COMMAND_SETLIGHTS               0x8000
180 
181 #define ROUND_UP_EXP_FOR_FLICKER 15
182 
183 /* Constants for automatic frame rate adjustment */
184 #define MAX_EXP       302
185 #define MAX_EXP_102   255
186 #define LOW_EXP       140
187 #define VERY_LOW_EXP   70
188 #define TC             94
189 #define EXP_ACC_DARK   50
190 #define EXP_ACC_LIGHT  90
191 #define HIGH_COMP_102 160
192 #define MAX_COMP      239
193 #define DARK_TIME       3
194 #define LIGHT_TIME      3
195 
196 /* Maximum number of 10ms loops to wait for the stream to become ready */
197 #define READY_TIMEOUT 100
198 
199 /* Developer's Guide Table 5 p 3-34
200  * indexed by [mains][sensorFps.baserate][sensorFps.divisor]*/
201 static u8 flicker_jumps[2][2][4] =
202 { { { 76, 38, 19, 9 }, { 92, 46, 23, 11 } },
203   { { 64, 32, 16, 8 }, { 76, 38, 19, 9} }
204 };
205 
206 /* forward declaration of local function */
207 static void reset_camera_struct(struct cam_data *cam);
208 static int find_over_exposure(int brightness);
209 static void set_flicker(struct cam_params *params, volatile u32 *command_flags,
210                         int on);
211 
212 
213 /**********************************************************************
214  *
215  * Memory management
216  *
217  **********************************************************************/
218 static void *rvmalloc(unsigned long size)
219 {
220         void *mem;
221         unsigned long adr;
222 
223         size = PAGE_ALIGN(size);
224         mem = vmalloc_32(size);
225         if (!mem)
226                 return NULL;
227 
228         memset(mem, 0, size); /* Clear the ram out, no junk to the user */
229         adr = (unsigned long) mem;
230         while (size > 0) {
231                 SetPageReserved(vmalloc_to_page((void *)adr));
232                 adr += PAGE_SIZE;
233                 size -= PAGE_SIZE;
234         }
235 
236         return mem;
237 }
238 
239 static void rvfree(void *mem, unsigned long size)
240 {
241         unsigned long adr;
242 
243         if (!mem)
244                 return;
245 
246         adr = (unsigned long) mem;
247         while ((long) size > 0) {
248                 ClearPageReserved(vmalloc_to_page((void *)adr));
249                 adr += PAGE_SIZE;
250                 size -= PAGE_SIZE;
251         }
252         vfree(mem);
253 }
254 
255 /**********************************************************************
256  *
257  * /proc interface
258  *
259  **********************************************************************/
260 #ifdef CONFIG_PROC_FS
261 static struct proc_dir_entry *cpia_proc_root=NULL;
262 
263 static int cpia_read_proc(char *page, char **start, off_t off,
264                           int count, int *eof, void *data)
265 {
266         char *out = page;
267         int len, tmp;
268         struct cam_data *cam = data;
269         char tmpstr[29];
270 
271         /* IMPORTANT: This output MUST be kept under PAGE_SIZE
272          *            or we need to get more sophisticated. */
273 
274         out += sprintf(out, "read-only\n-----------------------\n");
275         out += sprintf(out, "V4L Driver version:       %d.%d.%d\n",
276                        CPIA_MAJ_VER, CPIA_MIN_VER, CPIA_PATCH_VER);
277         out += sprintf(out, "CPIA Version:             %d.%02d (%d.%d)\n",
278                        cam->params.version.firmwareVersion,
279                        cam->params.version.firmwareRevision,
280                        cam->params.version.vcVersion,
281                        cam->params.version.vcRevision);
282         out += sprintf(out, "CPIA PnP-ID:              %04x:%04x:%04x\n",
283                        cam->params.pnpID.vendor, cam->params.pnpID.product,
284                        cam->params.pnpID.deviceRevision);
285         out += sprintf(out, "VP-Version:               %d.%d %04x\n",
286                        cam->params.vpVersion.vpVersion,
287                        cam->params.vpVersion.vpRevision,
288                        cam->params.vpVersion.cameraHeadID);
289 
290         out += sprintf(out, "system_state:             %#04x\n",
291                        cam->params.status.systemState);
292         out += sprintf(out, "grab_state:               %#04x\n",
293                        cam->params.status.grabState);
294         out += sprintf(out, "stream_state:             %#04x\n",
295                        cam->params.status.streamState);
296         out += sprintf(out, "fatal_error:              %#04x\n",
297                        cam->params.status.fatalError);
298         out += sprintf(out, "cmd_error:                %#04x\n",
299                        cam->params.status.cmdError);
300         out += sprintf(out, "debug_flags:              %#04x\n",
301                        cam->params.status.debugFlags);
302         out += sprintf(out, "vp_status:                %#04x\n",
303                        cam->params.status.vpStatus);
304         out += sprintf(out, "error_code:               %#04x\n",
305                        cam->params.status.errorCode);
306         /* QX3 specific entries */
307         if (cam->params.qx3.qx3_detected) {
308                 out += sprintf(out, "button:                   %4d\n",
309                                cam->params.qx3.button);
310                 out += sprintf(out, "cradled:                  %4d\n",
311                                cam->params.qx3.cradled);
312         }
313         out += sprintf(out, "video_size:               %s\n",
314                        cam->params.format.videoSize == VIDEOSIZE_CIF ?
315                        "CIF " : "QCIF");
316         out += sprintf(out, "roi:                      (%3d, %3d) to (%3d, %3d)\n",
317                        cam->params.roi.colStart*8,
318                        cam->params.roi.rowStart*4,
319                        cam->params.roi.colEnd*8,
320                        cam->params.roi.rowEnd*4);
321         out += sprintf(out, "actual_fps:               %3d\n", cam->fps);
322         out += sprintf(out, "transfer_rate:            %4dkB/s\n",
323                        cam->transfer_rate);
324 
325         out += sprintf(out, "\nread-write\n");
326         out += sprintf(out, "-----------------------  current       min"
327                        "       max   default  comment\n");
328         out += sprintf(out, "brightness:             %8d  %8d  %8d  %8d\n",
329                        cam->params.colourParams.brightness, 0, 100, 50);
330         if (cam->params.version.firmwareVersion == 1 &&
331            cam->params.version.firmwareRevision == 2)
332                 /* 1-02 firmware limits contrast to 80 */
333                 tmp = 80;
334         else
335                 tmp = 96;
336 
337         out += sprintf(out, "contrast:               %8d  %8d  %8d  %8d"
338                        "  steps of 8\n",
339                        cam->params.colourParams.contrast, 0, tmp, 48);
340         out += sprintf(out, "saturation:             %8d  %8d  %8d  %8d\n",
341                        cam->params.colourParams.saturation, 0, 100, 50);
342         tmp = (25000+5000*cam->params.sensorFps.baserate)/
343               (1<<cam->params.sensorFps.divisor);
344         out += sprintf(out, "sensor_fps:             %4d.%03d  %8d  %8d  %8d\n",
345                        tmp/1000, tmp%1000, 3, 30, 15);
346         out += sprintf(out, "stream_start_line:      %8d  %8d  %8d  %8d\n",
347                        2*cam->params.streamStartLine, 0,
348                        cam->params.format.videoSize == VIDEOSIZE_CIF ? 288:144,
349                        cam->params.format.videoSize == VIDEOSIZE_CIF ? 240:120);
350         out += sprintf(out, "sub_sample:             %8s  %8s  %8s  %8s\n",
351                        cam->params.format.subSample == SUBSAMPLE_420 ?
352                        "420" : "422", "420", "422", "422");
353         out += sprintf(out, "yuv_order:              %8s  %8s  %8s  %8s\n",
354                        cam->params.format.yuvOrder == YUVORDER_YUYV ?
355                        "YUYV" : "UYVY", "YUYV" , "UYVY", "YUYV");
356         out += sprintf(out, "ecp_timing:             %8s  %8s  %8s  %8s\n",
357                        cam->params.ecpTiming ? "slow" : "normal", "slow",
358                        "normal", "normal");
359 
360         if (cam->params.colourBalance.balanceMode == 2) {
361                 sprintf(tmpstr, "auto");
362         } else {
363                 sprintf(tmpstr, "manual");
364         }
365         out += sprintf(out, "color_balance_mode:     %8s  %8s  %8s"
366                        "  %8s\n",  tmpstr, "manual", "auto", "auto");
367         out += sprintf(out, "red_gain:               %8d  %8d  %8d  %8d\n",
368                        cam->params.colourBalance.redGain, 0, 212, 32);
369         out += sprintf(out, "green_gain:             %8d  %8d  %8d  %8d\n",
370                        cam->params.colourBalance.greenGain, 0, 212, 6);
371         out += sprintf(out, "blue_gain:              %8d  %8d  %8d  %8d\n",
372                        cam->params.colourBalance.blueGain, 0, 212, 92);
373 
374         if (cam->params.version.firmwareVersion == 1 &&
375            cam->params.version.firmwareRevision == 2)
376                 /* 1-02 firmware limits gain to 2 */
377                 sprintf(tmpstr, "%8d  %8d  %8d", 1, 2, 2);
378         else
379                 sprintf(tmpstr, "%8d  %8d  %8d", 1, 8, 2);
380 
381         if (cam->params.exposure.gainMode == 0)
382                 out += sprintf(out, "max_gain:                unknown  %28s"
383                                "  powers of 2\n", tmpstr);
384         else
385                 out += sprintf(out, "max_gain:               %8d  %28s"
386                                "  1,2,4 or 8 \n",
387                                1<<(cam->params.exposure.gainMode-1), tmpstr);
388 
389         switch(cam->params.exposure.expMode) {
390         case 1:
391         case 3:
392                 sprintf(tmpstr, "manual");
393                 break;
394         case 2:
395                 sprintf(tmpstr, "auto");
396                 break;
397         default:
398                 sprintf(tmpstr, "unknown");
399                 break;
400         }
401         out += sprintf(out, "exposure_mode:          %8s  %8s  %8s"
402                        "  %8s\n",  tmpstr, "manual", "auto", "auto");
403         out += sprintf(out, "centre_weight:          %8s  %8s  %8s  %8s\n",
404                        (2-cam->params.exposure.centreWeight) ? "on" : "off",
405                        "off", "on", "on");
406         out += sprintf(out, "gain:                   %8d  %8d  max_gain  %8d  1,2,4,8 possible\n",
407                        1<<cam->params.exposure.gain, 1, 1);
408         if (cam->params.version.firmwareVersion == 1 &&
409            cam->params.version.firmwareRevision == 2)
410                 /* 1-02 firmware limits fineExp/2 to 127 */
411                 tmp = 254;
412         else
413                 tmp = 510;
414 
415         out += sprintf(out, "fine_exp:               %8d  %8d  %8d  %8d\n",
416                        cam->params.exposure.fineExp*2, 0, tmp, 0);
417         if (cam->params.version.firmwareVersion == 1 &&
418            cam->params.version.firmwareRevision == 2)
419                 /* 1-02 firmware limits coarseExpHi to 0 */
420                 tmp = MAX_EXP_102;
421         else
422                 tmp = MAX_EXP;
423 
424         out += sprintf(out, "coarse_exp:             %8d  %8d  %8d"
425                        "  %8d\n", cam->params.exposure.coarseExpLo+
426                        256*cam->params.exposure.coarseExpHi, 0, tmp, 185);
427         out += sprintf(out, "red_comp:               %8d  %8d  %8d  %8d\n",
428                        cam->params.exposure.redComp, COMP_RED, 255, COMP_RED);
429         out += sprintf(out, "green1_comp:            %8d  %8d  %8d  %8d\n",
430                        cam->params.exposure.green1Comp, COMP_GREEN1, 255,
431                        COMP_GREEN1);
432         out += sprintf(out, "green2_comp:            %8d  %8d  %8d  %8d\n",
433                        cam->params.exposure.green2Comp, COMP_GREEN2, 255,
434                        COMP_GREEN2);
435         out += sprintf(out, "blue_comp:              %8d  %8d  %8d  %8d\n",
436                        cam->params.exposure.blueComp, COMP_BLUE, 255, COMP_BLUE);
437 
438         out += sprintf(out, "apcor_gain1:            %#8x  %#8x  %#8x  %#8x\n",
439                        cam->params.apcor.gain1, 0, 0xff, 0x1c);
440         out += sprintf(out, "apcor_gain2:            %#8x  %#8x  %#8x  %#8x\n",
441                        cam->params.apcor.gain2, 0, 0xff, 0x1a);
442         out += sprintf(out, "apcor_gain4:            %#8x  %#8x  %#8x  %#8x\n",
443                        cam->params.apcor.gain4, 0, 0xff, 0x2d);
444         out += sprintf(out, "apcor_gain8:            %#8x  %#8x  %#8x  %#8x\n",
445                        cam->params.apcor.gain8, 0, 0xff, 0x2a);
446         out += sprintf(out, "vl_offset_gain1:        %8d  %8d  %8d  %8d\n",
447                        cam->params.vlOffset.gain1, 0, 255, 24);
448         out += sprintf(out, "vl_offset_gain2:        %8d  %8d  %8d  %8d\n",
449                        cam->params.vlOffset.gain2, 0, 255, 28);
450         out += sprintf(out, "vl_offset_gain4:        %8d  %8d  %8d  %8d\n",
451                        cam->params.vlOffset.gain4, 0, 255, 30);
452         out += sprintf(out, "vl_offset_gain8:        %8d  %8d  %8d  %8d\n",
453                        cam->params.vlOffset.gain8, 0, 255, 30);
454         out += sprintf(out, "flicker_control:        %8s  %8s  %8s  %8s\n",
455                        cam->params.flickerControl.flickerMode ? "on" : "off",
456                        "off", "on", "off");
457         out += sprintf(out, "mains_frequency:        %8d  %8d  %8d  %8d"
458                        " only 50/60\n",
459                        cam->mainsFreq ? 60 : 50, 50, 60, 50);
460         if(cam->params.flickerControl.allowableOverExposure < 0)
461                 out += sprintf(out, "allowable_overexposure: %4dauto      auto  %8d      auto\n",
462                                -cam->params.flickerControl.allowableOverExposure,
463                                255);
464         else
465                 out += sprintf(out, "allowable_overexposure: %8d      auto  %8d      auto\n",
466                                cam->params.flickerControl.allowableOverExposure,
467                                255);
468         out += sprintf(out, "compression_mode:       ");
469         switch(cam->params.compression.mode) {
470         case CPIA_COMPRESSION_NONE:
471                 out += sprintf(out, "%8s", "none");
472                 break;
473         case CPIA_COMPRESSION_AUTO:
474                 out += sprintf(out, "%8s", "auto");
475                 break;
476         case CPIA_COMPRESSION_MANUAL:
477                 out += sprintf(out, "%8s", "manual");
478                 break;
479         default:
480                 out += sprintf(out, "%8s", "unknown");
481                 break;
482         }
483         out += sprintf(out, "    none,auto,manual      auto\n");
484         out += sprintf(out, "decimation_enable:      %8s  %8s  %8s  %8s\n",
485                        cam->params.compression.decimation ==
486                        DECIMATION_ENAB ? "on":"off", "off", "on",
487                        "off");
488         out += sprintf(out, "compression_target:    %9s %9s %9s %9s\n",
489                        cam->params.compressionTarget.frTargeting  ==
490                        CPIA_COMPRESSION_TARGET_FRAMERATE ?
491                        "framerate":"quality",
492                        "framerate", "quality", "quality");
493         out += sprintf(out, "target_framerate:       %8d  %8d  %8d  %8d\n",
494                        cam->params.compressionTarget.targetFR, 1, 30, 15);
495         out += sprintf(out, "target_quality:         %8d  %8d  %8d  %8d\n",
496                        cam->params.compressionTarget.targetQ, 1, 64, 5);
497         out += sprintf(out, "y_threshold:            %8d  %8d  %8d  %8d\n",
498                        cam->params.yuvThreshold.yThreshold, 0, 31, 6);
499         out += sprintf(out, "uv_threshold:           %8d  %8d  %8d  %8d\n",
500                        cam->params.yuvThreshold.uvThreshold, 0, 31, 6);
501         out += sprintf(out, "hysteresis:             %8d  %8d  %8d  %8d\n",
502                        cam->params.compressionParams.hysteresis, 0, 255, 3);
503         out += sprintf(out, "threshold_max:          %8d  %8d  %8d  %8d\n",
504                        cam->params.compressionParams.threshMax, 0, 255, 11);
505         out += sprintf(out, "small_step:             %8d  %8d  %8d  %8d\n",
506                        cam->params.compressionParams.smallStep, 0, 255, 1);
507         out += sprintf(out, "large_step:             %8d  %8d  %8d  %8d\n",
508                        cam->params.compressionParams.largeStep, 0, 255, 3);
509         out += sprintf(out, "decimation_hysteresis:  %8d  %8d  %8d  %8d\n",
510                        cam->params.compressionParams.decimationHysteresis,
511                        0, 255, 2);
512         out += sprintf(out, "fr_diff_step_thresh:    %8d  %8d  %8d  %8d\n",
513                        cam->params.compressionParams.frDiffStepThresh,
514                        0, 255, 5);
515         out += sprintf(out, "q_diff_step_thresh:     %8d  %8d  %8d  %8d\n",
516                        cam->params.compressionParams.qDiffStepThresh,
517                        0, 255, 3);
518         out += sprintf(out, "decimation_thresh_mod:  %8d  %8d  %8d  %8d\n",
519                        cam->params.compressionParams.decimationThreshMod,
520                        0, 255, 2);
521         /* QX3 specific entries */
522         if (cam->params.qx3.qx3_detected) {
523                 out += sprintf(out, "toplight:               %8s  %8s  %8s  %8s\n",
524                                cam->params.qx3.toplight ? "on" : "off",
525                                "off", "on", "off");
526                 out += sprintf(out, "bottomlight:            %8s  %8s  %8s  %8s\n",
527                                cam->params.qx3.bottomlight ? "on" : "off",
528                                "off", "on", "off");
529         }
530 
531         len = out - page;
532         len -= off;
533         if (len < count) {
534                 *eof = 1;
535                 if (len <= 0) return 0;
536         } else
537                 len = count;
538 
539         *start = page + off;
540         return len;
541 }
542 
543 
544 static int match(char *checkstr, char **buffer, unsigned long *count,
545                  int *find_colon, int *err)
546 {
547         int ret, colon_found = 1;
548         int len = strlen(checkstr);
549         ret = (len <= *count && strncmp(*buffer, checkstr, len) == 0);
550         if (ret) {
551                 *buffer += len;
552                 *count -= len;
553                 if (*find_colon) {
554                         colon_found = 0;
555                         while (*count && (**buffer == ' ' || **buffer == '\t' ||
556                                           (!colon_found && **buffer == ':'))) {
557                                 if (**buffer == ':')
558                                         colon_found = 1;
559                                 --*count;
560                                 ++*buffer;
561                         }
562                         if (!*count || !colon_found)
563                                 *err = -EINVAL;
564                         *find_colon = 0;
565                 }
566         }
567         return ret;
568 }
569 
570 static unsigned long int value(char **buffer, unsigned long *count, int *err)
571 {
572         char *p;
573         unsigned long int ret;
574         ret = simple_strtoul(*buffer, &p, 0);
575         if (p == *buffer)
576                 *err = -EINVAL;
577         else {
578                 *count -= p - *buffer;
579                 *buffer = p;
580         }
581         return ret;
582 }
583 
584 static int cpia_write_proc(struct file *file, const char __user *buf,
585                            unsigned long count, void *data)
586 {
587         struct cam_data *cam = data;
588         struct cam_params new_params;
589         char *page, *buffer;
590         int retval, find_colon;
591         int size = count;
592         unsigned long val = 0;
593         u32 command_flags = 0;
594         u8 new_mains;
595 
596         /*
597          * This code to copy from buf to page is shamelessly copied
598          * from the comx driver
599          */
600         if (count > PAGE_SIZE) {
601                 printk(KERN_ERR "count is %lu > %d!!!\n", count, (int)PAGE_SIZE);
602                 return -ENOSPC;
603         }
604 
605         if (!(page = (char *)__get_free_page(GFP_KERNEL))) return -ENOMEM;
606 
607         if(copy_from_user(page, buf, count))
608         {
609                 retval = -EFAULT;
610                 goto out;
611         }
612 
613         if (page[count-1] == '\n')
614                 page[count-1] = '\0';
615         else if (count < PAGE_SIZE)
616                 page[count] = '\0';
617         else if (page[count]) {
618                 retval = -EINVAL;
619                 goto out;
620         }
621 
622         buffer = page;
623 
624         if (mutex_lock_interruptible(&cam->param_lock))
625                 return -ERESTARTSYS;
626 
627         /*
628          * Skip over leading whitespace
629          */
630         while (count && isspace(*buffer)) {
631                 --count;
632                 ++buffer;
633         }
634 
635         memcpy(&new_params, &cam->params, sizeof(struct cam_params));
636         new_mains = cam->mainsFreq;
637 
638 #define MATCH(x) (match(x, &buffer, &count, &find_colon, &retval))
639 #define VALUE (value(&buffer,&count, &retval))
640 #define FIRMWARE_VERSION(x,y) (new_params.version.firmwareVersion == (x) && \
641                                new_params.version.firmwareRevision == (y))
642 
643         retval = 0;
644         while (count && !retval) {
645                 find_colon = 1;
646                 if (MATCH("brightness")) {
647                         if (!retval)
648                                 val = VALUE;
649 
650                         if (!retval) {
651                                 if (val <= 100)
652                                         new_params.colourParams.brightness = val;
653                                 else
654                                         retval = -EINVAL;
655                         }
656                         command_flags |= COMMAND_SETCOLOURPARAMS;
657                         if(new_params.flickerControl.allowableOverExposure < 0)
658                                 new_params.flickerControl.allowableOverExposure =
659                                         -find_over_exposure(new_params.colourParams.brightness);
660                         if(new_params.flickerControl.flickerMode != 0)
661                                 command_flags |= COMMAND_SETFLICKERCTRL;
662 
663                 } else if (MATCH("contrast")) {
664                         if (!retval)
665                                 val = VALUE;
666 
667                         if (!retval) {
668                                 if (val <= 100) {
669                                         /* contrast is in steps of 8, so round*/
670                                         val = ((val + 3) / 8) * 8;
671                                         /* 1-02 firmware limits contrast to 80*/
672                                         if (FIRMWARE_VERSION(1,2) && val > 80)
673                                                 val = 80;
674 
675                                         new_params.colourParams.contrast = val;
676                                 } else
677                                         retval = -EINVAL;
678                         }
679                         command_flags |= COMMAND_SETCOLOURPARAMS;
680                 } else if (MATCH("saturation")) {
681                         if (!retval)
682                                 val = VALUE;
683 
684                         if (!retval) {
685                                 if (val <= 100)
686                                         new_params.colourParams.saturation = val;
687                                 else
688                                         retval = -EINVAL;
689                         }
690                         command_flags |= COMMAND_SETCOLOURPARAMS;
691                 } else if (MATCH("sensor_fps")) {
692                         if (!retval)
693                                 val = VALUE;
694 
695                         if (!retval) {
696                                 /* find values so that sensorFPS is minimized,
697                                  * but >= val */
698                                 if (val > 30)
699                                         retval = -EINVAL;
700                                 else if (val > 25) {
701                                         new_params.sensorFps.divisor = 0;
702                                         new_params.sensorFps.baserate = 1;
703                                 } else if (val > 15) {
704                                         new_params.sensorFps.divisor = 0;
705                                         new_params.sensorFps.baserate = 0;
706                                 } else if (val > 12) {
707                                         new_params.sensorFps.divisor = 1;
708                                         new_params.sensorFps.baserate = 1;
709                                 } else if (val > 7) {
710                                         new_params.sensorFps.divisor = 1;
711                                         new_params.sensorFps.baserate = 0;
712                                 } else if (val > 6) {
713                                         new_params.sensorFps.divisor = 2;
714                                         new_params.sensorFps.baserate = 1;
715                                 } else if (val > 3) {
716                                         new_params.sensorFps.divisor = 2;
717                                         new_params.sensorFps.baserate = 0;
718                                 } else {
719                                         new_params.sensorFps.divisor = 3;
720                                         /* Either base rate would work here */
721                                         new_params.sensorFps.baserate = 1;
722                                 }
723                                 new_params.flickerControl.coarseJump =
724                                         flicker_jumps[new_mains]
725                                         [new_params.sensorFps.baserate]
726                                         [new_params.sensorFps.divisor];
727                                 if (new_params.flickerControl.flickerMode)
728                                         command_flags |= COMMAND_SETFLICKERCTRL;
729                         }
730                         command_flags |= COMMAND_SETSENSORFPS;
731                         cam->exposure_status = EXPOSURE_NORMAL;
732                 } else if (MATCH("stream_start_line")) {
733                         if (!retval)
734                                 val = VALUE;
735 
736                         if (!retval) {
737                                 int max_line = 288;
738 
739                                 if (new_params.format.videoSize == VIDEOSIZE_QCIF)
740                                         max_line = 144;
741                                 if (val <= max_line)
742                                         new_params.streamStartLine = val/2;
743                                 else
744                                         retval = -EINVAL;
745                         }
746                 } else if (MATCH("sub_sample")) {
747                         if (!retval && MATCH("420"))
748                                 new_params.format.subSample = SUBSAMPLE_420;
749                         else if (!retval && MATCH("422"))
750                                 new_params.format.subSample = SUBSAMPLE_422;
751                         else
752                                 retval = -EINVAL;
753 
754                         command_flags |= COMMAND_SETFORMAT;
755                 } else if (MATCH("yuv_order")) {
756                         if (!retval && MATCH("YUYV"))
757                                 new_params.format.yuvOrder = YUVORDER_YUYV;
758                         else if (!retval && MATCH("UYVY"))
759                                 new_params.format.yuvOrder = YUVORDER_UYVY;
760                         else
761                                 retval = -EINVAL;
762 
763                         command_flags |= COMMAND_SETFORMAT;
764                 } else if (MATCH("ecp_timing")) {
765                         if (!retval && MATCH("normal"))
766                                 new_params.ecpTiming = 0;
767                         else if (!retval && MATCH("slow"))
768                                 new_params.ecpTiming = 1;
769                         else
770                                 retval = -EINVAL;
771 
772                         command_flags |= COMMAND_SETECPTIMING;
773                 } else if (MATCH("color_balance_mode")) {
774                         if (!retval && MATCH("manual"))
775                                 new_params.colourBalance.balanceMode = 3;
776                         else if (!retval && MATCH("auto"))
777                                 new_params.colourBalance.balanceMode = 2;
778                         else
779                                 retval = -EINVAL;
780 
781                         command_flags |= COMMAND_SETCOLOURBALANCE;
782                 } else if (MATCH("red_gain")) {
783                         if (!retval)
784                                 val = VALUE;
785 
786                         if (!retval) {
787                                 if (val <= 212) {
788                                         new_params.colourBalance.redGain = val;
789                                         new_params.colourBalance.balanceMode = 1;
790                                 } else
791                                         retval = -EINVAL;
792                         }
793                         command_flags |= COMMAND_SETCOLOURBALANCE;
794                 } else if (MATCH("green_gain")) {
795                         if (!retval)
796                                 val = VALUE;
797 
798                         if (!retval) {
799                                 if (val <= 212) {
800                                         new_params.colourBalance.greenGain = val;
801                                         new_params.colourBalance.balanceMode = 1;
802                                 } else
803                                         retval = -EINVAL;
804                         }
805                         command_flags |= COMMAND_SETCOLOURBALANCE;
806                 } else if (MATCH("blue_gain")) {
807                         if (!retval)
808                                 val = VALUE;
809 
810                         if (!retval) {
811                                 if (val <= 212) {
812                                         new_params.colourBalance.blueGain = val;
813                                         new_params.colourBalance.balanceMode = 1;
814                                 } else
815                                         retval = -EINVAL;
816                         }
817                         command_flags |= COMMAND_SETCOLOURBALANCE;
818                 } else if (MATCH("max_gain")) {
819                         if (!retval)
820                                 val = VALUE;
821 
822                         if (!retval) {
823                                 /* 1-02 firmware limits gain to 2 */
824                                 if (FIRMWARE_VERSION(1,2) && val > 2)
825                                         val = 2;