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;