4 * Supports CPiA based Video Camera's.
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
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.
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.
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.
26 /* define _CPIA_DEBUG_ for verbose debug output (see cpia.h) */
27 /* #define _CPIA_DEBUG_ 1 */
29 #include <linux/config.h>
31 #include <linux/module.h>
32 #include <linux/moduleparam.h>
33 #include <linux/init.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>
42 #include <asm/semaphore.h>
45 #include <linux/kmod.h>
50 #ifdef CONFIG_VIDEO_CPIA_PP
51 extern int cpia_pp_init(void);
53 #ifdef CONFIG_VIDEO_CPIA_USB
54 extern int cpia_usb_init(void);
57 static int video_nr = -1;
60 module_param(video_nr, int, 0);
61 MODULE_AUTHOR("Scott J. Bertin <sbertin@securenym.net> & Peter Pregler <Peter_Pregler@email.com> & Johannes Erdfelt <johannes@erdfeld.com>");
62 MODULE_DESCRIPTION("V4L-driver for Vision CPiA based cameras");
63 MODULE_LICENSE("GPL");
64 MODULE_SUPPORTED_DEVICE("video");
67 static unsigned short colorspace_conv = 0;
68 module_param(colorspace_conv, ushort, 0444);
69 MODULE_PARM_DESC(colorspace_conv,
70 "\n<n> Colorspace conversion:"
73 "\nDefault value is 0"
76 #define ABOUT "V4L-Driver for Vision CPiA based cameras"
78 #ifndef VID_HARDWARE_CPIA
79 #define VID_HARDWARE_CPIA 24 /* FIXME -> from linux/videodev.h */
82 #define CPIA_MODULE_CPIA (0<<5)
83 #define CPIA_MODULE_SYSTEM (1<<5)
84 #define CPIA_MODULE_VP_CTRL (5<<5)
85 #define CPIA_MODULE_CAPTURE (6<<5)
86 #define CPIA_MODULE_DEBUG (7<<5)
88 #define INPUT (DATA_IN << 8)
89 #define OUTPUT (DATA_OUT << 8)
91 #define CPIA_COMMAND_GetCPIAVersion (INPUT | CPIA_MODULE_CPIA | 1)
92 #define CPIA_COMMAND_GetPnPID (INPUT | CPIA_MODULE_CPIA | 2)
93 #define CPIA_COMMAND_GetCameraStatus (INPUT | CPIA_MODULE_CPIA | 3)
94 #define CPIA_COMMAND_GotoHiPower (OUTPUT | CPIA_MODULE_CPIA | 4)
95 #define CPIA_COMMAND_GotoLoPower (OUTPUT | CPIA_MODULE_CPIA | 5)
96 #define CPIA_COMMAND_GotoSuspend (OUTPUT | CPIA_MODULE_CPIA | 7)
97 #define CPIA_COMMAND_GotoPassThrough (OUTPUT | CPIA_MODULE_CPIA | 8)
98 #define CPIA_COMMAND_ModifyCameraStatus (OUTPUT | CPIA_MODULE_CPIA | 10)
100 #define CPIA_COMMAND_ReadVCRegs (INPUT | CPIA_MODULE_SYSTEM | 1)
101 #define CPIA_COMMAND_WriteVCReg (OUTPUT | CPIA_MODULE_SYSTEM | 2)
102 #define CPIA_COMMAND_ReadMCPorts (INPUT | CPIA_MODULE_SYSTEM | 3)
103 #define CPIA_COMMAND_WriteMCPort (OUTPUT | CPIA_MODULE_SYSTEM | 4)
104 #define CPIA_COMMAND_SetBaudRate (OUTPUT | CPIA_MODULE_SYSTEM | 5)
105 #define CPIA_COMMAND_SetECPTiming (OUTPUT | CPIA_MODULE_SYSTEM | 6)
106 #define CPIA_COMMAND_ReadIDATA (INPUT | CPIA_MODULE_SYSTEM | 7)
107 #define CPIA_COMMAND_WriteIDATA (OUTPUT | CPIA_MODULE_SYSTEM | 8)
108 #define CPIA_COMMAND_GenericCall (OUTPUT | CPIA_MODULE_SYSTEM | 9)
109 #define CPIA_COMMAND_I2CStart (OUTPUT | CPIA_MODULE_SYSTEM | 10)
110 #define CPIA_COMMAND_I2CStop (OUTPUT | CPIA_MODULE_SYSTEM | 11)
111 #define CPIA_COMMAND_I2CWrite (OUTPUT | CPIA_MODULE_SYSTEM | 12)
112 #define CPIA_COMMAND_I2CRead (INPUT | CPIA_MODULE_SYSTEM | 13)
114 #define CPIA_COMMAND_GetVPVersion (INPUT | CPIA_MODULE_VP_CTRL | 1)
115 #define CPIA_COMMAND_ResetFrameCounter (INPUT | CPIA_MODULE_VP_CTRL | 2)
116 #define CPIA_COMMAND_SetColourParams (OUTPUT | CPIA_MODULE_VP_CTRL | 3)
117 #define CPIA_COMMAND_SetExposure (OUTPUT | CPIA_MODULE_VP_CTRL | 4)
118 #define CPIA_COMMAND_SetColourBalance (OUTPUT | CPIA_MODULE_VP_CTRL | 6)
119 #define CPIA_COMMAND_SetSensorFPS (OUTPUT | CPIA_MODULE_VP_CTRL | 7)
120 #define CPIA_COMMAND_SetVPDefaults (OUTPUT | CPIA_MODULE_VP_CTRL | 8)
121 #define CPIA_COMMAND_SetApcor (OUTPUT | CPIA_MODULE_VP_CTRL | 9)
122 #define CPIA_COMMAND_SetFlickerCtrl (OUTPUT | CPIA_MODULE_VP_CTRL | 10)
123 #define CPIA_COMMAND_SetVLOffset (OUTPUT | CPIA_MODULE_VP_CTRL | 11)
124 #define CPIA_COMMAND_GetColourParams (INPUT | CPIA_MODULE_VP_CTRL | 16)
125 #define CPIA_COMMAND_GetColourBalance (INPUT | CPIA_MODULE_VP_CTRL | 17)
126 #define CPIA_COMMAND_GetExposure (INPUT | CPIA_MODULE_VP_CTRL | 18)
127 #define CPIA_COMMAND_SetSensorMatrix (OUTPUT | CPIA_MODULE_VP_CTRL | 19)
128 #define CPIA_COMMAND_ColourBars (OUTPUT | CPIA_MODULE_VP_CTRL | 25)
129 #define CPIA_COMMAND_ReadVPRegs (INPUT | CPIA_MODULE_VP_CTRL | 30)
130 #define CPIA_COMMAND_WriteVPReg (OUTPUT | CPIA_MODULE_VP_CTRL | 31)
132 #define CPIA_COMMAND_GrabFrame (OUTPUT | CPIA_MODULE_CAPTURE | 1)
133 #define CPIA_COMMAND_UploadFrame (OUTPUT | CPIA_MODULE_CAPTURE | 2)
134 #define CPIA_COMMAND_SetGrabMode (OUTPUT | CPIA_MODULE_CAPTURE | 3)
135 #define CPIA_COMMAND_InitStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 4)
136 #define CPIA_COMMAND_FiniStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 5)
137 #define CPIA_COMMAND_StartStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 6)
138 #define CPIA_COMMAND_EndStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 7)
139 #define CPIA_COMMAND_SetFormat (OUTPUT | CPIA_MODULE_CAPTURE | 8)
140 #define CPIA_COMMAND_SetROI (OUTPUT | CPIA_MODULE_CAPTURE | 9)
141 #define CPIA_COMMAND_SetCompression (OUTPUT | CPIA_MODULE_CAPTURE | 10)
142 #define CPIA_COMMAND_SetCompressionTarget (OUTPUT | CPIA_MODULE_CAPTURE | 11)
143 #define CPIA_COMMAND_SetYUVThresh (OUTPUT | CPIA_MODULE_CAPTURE | 12)
144 #define CPIA_COMMAND_SetCompressionParams (OUTPUT | CPIA_MODULE_CAPTURE | 13)
145 #define CPIA_COMMAND_DiscardFrame (OUTPUT | CPIA_MODULE_CAPTURE | 14)
146 #define CPIA_COMMAND_GrabReset (OUTPUT | CPIA_MODULE_CAPTURE | 15)
148 #define CPIA_COMMAND_OutputRS232 (OUTPUT | CPIA_MODULE_DEBUG | 1)
149 #define CPIA_COMMAND_AbortProcess (OUTPUT | CPIA_MODULE_DEBUG | 4)
150 #define CPIA_COMMAND_SetDramPage (OUTPUT | CPIA_MODULE_DEBUG | 5)
151 #define CPIA_COMMAND_StartDramUpload (OUTPUT | CPIA_MODULE_DEBUG | 6)
152 #define CPIA_COMMAND_StartDummyDtream (OUTPUT | CPIA_MODULE_DEBUG | 8)
153 #define CPIA_COMMAND_AbortStream (OUTPUT | CPIA_MODULE_DEBUG | 9)
154 #define CPIA_COMMAND_DownloadDRAM (OUTPUT | CPIA_MODULE_DEBUG | 10)
155 #define CPIA_COMMAND_Null (OUTPUT | CPIA_MODULE_DEBUG | 11)
158 FRAME_READY, /* Ready to grab into */
159 FRAME_GRABBING, /* In the process of being grabbed into */
160 FRAME_DONE, /* Finished grabbing, but not been synced yet */
161 FRAME_UNUSED, /* Unused (no MCAPTURE) */
164 #define COMMAND_NONE 0x0000
165 #define COMMAND_SETCOMPRESSION 0x0001
166 #define COMMAND_SETCOMPRESSIONTARGET 0x0002
167 #define COMMAND_SETCOLOURPARAMS 0x0004
168 #define COMMAND_SETFORMAT 0x0008
169 #define COMMAND_PAUSE 0x0010
170 #define COMMAND_RESUME 0x0020
171 #define COMMAND_SETYUVTHRESH 0x0040
172 #define COMMAND_SETECPTIMING 0x0080
173 #define COMMAND_SETCOMPRESSIONPARAMS 0x0100
174 #define COMMAND_SETEXPOSURE 0x0200
175 #define COMMAND_SETCOLOURBALANCE 0x0400
176 #define COMMAND_SETSENSORFPS 0x0800
177 #define COMMAND_SETAPCOR 0x1000
178 #define COMMAND_SETFLICKERCTRL 0x2000
179 #define COMMAND_SETVLOFFSET 0x4000
180 #define COMMAND_SETLIGHTS 0x8000
182 #define ROUND_UP_EXP_FOR_FLICKER 15
184 /* Constants for automatic frame rate adjustment */
186 #define MAX_EXP_102 255
188 #define VERY_LOW_EXP 70
190 #define EXP_ACC_DARK 50
191 #define EXP_ACC_LIGHT 90
192 #define HIGH_COMP_102 160
197 /* Maximum number of 10ms loops to wait for the stream to become ready */
198 #define READY_TIMEOUT 100
200 /* Developer's Guide Table 5 p 3-34
201 * indexed by [mains][sensorFps.baserate][sensorFps.divisor]*/
202 static u8 flicker_jumps[2][2][4] =
203 { { { 76, 38, 19, 9 }, { 92, 46, 23, 11 } },
204 { { 64, 32, 16, 8 }, { 76, 38, 19, 9} }
207 /* forward declaration of local function */
208 static void reset_camera_struct(struct cam_data *cam);
209 static int find_over_exposure(int brightness);
210 static void set_flicker(struct cam_params *params, volatile u32 *command_flags,
214 /**********************************************************************
218 **********************************************************************/
219 static void *rvmalloc(unsigned long size)
224 size = PAGE_ALIGN(size);
225 mem = vmalloc_32(size);
229 memset(mem, 0, size); /* Clear the ram out, no junk to the user */
230 adr = (unsigned long) mem;
232 SetPageReserved(vmalloc_to_page((void *)adr));
240 static void rvfree(void *mem, unsigned long size)
247 adr = (unsigned long) mem;
248 while ((long) size > 0) {
249 ClearPageReserved(vmalloc_to_page((void *)adr));
256 /**********************************************************************
260 **********************************************************************/
261 #ifdef CONFIG_PROC_FS
262 static struct proc_dir_entry *cpia_proc_root=NULL;
264 static int cpia_read_proc(char *page, char **start, off_t off,
265 int count, int *eof, void *data)
269 struct cam_data *cam = data;
272 /* IMPORTANT: This output MUST be kept under PAGE_SIZE
273 * or we need to get more sophisticated. */
275 out += sprintf(out, "read-only\n-----------------------\n");
276 out += sprintf(out, "V4L Driver version: %d.%d.%d\n",
277 CPIA_MAJ_VER, CPIA_MIN_VER, CPIA_PATCH_VER);
278 out += sprintf(out, "CPIA Version: %d.%02d (%d.%d)\n",
279 cam->params.version.firmwareVersion,
280 cam->params.version.firmwareRevision,
281 cam->params.version.vcVersion,
282 cam->params.version.vcRevision);
283 out += sprintf(out, "CPIA PnP-ID: %04x:%04x:%04x\n",
284 cam->params.pnpID.vendor, cam->params.pnpID.product,
285 cam->params.pnpID.deviceRevision);
286 out += sprintf(out, "VP-Version: %d.%d %04x\n",
287 cam->params.vpVersion.vpVersion,
288 cam->params.vpVersion.vpRevision,
289 cam->params.vpVersion.cameraHeadID);
291 out += sprintf(out, "system_state: %#04x\n",
292 cam->params.status.systemState);
293 out += sprintf(out, "grab_state: %#04x\n",
294 cam->params.status.grabState);
295 out += sprintf(out, "stream_state: %#04x\n",
296 cam->params.status.streamState);
297 out += sprintf(out, "fatal_error: %#04x\n",
298 cam->params.status.fatalError);
299 out += sprintf(out, "cmd_error: %#04x\n",
300 cam->params.status.cmdError);
301 out += sprintf(out, "debug_flags: %#04x\n",
302 cam->params.status.debugFlags);
303 out += sprintf(out, "vp_status: %#04x\n",
304 cam->params.status.vpStatus);
305 out += sprintf(out, "error_code: %#04x\n",
306 cam->params.status.errorCode);
307 /* QX3 specific entries */
308 if (cam->params.qx3.qx3_detected) {
309 out += sprintf(out, "button: %4d\n",
310 cam->params.qx3.button);
311 out += sprintf(out, "cradled: %4d\n",
312 cam->params.qx3.cradled);
314 out += sprintf(out, "video_size: %s\n",
315 cam->params.format.videoSize == VIDEOSIZE_CIF ?
317 out += sprintf(out, "roi: (%3d, %3d) to (%3d, %3d)\n",
318 cam->params.roi.colStart*8,
319 cam->params.roi.rowStart*4,
320 cam->params.roi.colEnd*8,
321 cam->params.roi.rowEnd*4);
322 out += sprintf(out, "actual_fps: %3d\n", cam->fps);
323 out += sprintf(out, "transfer_rate: %4dkB/s\n",
326 out += sprintf(out, "\nread-write\n");
327 out += sprintf(out, "----------------------- current min"
328 " max default comment\n");
329 out += sprintf(out, "brightness: %8d %8d %8d %8d\n",
330 cam->params.colourParams.brightness, 0, 100, 50);
331 if (cam->params.version.firmwareVersion == 1 &&
332 cam->params.version.firmwareRevision == 2)
333 /* 1-02 firmware limits contrast to 80 */
338 out += sprintf(out, "contrast: %8d %8d %8d %8d"
340 cam->params.colourParams.contrast, 0, tmp, 48);
341 out += sprintf(out, "saturation: %8d %8d %8d %8d\n",
342 cam->params.colourParams.saturation, 0, 100, 50);
343 tmp = (25000+5000*cam->params.sensorFps.baserate)/
344 (1<<cam->params.sensorFps.divisor);
345 out += sprintf(out, "sensor_fps: %4d.%03d %8d %8d %8d\n",
346 tmp/1000, tmp%1000, 3, 30, 15);
347 out += sprintf(out, "stream_start_line: %8d %8d %8d %8d\n",
348 2*cam->params.streamStartLine, 0,
349 cam->params.format.videoSize == VIDEOSIZE_CIF ? 288:144,
350 cam->params.format.videoSize == VIDEOSIZE_CIF ? 240:120);
351 out += sprintf(out, "sub_sample: %8s %8s %8s %8s\n",
352 cam->params.format.subSample == SUBSAMPLE_420 ?
353 "420" : "422", "420", "422", "422");
354 out += sprintf(out, "yuv_order: %8s %8s %8s %8s\n",
355 cam->params.format.yuvOrder == YUVORDER_YUYV ?
356 "YUYV" : "UYVY", "YUYV" , "UYVY", "YUYV");
357 out += sprintf(out, "ecp_timing: %8s %8s %8s %8s\n",
358 cam->params.ecpTiming ? "slow" : "normal", "slow",
361 if (cam->params.colourBalance.balanceMode == 2) {
362 sprintf(tmpstr, "auto");
364 sprintf(tmpstr, "manual");
366 out += sprintf(out, "color_balance_mode: %8s %8s %8s"
367 " %8s\n", tmpstr, "manual", "auto", "auto");
368 out += sprintf(out, "red_gain: %8d %8d %8d %8d\n",
369 cam->params.colourBalance.redGain, 0, 212, 32);
370 out += sprintf(out, "green_gain: %8d %8d %8d %8d\n",
371 cam->params.colourBalance.greenGain, 0, 212, 6);
372 out += sprintf(out, "blue_gain: %8d %8d %8d %8d\n",
373 cam->params.colourBalance.blueGain, 0, 212, 92);
375 if (cam->params.version.firmwareVersion == 1 &&
376 cam->params.version.firmwareRevision == 2)
377 /* 1-02 firmware limits gain to 2 */
378 sprintf(tmpstr, "%8d %8d %8d", 1, 2, 2);
380 sprintf(tmpstr, "%8d %8d %8d", 1, 8, 2);
382 if (cam->params.exposure.gainMode == 0)
383 out += sprintf(out, "max_gain: unknown %28s"
384 " powers of 2\n", tmpstr);
386 out += sprintf(out, "max_gain: %8d %28s"
388 1<<(cam->params.exposure.gainMode-1), tmpstr);
390 switch(cam->params.exposure.expMode) {
393 sprintf(tmpstr, "manual");
396 sprintf(tmpstr, "auto");
399 sprintf(tmpstr, "unknown");
402 out += sprintf(out, "exposure_mode: %8s %8s %8s"
403 " %8s\n", tmpstr, "manual", "auto", "auto");
404 out += sprintf(out, "centre_weight: %8s %8s %8s %8s\n",
405 (2-cam->params.exposure.centreWeight) ? "on" : "off",
407 out += sprintf(out, "gain: %8d %8d max_gain %8d 1,2,4,8 possible\n",
408 1<<cam->params.exposure.gain, 1, 1);
409 if (cam->params.version.firmwareVersion == 1 &&
410 cam->params.version.firmwareRevision == 2)
411 /* 1-02 firmware limits fineExp/2 to 127 */
416 out += sprintf(out, "fine_exp: %8d %8d %8d %8d\n",
417 cam->params.exposure.fineExp*2, 0, tmp, 0);
418 if (cam->params.version.firmwareVersion == 1 &&
419 cam->params.version.firmwareRevision == 2)
420 /* 1-02 firmware limits coarseExpHi to 0 */
425 out += sprintf(out, "coarse_exp: %8d %8d %8d"
426 " %8d\n", cam->params.exposure.coarseExpLo+
427 256*cam->params.exposure.coarseExpHi, 0, tmp, 185);
428 out += sprintf(out, "red_comp: %8d %8d %8d %8d\n",
429 cam->params.exposure.redComp, COMP_RED, 255, COMP_RED);
430 out += sprintf(out, "green1_comp: %8d %8d %8d %8d\n",
431 cam->params.exposure.green1Comp, COMP_GREEN1, 255,
433 out += sprintf(out, "green2_comp: %8d %8d %8d %8d\n",
434 cam->params.exposure.green2Comp, COMP_GREEN2, 255,
436 out += sprintf(out, "blue_comp: %8d %8d %8d %8d\n",
437 cam->params.exposure.blueComp, COMP_BLUE, 255, COMP_BLUE);
439 out += sprintf(out, "apcor_gain1: %#8x %#8x %#8x %#8x\n",
440 cam->params.apcor.gain1, 0, 0xff, 0x1c);
441 out += sprintf(out, "apcor_gain2: %#8x %#8x %#8x %#8x\n",
442 cam->params.apcor.gain2, 0, 0xff, 0x1a);
443 out += sprintf(out, "apcor_gain4: %#8x %#8x %#8x %#8x\n",
444 cam->params.apcor.gain4, 0, 0xff, 0x2d);
445 out += sprintf(out, "apcor_gain8: %#8x %#8x %#8x %#8x\n",
446 cam->params.apcor.gain8, 0, 0xff, 0x2a);
447 out += sprintf(out, "vl_offset_gain1: %8d %8d %8d %8d\n",
448 cam->params.vlOffset.gain1, 0, 255, 24);
449 out += sprintf(out, "vl_offset_gain2: %8d %8d %8d %8d\n",
450 cam->params.vlOffset.gain2, 0, 255, 28);
451 out += sprintf(out, "vl_offset_gain4: %8d %8d %8d %8d\n",
452 cam->params.vlOffset.gain4, 0, 255, 30);
453 out += sprintf(out, "vl_offset_gain8: %8d %8d %8d %8d\n",
454 cam->params.vlOffset.gain8, 0, 255, 30);
455 out += sprintf(out, "flicker_control: %8s %8s %8s %8s\n",
456 cam->params.flickerControl.flickerMode ? "on" : "off",
458 out += sprintf(out, "mains_frequency: %8d %8d %8d %8d"
460 cam->mainsFreq ? 60 : 50, 50, 60, 50);
461 if(cam->params.flickerControl.allowableOverExposure < 0)
462 out += sprintf(out, "allowable_overexposure: %4dauto auto %8d auto\n",
463 -cam->params.flickerControl.allowableOverExposure,
466 out += sprintf(out, "allowable_overexposure: %8d auto %8d auto\n",
467 cam->params.flickerControl.allowableOverExposure,
469 out += sprintf(out, "compression_mode: ");
470 switch(cam->params.compression.mode) {
471 case CPIA_COMPRESSION_NONE:
472 out += sprintf(out, "%8s", "none");
474 case CPIA_COMPRESSION_AUTO:
475 out += sprintf(out, "%8s", "auto");
477 case CPIA_COMPRESSION_MANUAL:
478 out += sprintf(out, "%8s", "manual");
481 out += sprintf(out, "%8s", "unknown");
484 out += sprintf(out, " none,auto,manual auto\n");
485 out += sprintf(out, "decimation_enable: %8s %8s %8s %8s\n",
486 cam->params.compression.decimation ==
487 DECIMATION_ENAB ? "on":"off", "off", "on",
489 out += sprintf(out, "compression_target: %9s %9s %9s %9s\n",
490 cam->params.compressionTarget.frTargeting ==
491 CPIA_COMPRESSION_TARGET_FRAMERATE ?
492 "framerate":"quality",
493 "framerate", "quality", "quality");
494 out += sprintf(out, "target_framerate: %8d %8d %8d %8d\n",
495 cam->params.compressionTarget.targetFR, 1, 30, 15);
496 out += sprintf(out, "target_quality: %8d %8d %8d %8d\n",
497 cam->params.compressionTarget.targetQ, 1, 64, 5);
498 out += sprintf(out, "y_threshold: %8d %8d %8d %8d\n",
499 cam->params.yuvThreshold.yThreshold, 0, 31, 6);
500 out += sprintf(out, "uv_threshold: %8d %8d %8d %8d\n",
501 cam->params.yuvThreshold.uvThreshold, 0, 31, 6);
502 out += sprintf(out, "hysteresis: %8d %8d %8d %8d\n",
503 cam->params.compressionParams.hysteresis, 0, 255, 3);
504 out += sprintf(out, "threshold_max: %8d %8d %8d %8d\n",
505 cam->params.compressionParams.threshMax, 0, 255, 11);
506 out += sprintf(out, "small_step: %8d %8d %8d %8d\n",
507 cam->params.compressionParams.smallStep, 0, 255, 1);
508 out += sprintf(out, "large_step: %8d %8d %8d %8d\n",
509 cam->params.compressionParams.largeStep, 0, 255, 3);
510 out += sprintf(out, "decimation_hysteresis: %8d %8d %8d %8d\n",
511 cam->params.compressionParams.decimationHysteresis,
513 out += sprintf(out, "fr_diff_step_thresh: %8d %8d %8d %8d\n",
514 cam->params.compressionParams.frDiffStepThresh,
516 out += sprintf(out, "q_diff_step_thresh: %8d %8d %8d %8d\n",
517 cam->params.compressionParams.qDiffStepThresh,
519 out += sprintf(out, "decimation_thresh_mod: %8d %8d %8d %8d\n",
520 cam->params.compressionParams.decimationThreshMod,
522 /* QX3 specific entries */
523 if (cam->params.qx3.qx3_detected) {
524 out += sprintf(out, "toplight: %8s %8s %8s %8s\n",
525 cam->params.qx3.toplight ? "on" : "off",
527 out += sprintf(out, "bottomlight: %8s %8s %8s %8s\n",
528 cam->params.qx3.bottomlight ? "on" : "off",
536 if (len <= 0) return 0;
545 static int match(char *checkstr, char **buffer, unsigned long *count,
546 int *find_colon, int *err)
548 int ret, colon_found = 1;
549 int len = strlen(checkstr);
550 ret = (len <= *count && strncmp(*buffer, checkstr, len) == 0);
556 while (*count && (**buffer == ' ' || **buffer == '\t' ||
557 (!colon_found && **buffer == ':'))) {
563 if (!*count || !colon_found)
571 static unsigned long int value(char **buffer, unsigned long *count, int *err)
574 unsigned long int ret;
575 ret = simple_strtoul(*buffer, &p, 0);
579 *count -= p - *buffer;
585 static int cpia_write_proc(struct file *file, const char __user *buf,
586 unsigned long count, void *data)
588 struct cam_data *cam = data;
589 struct cam_params new_params;
591 int retval, find_colon;
593 unsigned long val = 0;
594 u32 command_flags = 0;
598 * This code to copy from buf to page is shamelessly copied
599 * from the comx driver
601 if (count > PAGE_SIZE) {
602 printk(KERN_ERR "count is %lu > %d!!!\n", count, (int)PAGE_SIZE);
606 if (!(page = (char *)__get_free_page(GFP_KERNEL))) return -ENOMEM;
608 if(copy_from_user(page, buf, count))
614 if (page[count-1] == '\n')
615 page[count-1] = '\0';
616 else if (count < PAGE_SIZE)
618 else if (page[count]) {
625 if (down_interruptible(&cam->param_lock))
629 * Skip over leading whitespace
631 while (count && isspace(*buffer)) {
636 memcpy(&new_params, &cam->params, sizeof(struct cam_params));
637 new_mains = cam->mainsFreq;
639 #define MATCH(x) (match(x, &buffer, &count, &find_colon, &retval))
640 #define VALUE (value(&buffer,&count, &retval))
641 #define FIRMWARE_VERSION(x,y) (new_params.version.firmwareVersion == (x) && \
642 new_params.version.firmwareRevision == (y))
645 while (count && !retval) {
647 if (MATCH("brightness")) {
653 new_params.colourParams.brightness = val;
657 command_flags |= COMMAND_SETCOLOURPARAMS;
658 if(new_params.flickerControl.allowableOverExposure < 0)
659 new_params.flickerControl.allowableOverExposure =
660 -find_over_exposure(new_params.colourParams.brightness);
661 if(new_params.flickerControl.flickerMode != 0)
662 command_flags |= COMMAND_SETFLICKERCTRL;
664 } else if (MATCH("contrast")) {
670 /* contrast is in steps of 8, so round*/
671 val = ((val + 3) / 8) * 8;
672 /* 1-02 firmware limits contrast to 80*/
673 if (FIRMWARE_VERSION(1,2) && val > 80)
676 new_params.colourParams.contrast = val;
680 command_flags |= COMMAND_SETCOLOURPARAMS;
681 } else if (MATCH("saturation")) {
687 new_params.colourParams.saturation = val;
691 command_flags |= COMMAND_SETCOLOURPARAMS;
692 } else if (MATCH("sensor_fps")) {
697 /* find values so that sensorFPS is minimized,
702 new_params.sensorFps.divisor = 0;
703 new_params.sensorFps.baserate = 1;
704 } else if (val > 15) {
705 new_params.sensorFps.divisor = 0;
706 new_params.sensorFps.baserate = 0;
707 } else if (val > 12) {
708 new_params.sensorFps.divisor = 1;
709 new_params.sensorFps.baserate = 1;
710 } else if (val > 7) {
711 new_params.sensorFps.divisor = 1;
712 new_params.sensorFps.baserate = 0;
713 } else if (val > 6) {
714 new_params.sensorFps.divisor = 2;
715 new_params.sensorFps.baserate = 1;
716 } else if (val > 3) {
717 new_params.sensorFps.divisor = 2;
718 new_params.sensorFps.baserate = 0;
720 new_params.sensorFps.divisor = 3;
721 /* Either base rate would work here */
722 new_params.sensorFps.baserate = 1;
724 new_params.flickerControl.coarseJump =
725 flicker_jumps[new_mains]
726 [new_params.sensorFps.baserate]
727 [new_params.sensorFps.divisor];
728 if (new_params.flickerControl.flickerMode)
729 command_flags |= COMMAND_SETFLICKERCTRL;
731 command_flags |= COMMAND_SETSENSORFPS;
732 cam->exposure_status = EXPOSURE_NORMAL;
733 } else if (MATCH("stream_start_line")) {
740 if (new_params.format.videoSize == VIDEOSIZE_QCIF)
743 new_params.streamStartLine = val/2;
747 } else if (MATCH("sub_sample")) {
748 if (!retval && MATCH("420"))
749 new_params.format.subSample = SUBSAMPLE_420;
750 else if (!retval && MATCH("422"))
751 new_params.format.subSample = SUBSAMPLE_422;
755 command_flags |= COMMAND_SETFORMAT;
756 } else if (MATCH("yuv_order")) {
757 if (!retval && MATCH("YUYV"))
758 new_params.format.yuvOrder = YUVORDER_YUYV;
759 else if (!retval && MATCH("UYVY"))
760 new_params.format.yuvOrder = YUVORDER_UYVY;
764 command_flags |= COMMAND_SETFORMAT;
765 } else if (MATCH("ecp_timing")) {
766 if (!retval && MATCH("normal"))
767 new_params.ecpTiming = 0;
768 else if (!retval && MATCH("slow"))
769 new_params.ecpTiming = 1;
773 command_flags |= COMMAND_SETECPTIMING;
774 } else if (MATCH("color_balance_mode")) {
775 if (!retval && MATCH("manual"))
776 new_params.colourBalance.balanceMode = 3;
777 else if (!retval && MATCH("auto"))
778 new_params.colourBalance.balanceMode = 2;
782 command_flags |= COMMAND_SETCOLOURBALANCE;
783 } else if (MATCH("red_gain")) {
789 new_params.colourBalance.redGain = val;
790 new_params.colourBalance.balanceMode = 1;
794 command_flags |= COMMAND_SETCOLOURBALANCE;
795 } else if (MATCH("green_gain")) {
801 new_params.colourBalance.greenGain = val;
802 new_params.colourBalance.balanceMode = 1;
806 command_flags |= COMMAND_SETCOLOURBALANCE;
807 } else if (MATCH("blue_gain")) {
813 new_params.colourBalance.blueGain = val;
814 new_params.colourBalance.balanceMode = 1;
818 command_flags |= COMMAND_SETCOLOURBALANCE;
819 } else if (MATCH("max_gain")) {
824 /* 1-02 firmware limits gain to 2 */
825 if (FIRMWARE_VERSION(1,2) && val > 2)
829 new_params.exposure.gainMode = 1;
832 new_params.exposure.gainMode = 2;
835 new_params.exposure.gainMode = 3;
838 new_params.exposure.gainMode = 4;
845 command_flags |= COMMAND_SETEXPOSURE;
846 } else if (MATCH("exposure_mode")) {
847 if (!retval && MATCH("auto"))
848 new_params.exposure.expMode = 2;
849 else if (!retval && MATCH("manual")) {
850 if (new_params.exposure.expMode == 2)
851 new_params.exposure.expMode = 3;
852 if(new_params.flickerControl.flickerMode != 0)
853 command_flags |= COMMAND_SETFLICKERCTRL;
854 new_params.flickerControl.flickerMode = 0;
858 command_flags |= COMMAND_SETEXPOSURE;
859 } else if (MATCH("centre_weight")) {
860 if (!retval && MATCH("on"))
861 new_params.exposure.centreWeight = 1;
862 else if (!retval && MATCH("off"))
863 new_params.exposure.centreWeight = 2;
867 command_flags |= COMMAND_SETEXPOSURE;
868 } else if (MATCH("gain")) {
875 new_params.exposure.gain = 0;
878 new_params.exposure.gain = 1;
881 new_params.exposure.gain = 2;
884 new_params.exposure.gain = 3;
890 new_params.exposure.expMode = 1;
891 if(new_params.flickerControl.flickerMode != 0)
892 command_flags |= COMMAND_SETFLICKERCTRL;
893 new_params.flickerControl.flickerMode = 0;
894 command_flags |= COMMAND_SETEXPOSURE;
895 if (new_params.exposure.gain >
896 new_params.exposure.gainMode-1)
899 } else if (MATCH("fine_exp")) {
905 /* 1-02 firmware limits fineExp/2 to 127*/
906 if (FIRMWARE_VERSION(1,2) && val > 127)
908 new_params.exposure.fineExp = val;
909 new_params.exposure.expMode = 1;
910 command_flags |= COMMAND_SETEXPOSURE;
911 if(new_params.flickerControl.flickerMode != 0)
912 command_flags |= COMMAND_SETFLICKERCTRL;
913 new_params.flickerControl.flickerMode = 0;
914 command_flags |= COMMAND_SETFLICKERCTRL;
918 } else if (MATCH("coarse_exp")) {
923 if (val <= MAX_EXP) {
924 if (FIRMWARE_VERSION(1,2) &&
927 new_params.exposure.coarseExpLo =
929 new_params.exposure.coarseExpHi =
931 new_params.exposure.expMode = 1;
932 command_flags |= COMMAND_SETEXPOSURE;
933 if(new_params.flickerControl.flickerMode != 0)
934 command_flags |= COMMAND_SETFLICKERCTRL;
935 new_params.flickerControl.flickerMode = 0;
936 command_flags |= COMMAND_SETFLICKERCTRL;
940 } else if (MATCH("red_comp")) {
945 if (val >= COMP_RED && val <= 255) {
946 new_params.exposure.redComp = val;
947 new_params.exposure.compMode = 1;
948 command_flags |= COMMAND_SETEXPOSURE;
952 } else if (MATCH("green1_comp")) {
957 if (val >= COMP_GREEN1 && val <= 255) {
958 new_params.exposure.green1Comp = val;
959 new_params.exposure.compMode = 1;
960 command_flags |= COMMAND_SETEXPOSURE;
964 } else if (MATCH("green2_comp")) {
969 if (val >= COMP_GREEN2 && val <= 255) {
970 new_params.exposure.green2Comp = val;
971 new_params.exposure.compMode = 1;
972 command_flags |= COMMAND_SETEXPOSURE;
976 } else if (MATCH("blue_comp")) {
981 if (val >= COMP_BLUE && val <= 255) {
982 new_params.exposure.blueComp = val;
983 new_params.exposure.compMode = 1;
984 command_flags |= COMMAND_SETEXPOSURE;
988 } else if (MATCH("apcor_gain1")) {
993 command_flags |= COMMAND_SETAPCOR;
995 new_params.apcor.gain1 = val;
999 } else if (MATCH("apcor_gain2")) {
1004 command_flags |= COMMAND_SETAPCOR;
1006 new_params.apcor.gain2 = val;
1010 } else if (MATCH("apcor_gain4")) {
1015 command_flags |= COMMAND_SETAPCOR;
1017 new_params.apcor.gain4 = val;
1021 } else if (MATCH("apcor_gain8")) {
1026 command_flags |= COMMAND_SETAPCOR;
1028 new_params.apcor.gain8 = val;
1032 } else if (MATCH("vl_offset_gain1")) {
1038 new_params.vlOffset.gain1 = val;
1042 command_flags |= COMMAND_SETVLOFFSET;
1043 } else if (MATCH("vl_offset_gain2")) {
1049 new_params.vlOffset.gain2 = val;
1053 command_flags |= COMMAND_SETVLOFFSET;
1054 } else if (MATCH("vl_offset_gain4")) {
1060 new_params.vlOffset.gain4 = val;
1064 command_flags |= COMMAND_SETVLOFFSET;
1065 } else if (MATCH("vl_offset_gain8")) {
1071 new_params.vlOffset.gain8 = val;
1075 command_flags |= COMMAND_SETVLOFFSET;
1076 } else if (MATCH("flicker_control")) {
1077 if (!retval && MATCH("on")) {
1078 set_flicker(&new_params, &command_flags, 1);
1079 } else if (!retval && MATCH("off")) {
1080 set_flicker(&new_params, &command_flags, 0);
1084 command_flags |= COMMAND_SETFLICKERCTRL;
1085 } else if (MATCH("mains_frequency")) {
1086 if (!retval && MATCH("50")) {
1088 new_params.flickerControl.coarseJump =
1089 flicker_jumps[new_mains]
1090 [new_params.sensorFps.baserate]
1091 [new_params.sensorFps.divisor];
1092 if (new_params.flickerControl.flickerMode)
1093 command_flags |= COMMAND_SETFLICKERCTRL;
1094 } else if (!retval && MATCH("60")) {
1096 new_params.flickerControl.coarseJump =
1097 flicker_jumps[new_mains]
1098 [new_params.sensorFps.baserate]
1099 [new_params.sensorFps.divisor];
1100 if (new_params.flickerControl.flickerMode)
1101 command_flags |= COMMAND_SETFLICKERCTRL;
1104 } else if (MATCH("allowable_overexposure")) {
1105 if (!retval && MATCH("auto")) {
1106 new_params.flickerControl.allowableOverExposure =
1107 -find_over_exposure(new_params.colourParams.brightness);
1108 if(new_params.flickerControl.flickerMode != 0)
1109 command_flags |= COMMAND_SETFLICKERCTRL;
1116 new_params.flickerControl.
1117 allowableOverExposure = val;
1118 if(new_params.flickerControl.flickerMode != 0)
1119 command_flags |= COMMAND_SETFLICKERCTRL;
1124 } else if (MATCH("compression_mode")) {
1125 if (!retval && MATCH("none"))
1126 new_params.compression.mode =
1127 CPIA_COMPRESSION_NONE;
1128 else if (!retval && MATCH("auto"))
1129 new_params.compression.mode =
1130 CPIA_COMPRESSION_AUTO;
1131 else if (!retval && MATCH("manual"))
1132 new_params.compression.mode =
1133 CPIA_COMPRESSION_MANUAL;
1137 command_flags |= COMMAND_SETCOMPRESSION;
1138 } else if (MATCH("decimation_enable")) {
1139 if (!retval && MATCH("off"))
1140 new_params.compression.decimation = 0;
1141 else if (!retval && MATCH("on"))
1142 new_params.compression.decimation = 1;
1146 command_flags |= COMMAND_SETCOMPRESSION;
1147 } else if (MATCH("compression_target")) {
1148 if (!retval && MATCH("quality"))
1149 new_params.compressionTarget.frTargeting =
1150 CPIA_COMPRESSION_TARGET_QUALITY;
1151 else if (!retval && MATCH("framerate"))
1152 new_params.compressionTarget.frTargeting =
1153 CPIA_COMPRESSION_TARGET_FRAMERATE;
1157 command_flags |= COMMAND_SETCOMPRESSIONTARGET;
1158 } else if (MATCH("target_framerate")) {
1163 if(val > 0 && val <= 30)
1164 new_params.compressionTarget.targetFR = val;
1168 command_flags |= COMMAND_SETCOMPRESSIONTARGET;
1169 } else if (MATCH("target_quality")) {
1174 if(val > 0 && val <= 64)
1175 new_params.compressionTarget.targetQ = val;
1179 command_flags |= COMMAND_SETCOMPRESSIONTARGET;
1180 } else if (MATCH("y_threshold")) {
1186 new_params.yuvThreshold.yThreshold = val;
1190 command_flags |= COMMAND_SETYUVTHRESH;
1191 } else if (MATCH("uv_threshold")) {
1197 new_params.yuvThreshold.uvThreshold = val;
1201 command_flags |= COMMAND_SETYUVTHRESH;
1202 } else if (MATCH("hysteresis")) {
1208 new_params.compressionParams.hysteresis = val;
1212 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1213 } else if (MATCH("threshold_max")) {
1219 new_params.compressionParams.threshMax = val;
1223 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1224 } else if (MATCH("small_step")) {
1230 new_params.compressionParams.smallStep = val;
1234 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1235 } else if (MATCH("large_step")) {
1241 new_params.compressionParams.largeStep = val;
1245 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1246 } else if (MATCH("decimation_hysteresis")) {
1252 new_params.compressionParams.decimationHysteresis = val;
1256 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1257 } else if (MATCH("fr_diff_step_thresh")) {
1263 new_params.compressionParams.frDiffStepThresh = val;
1267 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1268 } else if (MATCH("q_diff_step_thresh")) {
1274 new_params.compressionParams.qDiffStepThresh = val;
1278 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1279 } else if (MATCH("decimation_thresh_mod")) {
1285 new_params.compressionParams.decimationThreshMod = val;
1289 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1290 } else if (MATCH("toplight")) {
1291 if (!retval && MATCH("on"))
1292 new_params.qx3.toplight = 1;
1293 else if (!retval && MATCH("off"))
1294 new_params.qx3.toplight = 0;
1297 command_flags |= COMMAND_SETLIGHTS;
1298 } else if (MATCH("bottomlight")) {
1299 if (!retval && MATCH("on"))
1300 new_params.qx3.bottomlight = 1;
1301 else if (!retval && MATCH("off"))
1302 new_params.qx3.bottomlight = 0;
1305 command_flags |= COMMAND_SETLIGHTS;
1307 DBG("No match found\n");
1312 while (count && isspace(*buffer) && *buffer != '\n') {
1317 if (*buffer == '\0' && count != 1)
1319 else if (*buffer != '\n' && *buffer != ';' &&
1331 #undef FIRMWARE_VERSION
1333 if (command_flags & COMMAND_SETCOLOURPARAMS) {
1334 /* Adjust cam->vp to reflect these changes */
1335 cam->vp.brightness =
1336 new_params.colourParams.brightness*65535/100;
1338 new_params.colourParams.contrast*65535/100;
1340 new_params.colourParams.saturation*65535/100;
1342 if((command_flags & COMMAND_SETEXPOSURE) &&
1343 new_params.exposure.expMode == 2)
1344 cam->exposure_status = EXPOSURE_NORMAL;
1346 memcpy(&cam->params, &new_params, sizeof(struct cam_params));
1347 cam->mainsFreq = new_mains;
1348 cam->cmd_queue |= command_flags;
1351 DBG("error: %d\n", retval);
1353 up(&cam->param_lock);
1356 free_page((unsigned long)page);
1360 static void create_proc_cpia_cam(struct cam_data *cam)
1363 struct proc_dir_entry *ent;
1365 if (!cpia_proc_root || !cam)
1368 sprintf(name, "video%d", cam->vdev.minor);
1370 ent = create_proc_entry(name, S_IFREG|S_IRUGO|S_IWUSR, cpia_proc_root);
1375 ent->read_proc = cpia_read_proc;
1376 ent->write_proc = cpia_write_proc;
1378 size of the proc entry is 3736 bytes for the standard webcam;
1379 the extra features of the QX3 microscope add 189 bytes.
1380 (we have not yet probed the camera to see which type it is).
1382 ent->size = 3736 + 189;
1383 cam->proc_entry = ent;
1386 static void destroy_proc_cpia_cam(struct cam_data *cam)
1390 if (!cam || !cam->proc_entry)
1393 sprintf(name, "video%d", cam->vdev.minor);
1394 remove_proc_entry(name, cpia_proc_root);
1395 cam->proc_entry = NULL;
1398 static void proc_cpia_create(void)
1400 cpia_proc_root = create_proc_entry("cpia", S_IFDIR, NULL);
1403 cpia_proc_root->owner = THIS_MODULE;
1405 LOG("Unable to initialise /proc/cpia\n");
1408 static void __exit proc_cpia_destroy(void)
1410 remove_proc_entry("cpia", NULL);
1412 #endif /* CONFIG_PROC_FS */
1414 /* ----------------------- debug functions ---------------------- */
1416 #define printstatus(cam) \
1417 DBG("%02x %02x %02x %02x %02x %02x %02x %02x\n",\
1418 cam->params.status.systemState, cam->params.status.grabState, \
1419 cam->params.status.streamState, cam->params.status.fatalError, \
1420 cam->params.status.cmdError, cam->params.status.debugFlags, \
1421 cam->params.status.vpStatus, cam->params.status.errorCode);
1423 /* ----------------------- v4l helpers -------------------------- */
1425 /* supported frame palettes and depths */
1426 static inline int valid_mode(u16 palette, u16 depth)
1428 if ((palette == VIDEO_PALETTE_YUV422 && depth == 16) ||
1429 (palette == VIDEO_PALETTE_YUYV && depth == 16))
1432 if (colorspace_conv)
1433 return (palette == VIDEO_PALETTE_GREY && depth == 8) ||
1434 (palette == VIDEO_PALETTE_RGB555 && depth == 16) ||
1435 (palette == VIDEO_PALETTE_RGB565 && depth == 16) ||
1436 (palette == VIDEO_PALETTE_RGB24 && depth == 24) ||
1437 (palette == VIDEO_PALETTE_RGB32 && depth == 32) ||
1438 (palette == VIDEO_PALETTE_UYVY && depth == 16);
1443 static int match_videosize( int width, int height )
1445 /* return the best match, where 'best' is as always
1446 * the largest that is not bigger than what is requested. */
1447 if (width>=352 && height>=288)
1448 return VIDEOSIZE_352_288; /* CIF */
1450 if (width>=320 && height>=240)
1451 return VIDEOSIZE_320_240; /* SIF */
1453 if (width>=288 && height>=216)
1454 return VIDEOSIZE_288_216;
1456 if (width>=256 && height>=192)
1457 return VIDEOSIZE_256_192;
1459 if (width>=224 && height>=168)
1460 return VIDEOSIZE_224_168;
1462 if (width>=192 && height>=144)
1463 return VIDEOSIZE_192_144;
1465 if (width>=176 && height>=144)
1466 return VIDEOSIZE_176_144; /* QCIF */
1468 if (width>=160 && height>=120)
1469 return VIDEOSIZE_160_120; /* QSIF */
1471 if (width>=128 && height>=96)
1472 return VIDEOSIZE_128_96;
1474 if (width>=88 && height>=72)
1475 return VIDEOSIZE_88_72;
1477 if (width>=64 && height>=48)
1478 return VIDEOSIZE_64_48;
1480 if (width>=48 && height>=48)
1481 return VIDEOSIZE_48_48;
1486 /* these are the capture sizes we support */
1487 static void set_vw_size(struct cam_data *cam)
1489 /* the col/row/start/end values are the result of simple math */
1490 /* study the SetROI-command in cpia developers guide p 2-22 */
1491 /* streamStartLine is set to the recommended value in the cpia */
1492 /* developers guide p 3-37 */
1493 switch(cam->video_size) {
1495 cam->vw.width = 352;
1496 cam->vw.height = 288;
1497 cam->params.format.videoSize=VIDEOSIZE_CIF;
1498 cam->params.roi.colStart=0;
1499 cam->params.roi.rowStart=0;
1500 cam->params.streamStartLine = 120;
1503 cam->vw.width = 320;
1504 cam->vw.height = 240;
1505 cam->params.format.videoSize=VIDEOSIZE_CIF;
1506 cam->params.roi.colStart=2;
1507 cam->params.roi.rowStart=6;
1508 cam->params.streamStartLine = 120;
1510 case VIDEOSIZE_288_216:
1511 cam->vw.width = 288;
1512 cam->vw.height = 216;
1513 cam->params.format.videoSize=VIDEOSIZE_CIF;
1514 cam->params.roi.colStart=4;
1515 cam->params.roi.rowStart=9;
1516 cam->params.streamStartLine = 120;
1518 case VIDEOSIZE_256_192:
1519 cam->vw.width = 256;
1520 cam->vw.height = 192;
1521 cam->params.format.videoSize=VIDEOSIZE_CIF;
1522 cam->params.roi.colStart=6;
1523 cam->params.roi.rowStart=12;
1524 cam->params.streamStartLine = 120;
1526 case VIDEOSIZE_224_168:
1527 cam->vw.width = 224;
1528 cam->vw.height = 168;
1529 cam->params.format.videoSize=VIDEOSIZE_CIF;
1530 cam->params.roi.colStart=8;
1531 cam->params.roi.rowStart=15;
1532 cam->params.streamStartLine = 120;
1534 case VIDEOSIZE_192_144:
1535 cam->vw.width = 192;
1536 cam->vw.height = 144;
1537 cam->params.format.videoSize=VIDEOSIZE_CIF;
1538 cam->params.roi.colStart=10;
1539 cam->params.roi.rowStart=18;
1540 cam->params.streamStartLine = 120;
1542 case VIDEOSIZE_QCIF:
1543 cam->vw.width = 176;
1544 cam->vw.height = 144;
1545 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1546 cam->params.roi.colStart=0;
1547 cam->params.roi.rowStart=0;
1548 cam->params.streamStartLine = 60;
1550 case VIDEOSIZE_QSIF:
1551 cam->vw.width = 160;
1552 cam->vw.height = 120;
1553 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1554 cam->params.roi.colStart=1;
1555 cam->params.roi.rowStart=3;
1556 cam->params.streamStartLine = 60;
1558 case VIDEOSIZE_128_96:
1559 cam->vw.width = 128;
1560 cam->vw.height = 96;
1561 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1562 cam->params.roi.colStart=3;
1563 cam->params.roi.rowStart=6;
1564 cam->params.streamStartLine = 60;
1566 case VIDEOSIZE_88_72:
1568 cam->vw.height = 72;
1569 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1570 cam->params.roi.colStart=5;
1571 cam->params.roi.rowStart=9;
1572 cam->params.streamStartLine = 60;
1574 case VIDEOSIZE_64_48:
1576 cam->vw.height = 48;
1577 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1578 cam->params.roi.colStart=7;
1579 cam->params.roi.rowStart=12;
1580 cam->params.streamStartLine = 60;
1582 case VIDEOSIZE_48_48:
1584 cam->vw.height = 48;
1585 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1586 cam->params.roi.colStart=8;
1587 cam->params.roi.rowStart=6;
1588 cam->params.streamStartLine = 60;
1591 LOG("bad videosize value: %d\n", cam->video_size);
1595 if(cam->vc.width == 0)
1596 cam->vc.width = cam->vw.width;
1597 if(cam->vc.height == 0)
1598 cam->vc.height = cam->vw.height;
1600 cam->params.roi.colStart += cam->vc.x >> 3;
1601 cam->params.roi.colEnd = cam->params.roi.colStart +
1602 (cam->vc.width >> 3);
1603 cam->params.roi.rowStart += cam->vc.y >> 2;
1604 cam->params.roi.rowEnd = cam->params.roi.rowStart +
1605 (cam->vc.height >> 2);
1610 static int allocate_frame_buf(struct cam_data *cam)
1614 cam->frame_buf = rvmalloc(FRAME_NUM * CPIA_MAX_FRAME_SIZE);
1615 if (!cam->frame_buf)
1618 for (i = 0; i < FRAME_NUM; i++)
1619 cam->frame[i].data = cam->frame_buf + i * CPIA_MAX_FRAME_SIZE;
1624 static int free_frame_buf(struct cam_data *cam)
1628 rvfree(cam->frame_buf, FRAME_NUM*CPIA_MAX_FRAME_SIZE);
1629 cam->frame_buf = NULL;
1630 for (i=0; i < FRAME_NUM; i++)
1631 cam->frame[i].data = NULL;
1637 static inline void free_frames(struct cpia_frame frame[FRAME_NUM])
1641 for (i=0; i < FRAME_NUM; i++)
1642 frame[i].state = FRAME_UNUSED;
1646 /**********************************************************************
1650 **********************************************************************/
1651 /* send an arbitrary command to the camera */
1652 static int do_command(struct cam_data *cam, u16 command, u8 a, u8 b, u8 c, u8 d)
1654 int retval, datasize;
1658 case CPIA_COMMAND_GetCPIAVersion:
1659 case CPIA_COMMAND_GetPnPID:
1660 case CPIA_COMMAND_GetCameraStatus:
1661 case CPIA_COMMAND_GetVPVersion:
1664 case CPIA_COMMAND_GetColourParams:
1665 case CPIA_COMMAND_GetColourBalance:
1666 case CPIA_COMMAND_GetExposure:
1667 down(&cam->param_lock);
1670 case CPIA_COMMAND_ReadMCPorts:
1671 case CPIA_COMMAND_ReadVCRegs:
1679 cmd[0] = command>>8;
1680 cmd[1] = command&0xff;
1688 retval = cam->ops->transferCmd(cam->lowlevel_data, cmd, data);
1690 DBG("%x - failed, retval=%d\n", command, retval);
1691 if (command == CPIA_COMMAND_GetColourParams ||
1692 command == CPIA_COMMAND_GetColourBalance ||
1693 command == CPIA_COMMAND_GetExposure)
1694 up(&cam->param_lock);
1697 case CPIA_COMMAND_GetCPIAVersion:
1698 cam->params.version.firmwareVersion = data[0];
1699 cam->params.version.firmwareRevision = data[1];
1700 cam->params.version.vcVersion = data[2];
1701 cam->params.version.vcRevision = data[3];
1703 case CPIA_COMMAND_GetPnPID:
1704 cam->params.pnpID.vendor = data[0]+(((u16)data[1])<<8);
1705 cam->params.pnpID.product = data[2]+(((u16)data[3])<<8);
1706 cam->params.pnpID.deviceRevision =
1707 data[4]+(((u16)data[5])<<8);
1709 case CPIA_COMMAND_GetCameraStatus:
1710 cam->params.status.systemState = data[0];
1711 cam->params.status.grabState = data[1];
1712 cam->params.status.streamState = data[2];
1713 cam->params.status.fatalError = data[3];
1714 cam->params.status.cmdError = data[4];
1715 cam->params.status.debugFlags = data[5];
1716 cam->params.status.vpStatus = data[6];
1717 cam->params.status.errorCode = data[7];
1719 case CPIA_COMMAND_GetVPVersion:
1720 cam->params.vpVersion.vpVersion = data[0];
1721 cam->params.vpVersion.vpRevision = data[1];
1722 cam->params.vpVersion.cameraHeadID =
1723 data[2]+(((u16)data[3])<<8);
1725 case CPIA_COMMAND_GetColourParams:
1726 cam->params.colourParams.brightness = data[0];
1727 cam->params.colourParams.contrast = data[1];
1728 cam->params.colourParams.saturation = data[2];
1729 up(&cam->param_lock);
1731 case CPIA_COMMAND_GetColourBalance:
1732 cam->params.colourBalance.redGain = data[0];
1733 cam->params.colourBalance.greenGain = data[1];
1734 cam->params.colourBalance.blueGain = data[2];
1735 up(&cam->param_lock);
1737 case CPIA_COMMAND_GetExposure:
1738 cam->params.exposure.gain = data[0];
1739 cam->params.exposure.fineExp = data[1];
1740 cam->params.exposure.coarseExpLo = data[2];
1741 cam->params.exposure.coarseExpHi = data[3];
1742 cam->params.exposure.redComp = data[4];
1743 cam->params.exposure.green1Comp = data[5];
1744 cam->params.exposure.green2Comp = data[6];
1745 cam->params.exposure.blueComp = data[7];
1746 up(&cam->param_lock);
1749 case CPIA_COMMAND_ReadMCPorts:
1750 if (!cam->params.qx3.qx3_detected)
1752 /* test button press */
1753 cam->params.qx3.button = ((data[1] & 0x02) == 0);
1754 if (cam->params.qx3.button) {
1755 /* button pressed - unlock the latch */
1756 do_command(cam,CPIA_COMMAND_WriteMCPort,3,0xDF,0xDF,0);
1757 do_command(cam,CPIA_COMMAND_WriteMCPort,3,0xFF,0xFF,0);
1760 /* test whether microscope is cradled */
1761 cam->params.qx3.cradled = ((data[2] & 0x40) == 0);
1771 /* send a command to the camera with an additional data transaction */
1772 static int do_command_extended(struct cam_data *cam, u16 command,
1773 u8 a, u8 b, u8 c, u8 d,
1774 u8 e, u8 f, u8 g, u8 h,
1775 u8 i, u8 j, u8 k, u8 l)
1780 cmd[0] = command>>8;
1781 cmd[1] = command&0xff;
1797 retval = cam->ops->transferCmd(cam->lowlevel_data, cmd, data);
1799 DBG("%x - failed\n", command);
1804 /**********************************************************************
1806 * Colorspace conversion
1808 **********************************************************************/
1809 #define LIMIT(x) ((((x)>0xffffff)?0xff0000:(((x)<=0xffff)?0:(x)&0xff0000))>>16)
1811 static int convert420(unsigned char *yuv, unsigned char *rgb, int out_fmt,
1812 int linesize, int mmap_kludge)
1814 int y, u, v, r, g, b, y1;
1816 /* Odd lines use the same u and v as the previous line.
1817 * Because of compression, it is necessary to get this
1818 * information from the decoded image. */
1820 case VIDEO_PALETTE_RGB555:
1821 y = (*yuv++ - 16) * 76310;
1822 y1 = (*yuv - 16) * 76310;
1823 r = ((*(rgb+1-linesize)) & 0x7c) << 1;
1824 g = ((*(rgb-linesize)) & 0xe0) >> 4 |
1825 ((*(rgb+1-linesize)) & 0x03) << 6;
1826 b = ((*(rgb-linesize)) & 0x1f) << 3;
1827 u = (-53294 * r - 104635 * g + 157929 * b) / 5756495;
1828 v = (157968 * r - 132278 * g - 25690 * b) / 5366159;
1830 g = -25690 * u - 53294 * v;
1832 *rgb++ = ((LIMIT(g+y) & 0xf8) << 2) | (LIMIT(b+y) >> 3);
1833 *rgb++ = ((LIMIT(r+y) & 0xf8) >> 1) | (LIMIT(g+y) >> 6);
1834 *rgb++ = ((LIMIT(g+y1) & 0xf8) << 2) | (LIMIT(b+y1) >> 3);
1835 *rgb = ((LIMIT(r+y1) & 0xf8) >> 1) | (LIMIT(g+y1) >> 6);
1837 case VIDEO_PALETTE_RGB565:
1838 y = (*yuv++ - 16) * 76310;
1839 y1 = (*yuv - 16) * 76310;
1840 r = (*(rgb+1-linesize)) & 0xf8;
1841 g = ((*(rgb-linesize)) & 0xe0) >> 3 |
1842 ((*(rgb+1-linesize)) & 0x07) << 5;
1843 b = ((*(rgb-linesize)) & 0x1f) << 3;
1844 u = (-53294 * r - 104635 * g + 157929 * b) / 5756495;
1845 v = (157968 * r - 132278 * g - 25690 * b) / 5366159;
1847 g = -25690 * u - 53294 * v;
1849 *rgb++ = ((LIMIT(g+y) & 0xfc) << 3) | (LIMIT(b+y) >> 3);
1850 *rgb++ = (LIMIT(r+y) & 0xf8) | (LIMIT(g+y) >> 5);
1851 *rgb++ = ((LIMIT(g+y1) & 0xfc) << 3) | (LIMIT(b+y1) >> 3);
1852 *rgb = (LIMIT(r+y1) & 0xf8) | (LIMIT(g+y1) >> 5);
1855 case VIDEO_PALETTE_RGB24:
1856 case VIDEO_PALETTE_RGB32:
1857 y = (*yuv++ - 16) * 76310;
1858 y1 = (*yuv - 16) * 76310;
1860 r = *(rgb+2-linesize);
1861 g = *(rgb+1-linesize);
1862 b = *(rgb-linesize);
1864 r = *(rgb-linesize);
1865 g = *(rgb+1-linesize);
1866 b = *(rgb+2-linesize);
1868 u = (-53294 * r - 104635 * g + 157929 * b) / 5756495;
1869 v = (157968 * r - 132278 * g - 25690 * b) / 5366159;
1871 g = -25690 * u + -53294 * v;
1874 *rgb++ = LIMIT(b+y);
1875 *rgb++ = LIMIT(g+y);
1876 *rgb++ = LIMIT(r+y);
1877 if(out_fmt == VIDEO_PALETTE_RGB32)
1879 *rgb++ = LIMIT(b+y1);
1880 *rgb++ = LIMIT(g+y1);
1883 *rgb++ = LIMIT(r+y);
1884 *rgb++ = LIMIT(g+y);
1885 *rgb++ = LIMIT(b+y);
1886 if(out_fmt == VIDEO_PALETTE_RGB32)
1888 *rgb++ = LIMIT(r+y1);
1889 *rgb++ = LIMIT(g+y1);
1892 if(out_fmt == VIDEO_PALETTE_RGB32)
1895 case VIDEO_PALETTE_YUV422:
1896 case VIDEO_PALETTE_YUYV:
1898 u = *(rgb+1-linesize);
1900 v = *(rgb+3-linesize);
1906 case VIDEO_PALETTE_UYVY:
1907 u = *(rgb-linesize);
1909 v = *(rgb+2-linesize);
1916 case VIDEO_PALETTE_GREY:
1921 DBG("Empty: %d\n", out_fmt);
1927 static int yuvconvert(unsigned char *yuv, unsigned char *rgb, int out_fmt,
1928 int in_uyvy, int mmap_kludge)
1930 int y, u, v, r, g, b, y1;
1933 case VIDEO_PALETTE_RGB555:
1934 case VIDEO_PALETTE_RGB565:
1935 case VIDEO_PALETTE_RGB24:
1936 case VIDEO_PALETTE_RGB32:
1939 y = (*yuv++ - 16) * 76310;
1941 y1 = (*yuv - 16) * 76310;
1943 y = (*yuv++ - 16) * 76310;
1945 y1 = (*yuv++ - 16) * 76310;
1949 g = -25690 * u + -53294 * v;
1957 /* Just to avoid compiler warnings */
1964 case VIDEO_PALETTE_RGB555:
1965 *rgb++ = ((LIMIT(g+y) & 0xf8) << 2) | (LIMIT(b+y) >> 3);
1966 *rgb++ = ((LIMIT(r+y) & 0xf8) >> 1) | (LIMIT(g+y) >> 6);
1967 *rgb++ = ((LIMIT(g+y1) & 0xf8) << 2) | (LIMIT(b+y1) >> 3);
1968 *rgb = ((LIMIT(r+y1) & 0xf8) >> 1) | (LIMIT(g+y1) >> 6);
1970 case VIDEO_PALETTE_RGB565:
1971 *rgb++ = ((LIMIT(g+y) & 0xfc) << 3) | (LIMIT(b+y) >> 3);
1972 *rgb++ = (LIMIT(r+y) & 0xf8) | (LIMIT(g+y) >> 5);
1973 *rgb++ = ((LIMIT(g+y1) & 0xfc) << 3) | (LIMIT(b+y1) >> 3);
1974 *rgb = (LIMIT(r+y1) & 0xf8) | (LIMIT(g+y1) >> 5);
1976 case VIDEO_PALETTE_RGB24:
1978 *rgb++ = LIMIT(b+y);
1979 *rgb++ = LIMIT(g+y);
1980 *rgb++ = LIMIT(r+y);
1981 *rgb++ = LIMIT(b+y1);
1982 *rgb++ = LIMIT(g+y1);
1985 *rgb++ = LIMIT(r+y);
1986 *rgb++ = LIMIT(g+y);
1987 *rgb++ = LIMIT(b+y);
1988 *rgb++ = LIMIT(r+y1);
1989 *rgb++ = LIMIT(g+y1);
1993 case VIDEO_PALETTE_RGB32:
1995 *rgb++ = LIMIT(b+y);
1996 *rgb++ = LIMIT(g+y);
1997 *rgb++ = LIMIT(r+y);
1999 *rgb++ = LIMIT(b+y1);
2000 *rgb++ = LIMIT(g+y1);
2003 *rgb++ = LIMIT(r+y);
2004 *rgb++ = LIMIT(g+y);
2005 *rgb++ = LIMIT(b+y);
2007 *rgb++ = LIMIT(r+y1);
2008 *rgb++ = LIMIT(g+y1);
2012 case VIDEO_PALETTE_GREY:
2016 case VIDEO_PALETTE_YUV422:
2017 case VIDEO_PALETTE_YUYV:
2023 case VIDEO_PALETTE_UYVY:
2030 DBG("Empty: %d\n", out_fmt);
2035 static int skipcount(int count, int fmt)
2038 case VIDEO_PALETTE_GREY:
2040 case VIDEO_PALETTE_RGB555:
2041 case VIDEO_PALETTE_RGB565:
2042 case VIDEO_PALETTE_YUV422:
2043 case VIDEO_PALETTE_YUYV:
2044 case VIDEO_PALETTE_UYVY:
2046 case VIDEO_PALETTE_RGB24:
2048 case VIDEO_PALETTE_RGB32:
2055 static int parse_picture(struct cam_data *cam, int size)
2057 u8 *obuf, *ibuf, *end_obuf;
2058 int ll, in_uyvy, compressed, decimation, even_line, origsize, out_fmt;
2059 int rows, cols, linesize, subsample_422;
2061 /* make sure params don't change while we are decoding */
2062 down(&cam->param_lock);
2064 obuf = cam->decompressed_frame.data;
2065 end_obuf = obuf+CPIA_MAX_FRAME_SIZE;
2066 ibuf = cam->raw_image;
2068 out_fmt = cam->vp.palette;
2070 if ((ibuf[0] != MAGIC_0) || (ibuf[1] != MAGIC_1)) {
2071 LOG("header not found\n");
2072 up(&cam->param_lock);
2076 if ((ibuf[16] != VIDEOSIZE_QCIF) && (ibuf[16] != VIDEOSIZE_CIF)) {
2077 LOG("wrong video size\n");
2078 up(&cam->param_lock);
2082 if (ibuf[17] != SUBSAMPLE_420 && ibuf[17] != SUBSAMPLE_422) {
2083 LOG("illegal subtype %d\n",ibuf[17]);
2084 up(&cam->param_lock);
2087 subsample_422 = ibuf[17] == SUBSAMPLE_422;
2089 if (ibuf[18] != YUVORDER_YUYV && ibuf[18] != YUVORDER_UYVY) {
2090 LOG("illegal yuvorder %d\n",ibuf[18]);
2091 up(&cam->param_lock);
2094 in_uyvy = ibuf[18] == YUVORDER_UYVY;
2096 if ((ibuf[24] != cam->params.roi.colStart) ||
2097 (ibuf[25] != cam->params.roi.colEnd) ||
2098 (ibuf[26] != cam->params.roi.rowStart) ||
2099 (ibuf[27] != cam->params.roi.rowEnd)) {
2100 LOG("ROI mismatch\n");
2101 up(&cam->param_lock);
2104 cols = 8*(ibuf[25] - ibuf[24]);
2105 rows = 4*(ibuf[27] - ibuf[26]);
2108 if ((ibuf[28] != NOT_COMPRESSED) && (ibuf[28] != COMPRESSED)) {
2109 LOG("illegal compression %d\n",ibuf[28]);
2110 up(&cam->param_lock);
2113 compressed = (ibuf[28] == COMPRESSED);
2115 if (ibuf[29] != NO_DECIMATION && ibuf[29] != DECIMATION_ENAB) {
2116 LOG("illegal decimation %d\n",ibuf[29]);
2117 up(&cam->param_lock);
2120 decimation = (ibuf[29] == DECIMATION_ENAB);
2122 cam->params.yuvThreshold.yThreshold = ibuf[30];
2123 cam->params.yuvThreshold.uvThreshold = ibuf[31];
2124 cam->params.status.systemState = ibuf[32];
2125 cam->params.status.grabState = ibuf[33];
2126 cam->params.status.streamState = ibuf[34];
2127 cam->params.status.fatalError = ibuf[35];
2128 cam->params.status.cmdError = ibuf[36];
2129 cam->params.status.debugFlags = ibuf[37];
2130 cam->params.status.vpStatus = ibuf[38];
2131 cam->params.status.errorCode = ibuf[39];
2132 cam->fps = ibuf[41];
2133 up(&cam->param_lock);
2135 linesize = skipcount(cols, out_fmt);
2136 ibuf += FRAME_HEADER_SIZE;
2137 size -= FRAME_HEADER_SIZE;
2138 ll = ibuf[0] | (ibuf[1] << 8);
2145 LOG("Insufficient data in buffer\n");
2150 if (!compressed || (compressed && !(*ibuf & 1))) {
2151 if(subsample_422 || even_line) {
2152 obuf += yuvconvert(ibuf, obuf, out_fmt,
2153 in_uyvy, cam->mmap_kludge);
2157 /* SUBSAMPLE_420 on an odd line */
2158 obuf += convert420(ibuf, obuf,
2165 /*skip compressed interval from previous frame*/
2166 obuf += skipcount(*ibuf >> 1, out_fmt);
2167 if (obuf > end_obuf) {
2168 LOG("Insufficient buffer size\n");
2177 DBG("EOL not found giving up after %d/%d"
2178 " bytes\n", origsize-size, origsize);
2182 ++ibuf; /* skip over EOL */
2184 if ((size > 3) && (ibuf[0] == EOI) && (ibuf[1] == EOI) &&
2185 (ibuf[2] == EOI) && (ibuf[3] == EOI)) {
2191 /* skip the odd lines for now */
2196 ll = ibuf[0] | (ibuf[1] << 8);
2197 ibuf += 2; /* skip over line length */
2200 even_line = !even_line;
2202 LOG("line length was not 1 but %d after %d/%d bytes\n",
2203 ll, origsize-size, origsize);
2209 /* interpolate odd rows */
2212 prev = cam->decompressed_frame.data;
2213 obuf = prev+linesize;
2214 next = obuf+linesize;
2215 for(i=1; i<rows-1; i+=2) {
2216 for(j=0; j<linesize; ++j) {
2217 *obuf++ = ((int)*prev++ + *next++) / 2;
2223 /* last row is odd, just copy previous row */
2224 memcpy(obuf, prev, linesize);
2227 cam->decompressed_frame.count = obuf-cam->decompressed_frame.data;
2229 return cam->decompressed_frame.count;
2232 /* InitStreamCap wrapper to select correct start line */
2233 static inline int init_stream_cap(struct cam_data *cam)
2235 return do_command(cam, CPIA_COMMAND_InitStreamCap,
2236 0, cam->params.streamStartLine, 0, 0);
2240 /* find_over_exposure
2241 * Finds a suitable value of OverExposure for use with SetFlickerCtrl
2242 * Some calculation is required because this value changes with the brightness
2243 * set with SetColourParameters
2245 * Parameters: Brightness - last brightness value set with SetColourParameters
2247 * Returns: OverExposure value to use with SetFlickerCtrl
2249 #define FLICKER_MAX_EXPOSURE 250
2250 #define FLICKER_ALLOWABLE_OVER_EXPOSURE 146
2251 #define FLICKER_BRIGHTNESS_CONSTANT 59
2252 static int find_over_exposure(int brightness)
2254 int MaxAllowableOverExposure, OverExposure;
2256 MaxAllowableOverExposure = FLICKER_MAX_EXPOSURE - brightness -
2257 FLICKER_BRIGHTNESS_CONSTANT;
2259 if (MaxAllowableOverExposure < FLICKER_ALLOWABLE_OVER_EXPOSURE) {
2260 OverExposure = MaxAllowableOverExposure;
2262 OverExposure = FLICKER_ALLOWABLE_OVER_EXPOSURE;
2265 return OverExposure;
2267 #undef FLICKER_MAX_EXPOSURE
2268 #undef FLICKER_ALLOWABLE_OVER_EXPOSURE
2269 #undef FLICKER_BRIGHTNESS_CONSTANT
2271 /* update various camera modes and settings */
2272 static void dispatch_commands(struct cam_data *cam)
2274 down(&cam->param_lock);
2275 if (cam->cmd_queue==COMMAND_NONE) {
2276 up(&cam->param_lock);
2279 DEB_BYTE(cam->cmd_queue);
2280 DEB_BYTE(cam->cmd_queue>>8);
2281 if (cam->cmd_queue & COMMAND_SETFORMAT) {
2282 do_command(cam, CPIA_COMMAND_SetFormat,
2283 cam->params.format.videoSize,
2284 cam->params.format.subSample,
2285 cam->params.format.yuvOrder, 0);
2286 do_command(cam, CPIA_COMMAND_SetROI,
2287 cam->params.roi.colStart, cam->params.roi.colEnd,
2288 cam->params.roi.rowStart, cam->params.roi.rowEnd);
2289 cam->first_frame = 1;
2292 if (cam->cmd_queue & COMMAND_SETCOLOURPARAMS)
2293 do_command(cam, CPIA_COMMAND_SetColourParams,
2294 cam->params.colourParams.brightness,
2295 cam->params.colourParams.contrast,
2296 cam->params.colourParams.saturation, 0);
2298 if (cam->cmd_queue & COMMAND_SETAPCOR)
2299 do_command(cam, CPIA_COMMAND_SetApcor,
2300 cam->params.apcor.gain1,
2301 cam->params.apcor.gain2,
2302 cam->params.apcor.gain4,
2303 cam->params.apcor.gain8);
2305 if (cam->cmd_queue & COMMAND_SETVLOFFSET)
2306 do_command(cam, CPIA_COMMAND_SetVLOffset,
2307 cam->params.vlOffset.gain1,
2308 cam->params.vlOffset.gain2,
2309 cam->params.vlOffset.gain4,
2310 cam->params.vlOffset.gain8);
2312 if (cam->cmd_queue & COMMAND_SETEXPOSURE) {
2313 do_command_extended(cam, CPIA_COMMAND_SetExposure,
2314 cam->params.exposure.gainMode,
2316 cam->params.exposure.compMode,
2317 cam->params.exposure.centreWeight,
2318 cam->params.exposure.gain,
2319 cam->params.exposure.fineExp,
2320 cam->params.exposure.coarseExpLo,
2321 cam->params.exposure.coarseExpHi,
2322 cam->params.exposure.redComp,
2323 cam->params.exposure.green1Comp,
2324 cam->params.exposure.green2Comp,
2325 cam->params.exposure.blueComp);
2326 if(cam->params.exposure.expMode != 1) {
2327 do_command_extended(cam, CPIA_COMMAND_SetExposure,
2329 cam->params.exposure.expMode,
2331 cam->params.exposure.gain,
2332 cam->params.exposure.fineExp,
2333 cam->params.exposure.coarseExpLo,
2334 cam->params.exposure.coarseExpHi,
2339 if (cam->cmd_queue & COMMAND_SETCOLOURBALANCE) {
2340 if (cam->params.colourBalance.balanceMode == 1) {
2341 do_command(cam, CPIA_COMMAND_SetColourBalance,
2343 cam->params.colourBalance.redGain,
2344 cam->params.colourBalance.greenGain,
2345 cam->params.colourBalance.blueGain);
2346 do_command(cam, CPIA_COMMAND_SetColourBalance,
2349 if (cam->params.colourBalance.balanceMode == 2) {
2350 do_command(cam, CPIA_COMMAND_SetColourBalance,
2353 if (cam->params.colourBalance.balanceMode == 3) {
2354 do_command(cam, CPIA_COMMAND_SetColourBalance,
2359 if (cam->cmd_queue & COMMAND_SETCOMPRESSIONTARGET)
2360 do_command(cam, CPIA_COMMAND_SetCompressionTarget,
2361 cam->params.compressionTarget.frTargeting,
2362 cam->params.compressionTarget.targetFR,
2363 cam->params.compressionTarget.targetQ, 0);
2365 if (cam->cmd_queue & COMMAND_SETYUVTHRESH)
2366 do_command(cam, CPIA_COMMAND_SetYUVThresh,
2367 cam->params.yuvThreshold.yThreshold,
2368 cam->params.yuvThreshold.uvThreshold, 0, 0);
2370 if (cam->cmd_queue & COMMAND_SETCOMPRESSIONPARAMS)
2371 do_command_extended(cam, CPIA_COMMAND_SetCompressionParams,
2373 cam->params.compressionParams.hysteresis,
2374 cam->params.compressionParams.threshMax,
2375 cam->params.compressionParams.smallStep,
2376 cam->params.compressionParams.largeStep,
2377 cam->params.compressionParams.decimationHysteresis,
2378 cam->params.compressionParams.frDiffStepThresh,
2379 cam->params.compressionParams.qDiffStepThresh,
2380 cam->params.compressionParams.decimationThreshMod);
2382 if (cam->cmd_queue & COMMAND_SETCOMPRESSION)
2383 do_command(cam, CPIA_COMMAND_SetCompression,
2384 cam->params.compression.mode,
2385 cam->params.compression.decimation, 0, 0);
2387 if (cam->cmd_queue & COMMAND_SETSENSORFPS)
2388 do_command(cam, CPIA_COMMAND_SetSensorFPS,
2389 cam->params.sensorFps.divisor,
2390 cam->params.sensorFps.baserate, 0, 0);
2392 if (cam->cmd_queue & COMMAND_SETFLICKERCTRL)
2393 do_command(cam, CPIA_COMMAND_SetFlickerCtrl,
2394 cam->params.flickerControl.flickerMode,
2395 cam->params.flickerControl.coarseJump,
2396 abs(cam->params.flickerControl.allowableOverExposure),
2399 if (cam->cmd_queue & COMMAND_SETECPTIMING)
2400 do_command(cam, CPIA_COMMAND_SetECPTiming,
2401 cam->params.ecpTiming, 0, 0, 0);
2403 if (cam->cmd_queue & COMMAND_PAUSE)
2404 do_command(cam, CPIA_COMMAND_EndStreamCap, 0, 0, 0, 0);
2406 if (cam->cmd_queue & COMMAND_RESUME)
2407 init_stream_cap(cam);
2409 if (cam->cmd_queue & COMMAND_SETLIGHTS && cam->params.qx3.qx3_detected)
2411 int p1 = (cam->params.qx3.bottomlight == 0) << 1;
2412 int p2 = (cam->params.qx3.toplight == 0) << 3;
2413 do_command(cam, CPIA_COMMAND_WriteVCReg, 0x90, 0x8F, 0x50, 0);
2414 do_command(cam, CPIA_COMMAND_WriteMCPort, 2, 0, (p1|p2|0xE0), 0);
2417 cam->cmd_queue = COMMAND_NONE;
2418 up(&cam->param_lock);
2424 static void set_flicker(struct cam_params *params, volatile u32 *command_flags,
2427 /* Everything in here is from the Windows driver */
2428 #define FIRMWARE_VERSION(x,y) (params->version.firmwareVersion == (x) && \
2429 params->version.firmwareRevision == (y))
2430 /* define for compgain calculation */
2432 #define COMPGAIN(base, curexp, newexp) \
2433 (u8) ((((float) base - 128.0) * ((float) curexp / (float) newexp)) + 128.5)
2434 #define EXP_FROM_COMP(basecomp, curcomp, curexp) \
2435 (u16)((float)curexp * (float)(u8)(curcomp + 128) / (float)(u8)(basecomp - 128))
2437 /* equivalent functions without floating point math */
2438 #define COMPGAIN(base, curexp, newexp) \
2439 (u8)(128 + (((u32)(2*(base-128)*curexp + newexp)) / (2* newexp)) )
2440 #define EXP_FROM_COMP(basecomp, curcomp, curexp) \
2441 (u16)(((u32)(curexp * (u8)(curcomp + 128)) / (u8)(basecomp - 128)))
2445 int currentexp = params->exposure.coarseExpLo +
2446 params->exposure.coarseExpHi*256;
2449 int cj = params->flickerControl.coarseJump;
2450 params->flickerControl.flickerMode = 1;
2451 params->flickerControl.disabled = 0;
2452 if(params->exposure.expMode != 2)
2453 *command_flags |= COMMAND_SETEXPOSURE;
2454 params->exposure.expMode = 2;
2455 currentexp = currentexp << params->exposure.gain;
2456 params->exposure.gain = 0;
2457 /* round down current exposure to nearest value */
2458 startexp = (currentexp + ROUND_UP_EXP_FOR_FLICKER) / cj;
2461 startexp = (startexp * cj) - 1;
2462 if(FIRMWARE_VERSION(1,2))
2463 while(startexp > MAX_EXP_102)
2466 while(startexp > MAX_EXP)
2468 params->exposure.coarseExpLo = startexp & 0xff;
2469 params->exposure.coarseExpHi = startexp >> 8;
2470 if (currentexp > startexp) {
2471 if (currentexp > (2 * startexp))
2472 currentexp = 2 * startexp;
2473 params->exposure.redComp = COMPGAIN (COMP_RED, currentexp, startexp);
2474 params->exposure.green1Comp = COMPGAIN (COMP_GREEN1, currentexp, startexp);
2475 params->exposure.green2Comp = COMPGAIN (COMP_GREEN2, currentexp, startexp);
2476 params->exposure.blueComp = COMPGAIN (COMP_BLUE, currentexp, startexp);
2478 params->exposure.redComp = COMP_RED;
2479 params->exposure.green1Comp = COMP_GREEN1;
2480 params->exposure.green2Comp = COMP_GREEN2;
2481 params->exposure.blueComp = COMP_BLUE;
2483 if(FIRMWARE_VERSION(1,2))
2484 params->exposure.compMode = 0;
2486 params->exposure.compMode = 1;
2488 params->apcor.gain1 = 0x18;
2489 params->apcor.gain2 = 0x18;
2490 params->apcor.gain4 = 0x16;
2491 params->apcor.gain8 = 0x14;
2492 *command_flags |= COMMAND_SETAPCOR;
2494 params->flickerControl.flickerMode = 0;
2495 params->flickerControl.disabled = 1;
2496 /* Coarse = average of equivalent coarse for each comp channel */
2497 startexp = EXP_FROM_COMP(COMP_RED, params->exposure.redComp, currentexp);
2498 startexp += EXP_FROM_COMP(COMP_GREEN1, params->exposure.green1Comp, currentexp);
2499 startexp += EXP_FROM_COMP(COMP_GREEN2, params->exposure.green2Comp, currentexp);
2500 startexp += EXP_FROM_COMP(COMP_BLUE, params->exposure.blueComp, currentexp);
2501 startexp = startexp >> 2;
2502 while(startexp > MAX_EXP &&
2503 params->exposure.gain < params->exposure.gainMode-1) {
2504 startexp = startexp >> 1;
2505 ++params->exposure.gain;
2507 if(FIRMWARE_VERSION(1,2) && startexp > MAX_EXP_102)
2508 startexp = MAX_EXP_102;
2509 if(startexp > MAX_EXP)
2511 params->exposure.coarseExpLo = startexp&0xff;
2512 params->exposure.coarseExpHi = startexp >> 8;
2513 params->exposure.redComp = COMP_RED;
2514 params->exposure.green1Comp = COMP_GREEN1;
2515 params->exposure.green2Comp = COMP_GREEN2;
2516 params->exposure.blueComp = COMP_BLUE;
2517 params->exposure.compMode = 1;
2518 *command_flags |= COMMAND_SETEXPOSURE;
2519 params->apcor.gain1 = 0x18;
2520 params->apcor.gain2 = 0x16;
2521 params->apcor.gain4 = 0x24;
2522 params->apcor.gain8 = 0x34;
2523 *command_flags |= COMMAND_SETAPCOR;
2525 params->vlOffset.gain1 = 20;
2526 params->vlOffset.gain2 = 24;
2527 params->vlOffset.gain4 = 26;
2528 params->vlOffset.gain8 = 26;
2529 *command_flags |= COMMAND_SETVLOFFSET;
2530 #undef FIRMWARE_VERSION
2531 #undef EXP_FROM_COMP
2535 #define FIRMWARE_VERSION(x,y) (cam->params.version.firmwareVersion == (x) && \
2536 cam->params.version.firmwareRevision == (y))
2537 /* monitor the exposure and adjust the sensor frame rate if needed */
2538 static void monitor_exposure(struct cam_data *cam)
2540 u8 exp_acc, bcomp, gain, coarseL, cmd[8], data[8];
2541 int retval, light_exp, dark_exp, very_dark_exp;
2542 int old_exposure, new_exposure, framerate;
2544 /* get necessary stats and register settings from camera */
2545 /* do_command can't handle this, so do it ourselves */
2546 cmd[0] = CPIA_COMMAND_ReadVPRegs>>8;
2547 cmd[1] = CPIA_COMMAND_ReadVPRegs&0xff;
2554 retval = cam->ops->transferCmd(cam->lowlevel_data, cmd, data);
2556 LOG("ReadVPRegs(30,4,9,8) - failed, retval=%d\n",
2565 down(&cam->param_lock);
2566 light_exp = cam->params.colourParams.brightness +
2567 TC - 50 + EXP_ACC_LIGHT;
2570 dark_exp = cam->params.colourParams.brightness +
2571 TC - 50 - EXP_ACC_DARK;
2574 very_dark_exp = dark_exp/2;
2576 old_exposure = cam->params.exposure.coarseExpHi * 256 +
2577 cam->params.exposure.coarseExpLo;
2579 if(!cam->params.flickerControl.disabled) {
2580 /* Flicker control on */
2581 int max_comp = FIRMWARE_VERSION(1,2) ? MAX_COMP : HIGH_COMP_102;
2582 bcomp += 128; /* decode */
2583 if(bcomp >= max_comp && exp_acc < dark_exp) {
2585 if(exp_acc < very_dark_exp) {
2587 if(cam->exposure_status == EXPOSURE_VERY_DARK)
2588 ++cam->exposure_count;
2590 cam->exposure_status = EXPOSURE_VERY_DARK;
2591 cam->exposure_count = 1;
2595 if(cam->exposure_status == EXPOSURE_DARK)
2596 ++cam->exposure_count;
2598 cam->exposure_status = EXPOSURE_DARK;
2599 cam->exposure_count = 1;
2602 } else if(old_exposure <= LOW_EXP || exp_acc > light_exp) {
2604 if(old_exposure <= VERY_LOW_EXP) {
2606 if(cam->exposure_status == EXPOSURE_VERY_LIGHT)
2607 ++cam->exposure_count;
2609 cam->exposure_status = EXPOSURE_VERY_LIGHT;
2610 cam->exposure_count = 1;
2614 if(cam->exposure_status == EXPOSURE_LIGHT)
2615 ++cam->exposure_count;
2617 cam->exposure_status = EXPOSURE_LIGHT;
2618 cam->exposure_count = 1;
2622 /* not dark or light */
2623 cam->exposure_status = EXPOSURE_NORMAL;
2626 /* Flicker control off */
2627 if(old_exposure >= MAX_EXP && exp_acc < dark_exp) {
2629 if(exp_acc < very_dark_exp) {
2631 if(cam->exposure_status == EXPOSURE_VERY_DARK)
2632 ++cam->exposure_count;
2634 cam->exposure_status = EXPOSURE_VERY_DARK;
2635 cam->exposure_count = 1;
2639 if(cam->exposure_status == EXPOSURE_DARK)
2640 ++cam->exposure_count;
2642 cam->exposure_status = EXPOSURE_DARK;
2643 cam->exposure_count = 1;
2646 } else if(old_exposure <= LOW_EXP || exp_acc > light_exp) {
2648 if(old_exposure <= VERY_LOW_EXP) {
2650 if(cam->exposure_status == EXPOSURE_VERY_LIGHT)
2651 ++cam->exposure_count;
2653 cam->exposure_status = EXPOSURE_VERY_LIGHT;
2654 cam->exposure_count = 1;
2658 if(cam->exposure_status == EXPOSURE_LIGHT)
2659 ++cam->exposure_count;
2661 cam->exposure_status = EXPOSURE_LIGHT;
2662 cam->exposure_count = 1;
2666 /* not dark or light */
2667 cam->exposure_status = EXPOSURE_NORMAL;
2671 framerate = cam->fps;
2672 if(framerate > 30 || framerate < 1)
2675 if(!cam->params.flickerControl.disabled) {
2676 /* Flicker control on */
2677 if((cam->exposure_status == EXPOSURE_VERY_DARK ||
2678 cam->exposure_status == EXPOSURE_DARK) &&
2679 cam->exposure_count >= DARK_TIME*framerate &&
2680 cam->params.sensorFps.divisor < 3) {
2682 /* dark for too long */
2683 ++cam->params.sensorFps.divisor;
2684 cam->cmd_queue |= COMMAND_SETSENSORFPS;
2686 cam->params.flickerControl.coarseJump =
2687 flicker_jumps[cam->mainsFreq]
2688 [cam->params.sensorFps.baserate]
2689 [cam->params.sensorFps.divisor];
2690 cam->cmd_queue |= COMMAND_SETFLICKERCTRL;
2692 new_exposure = cam->params.flickerControl.coarseJump-1;
2693 while(new_exposure < old_exposure/2)
2694 new_exposure += cam->params.flickerControl.coarseJump;
2695 cam->params.exposure.coarseExpLo = new_exposure & 0xff;
2696 cam->params.exposure.coarseExpHi = new_exposure >> 8;
2697 cam->cmd_queue |= COMMAND_SETEXPOSURE;
2698 cam->exposure_status = EXPOSURE_NORMAL;
2699 LOG("Automatically decreasing sensor_fps\n");
2701 } else if((cam->exposure_status == EXPOSURE_VERY_LIGHT ||
2702 cam->exposure_status == EXPOSURE_LIGHT) &&
2703 cam->exposure_count >= LIGHT_TIME*framerate &&
2704 cam->params.sensorFps.divisor > 0) {
2706 /* light for too long */
2707 int max_exp = FIRMWARE_VERSION(1,2) ? MAX_EXP_102 : MAX_EXP ;
2709 --cam->params.sensorFps.divisor;
2710 cam->cmd_queue |= COMMAND_SETSENSORFPS;
2712 cam->params.flickerControl.coarseJump =
2713 flicker_jumps[cam->mainsFreq]
2714 [cam->params.sensorFps.baserate]
2715 [cam->params.sensorFps.divisor];
2716 cam->cmd_queue |= COMMAND_SETFLICKERCTRL;
2718 new_exposure = cam->params.flickerControl.coarseJump-1;
2719 while(new_exposure < 2*old_exposure &&
2721 cam->params.flickerControl.coarseJump < max_exp)
2722 new_exposure += cam->params.flickerControl.coarseJump;
2723 cam->params.exposure.coarseExpLo = new_exposure & 0xff;
2724 cam->params.exposure.coarseExpHi = new_exposure >> 8;
2725 cam->cmd_queue |= COMMAND_SETEXPOSURE;
2726 cam->exposure_status = EXPOSURE_NORMAL;
2727 LOG("Automatically increasing sensor_fps\n");
2730 /* Flicker control off */
2731 if((cam->exposure_status == EXPOSURE_VERY_DARK ||
2732 cam->exposure_status == EXPOSURE_DARK) &&
2733 cam->exposure_count >= DARK_TIME*framerate &&
2734 cam->params.sensorFps.divisor < 3) {
2736 /* dark for too long */
2737 ++cam->params.sensorFps.divisor;
2738 cam->cmd_queue |= COMMAND_SETSENSORFPS;
2740 if(cam->params.exposure.gain > 0) {
2741 --cam->params.exposure.gain;
2742 cam->cmd_queue |= COMMAND_SETEXPOSURE;
2744 cam->exposure_status = EXPOSURE_NORMAL;
2745 LOG("Automatically decreasing sensor_fps\n");
2747 } else if((cam->exposure_status == EXPOSURE_VERY_LIGHT ||
2748 cam->exposure_status == EXPOSURE_LIGHT) &&
2749 cam->exposure_count >= LIGHT_TIME*framerate &&
2750 cam->params.sensorFps.divisor > 0) {
2752 /* light for too long */
2753 --cam->params.sensorFps.divisor;
2754 cam->cmd_queue |= COMMAND_SETSENSORFPS;
2756 if(cam->params.exposure.gain <
2757 cam->params.exposure.gainMode-1) {
2758 ++cam->params.exposure.gain;
2759 cam->cmd_queue |= COMMAND_SETEXPOSURE;
2761 cam->exposure_status = EXPOSURE_NORMAL;
2762 LOG("Automatically increasing sensor_fps\n");
2765 up(&cam->param_lock);
2768 /*-----------------------------------------------------------------*/
2769 /* if flicker is switched off, this function switches it back on.It checks,
2770 however, that conditions are suitable before restarting it.
2771 This should only be called for firmware version 1.2.
2773 It also adjust the colour balance when an exposure step is detected - as
2774 long as flicker is running
2776 static void restart_flicker(struct cam_data *cam)
2778 int cam_exposure, old_exp;
2779 if(!FIRMWARE_VERSION(1,2))
2781 down(&cam->param_lock);
2782 if(cam->params.flickerControl.flickerMode == 0 ||
2783 cam->raw_image[39] == 0) {
2784 up(&cam->param_lock);
2787 cam_exposure = cam->raw_image[39]*2;
2788 old_exp = cam->params.exposure.coarseExpLo +
2789 cam->params.exposure.coarseExpHi*256;
2791 see how far away camera exposure is from a valid
2792 flicker exposure value
2794 cam_exposure %= cam->params.flickerControl.coarseJump;
2795 if(!cam->params.flickerControl.disabled &&
2796 cam_exposure <= cam->params.flickerControl.coarseJump - 3) {
2797 /* Flicker control auto-disabled */
2798 cam->params.flickerControl.disabled = 1;
2801 if(cam->params.flickerControl.disabled &&
2802 cam->params.flickerControl.flickerMode &&
2803 old_exp > cam->params.flickerControl.coarseJump +
2804 ROUND_UP_EXP_FOR_FLICKER) {
2805 /* exposure is now high enough to switch
2806 flicker control back on */
2807 set_flicker(&cam->params, &cam->cmd_queue, 1);
2808 if((cam->cmd_queue & COMMAND_SETEXPOSURE) &&
2809 cam->params.exposure.expMode == 2)
2810 cam->exposure_status = EXPOSURE_NORMAL;
2813 up(&cam->param_lock);
2815 #undef FIRMWARE_VERSION
2817 static int clear_stall(struct cam_data *cam)
2819 /* FIXME: Does this actually work? */
2820 LOG("Clearing stall\n");
2822 cam->ops->streamRead(cam->lowlevel_data, cam->raw_image, 0);
2823 do_command(cam, CPIA_COMMAND_GetCameraStatus,0,0,0,0);
2824 return cam->params.status.streamState != STREAM_PAUSED;
2827 /* kernel thread function to read image from camera */
2828 static int fetch_frame(void *data)
2830 int image_size, retry;
2831 struct cam_data *cam = (struct cam_data *)data;
2832 unsigned long oldjif, rate, diff;
2834 /* Allow up to two bad images in a row to be read and
2835 * ignored before an error is reported */
2836 for (retry = 0; retry < 3; ++retry) {
2838 DBG("retry=%d\n", retry);
2843 /* load first frame always uncompressed */
2844 if (cam->first_frame &&
2845 cam->params.compression.mode != CPIA_COMPRESSION_NONE) {
2846 do_command(cam, CPIA_COMMAND_SetCompression,
2847 CPIA_COMPRESSION_NONE,
2848 NO_DECIMATION, 0, 0);
2849 /* Trial & error - Discarding a frame prevents the
2850 first frame from having an error in the data. */
2851 do_command(cam, CPIA_COMMAND_DiscardFrame, 0, 0, 0, 0);
2854 /* init camera upload */
2855 if (do_command(cam, CPIA_COMMAND_GrabFrame, 0,
2856 cam->params.streamStartLine, 0, 0))
2859 if (cam->ops->wait_for_stream_ready) {
2860 /* loop until image ready */
2862 do_command(cam, CPIA_COMMAND_GetCameraStatus,0,0,0,0);
2863 while (cam->params.status.streamState != STREAM_READY) {
2864 if(++count > READY_TIMEOUT)
2866 if(cam->params.status.streamState ==
2869 if(!clear_stall(cam))
2875 /* sleep for 10 ms, hopefully ;) */
2876 msleep_interruptible(10);
2877 if (signal_pending(current))
2880 do_command(cam, CPIA_COMMAND_GetCameraStatus,
2883 if(cam->params.status.streamState != STREAM_READY) {
2890 /* grab image from camera */
2892 image_size = cam->ops->streamRead(cam->lowlevel_data,
2894 if (image_size <= 0) {
2895 DBG("streamRead failed: %d\n", image_size);
2899 rate = image_size * HZ / 1024;
2900 diff = jiffies-oldjif;
2901 cam->transfer_rate = diff==0 ? rate : rate/diff;
2902 /* diff==0 ? unlikely but possible */
2904 /* Switch flicker control back on if it got turned off */
2905 restart_flicker(cam);
2907 /* If AEC is enabled, monitor the exposure and
2908 adjust the sensor frame rate if needed */
2909 if(cam->params.exposure.expMode == 2)
2910 monitor_exposure(cam);
2912 /* camera idle now so dispatch queued commands */
2913 dispatch_commands(cam);
2915 /* Update our knowledge of the camera state */
2916 do_command(cam, CPIA_COMMAND_GetColourBalance, 0, 0, 0, 0);
2917 do_command(cam, CPIA_COMMAND_GetExposure, 0, 0, 0, 0);
2918 do_command(cam, CPIA_COMMAND_ReadMCPorts, 0, 0, 0, 0);
2920 /* decompress and convert image to by copying it from
2921 * raw_image to decompressed_frame
2926 cam->image_size = parse_picture(cam, image_size);
2927 if (cam->image_size <= 0) {
2928 DBG("parse_picture failed %d\n", cam->image_size);
2929 if(cam->params.compression.mode !=
2930 CPIA_COMPRESSION_NONE) {
2931 /* Compression may not work right if we
2932 had a bad frame, get the next one
2934 cam->first_frame = 1;
2935 do_command(cam, CPIA_COMMAND_SetGrabMode,
2936 CPIA_GRAB_SINGLE, 0, 0, 0);
2937 /* FIXME: Trial & error - need up to 70ms for
2938 the grab mode change to complete ? */
2939 msleep_interruptible(70);
2940 if (signal_pending(current))
2948 /* FIXME: this only works for double buffering */
2949 if (cam->frame[cam->curframe].state == FRAME_READY) {
2950 memcpy(cam->frame[cam->curframe].data,
2951 cam->decompressed_frame.data,
2952 cam->decompressed_frame.count);
2953 cam->frame[cam->curframe].state = FRAME_DONE;
2955 cam->decompressed_frame.state = FRAME_DONE;
2957 if (cam->first_frame) {
2958 cam->first_frame = 0;
2959 do_command(cam, CPIA_COMMAND_SetCompression,
2960 cam->params.compression.mode,
2961 cam->params.compression.decimation, 0, 0);
2963 /* Switch from single-grab to continuous grab */
2964 do_command(cam, CPIA_COMMAND_SetGrabMode,
2965 CPIA_GRAB_CONTINUOUS, 0, 0, 0);
2972 static int capture_frame(struct cam_data *cam, struct video_mmap *vm)
2974 if (!cam->frame_buf) {
2975 /* we do lazy allocation */
2977 if ((err = allocate_frame_buf(cam)))
2981 cam->curframe = vm->frame;
2982 cam->frame[cam->curframe].state = FRAME_READY;
2983 return fetch_frame(cam);
2986 static int goto_high_power(struct cam_data *cam)
2988 if (do_command(cam, CPIA_COMMAND_GotoHiPower, 0, 0, 0, 0))
2990 msleep_interruptible(40); /* windows driver does it too */
2991 if(signal_pending(current))
2993 if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0))
2995 if (cam->params.status.systemState == HI_POWER_STATE) {
2996 DBG("camera now in HIGH power state\n");
3003 static int goto_low_power(struct cam_data *cam)
3005 if (do_command(cam, CPIA_COMMAND_GotoLoPower, 0, 0, 0, 0))
3007 if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0))
3009 if (cam->params.status.systemState == LO_POWER_STATE) {
3010 DBG("camera now in LOW power state\n");
3017 static void save_camera_state(struct cam_data *cam)
3019 if(!(cam->cmd_queue & COMMAND_SETCOLOURBALANCE))
3020 do_command(cam, CPIA_COMMAND_GetColourBalance, 0, 0, 0, 0);
3021 if(!(cam->cmd_queue & COMMAND_SETEXPOSURE))
3022 do_command(cam, CPIA_COMMAND_GetExposure, 0, 0, 0, 0);
3024 DBG("%d/%d/%d/%d/%d/%d/%d/%d\n",
3025 cam->params.exposure.gain,
3026 cam->params.exposure.fineExp,
3027 cam->params.exposure.coarseExpLo,
3028 cam->params.exposure.coarseExpHi,
3029 cam->params.exposure.redComp,
3030 cam->params.exposure.green1Comp,
3031 cam->params.exposure.green2Comp,
3032 cam->params.exposure.blueComp);
3034 cam->params.colourBalance.redGain,
3035 cam->params.colourBalance.greenGain,
3036 cam->params.colourBalance.blueGain);
3039 static int set_camera_state(struct cam_data *cam)
3041 cam->cmd_queue = COMMAND_SETCOMPRESSION |
3042 COMMAND_SETCOMPRESSIONTARGET |
3043 COMMAND_SETCOLOURPARAMS |
3045 COMMAND_SETYUVTHRESH |
3046 COMMAND_SETECPTIMING |
3047 COMMAND_SETCOMPRESSIONPARAMS |
3048 COMMAND_SETEXPOSURE |
3049 COMMAND_SETCOLOURBALANCE |
3050 COMMAND_SETSENSORFPS |
3052 COMMAND_SETFLICKERCTRL |
3053 COMMAND_SETVLOFFSET;
3055 do_command(cam, CPIA_COMMAND_SetGrabMode, CPIA_GRAB_SINGLE,0,0,0);
3056 dispatch_commands(cam);
3058 /* Wait 6 frames for the sensor to get all settings and
3059 AEC/ACB to settle */
3060 msleep_interruptible(6*(cam->params.sensorFps.baserate ? 33 : 40) *
3061 (1 << cam->params.sensorFps.divisor) + 10);
3063 if(signal_pending(current))
3066 save_camera_state(cam);
3071 static void get_version_information(struct cam_data *cam)
3073 /* GetCPIAVersion */
3074 do_command(cam, CPIA_COMMAND_GetCPIAVersion, 0, 0, 0, 0);
3077 do_command(cam, CPIA_COMMAND_GetPnPID, 0, 0, 0, 0);
3080 /* initialize camera */
3081 static int reset_camera(struct cam_data *cam)
3084 /* Start the camera in low power mode */
3085 if (goto_low_power(cam)) {
3086 if (cam->params.status.systemState != WARM_BOOT_STATE)
3089 /* FIXME: this is just dirty trial and error */
3090 err = goto_high_power(cam);
3093 do_command(cam, CPIA_COMMAND_DiscardFrame, 0, 0, 0, 0);
3094 if (goto_low_power(cam))
3098 /* procedure described in developer's guide p3-28 */
3100 /* Check the firmware version. */
3101 cam->params.version.firmwareVersion = 0;
3102 get_version_information(cam);
3103 if (cam->params.version.firmwareVersion != 1)
3106 /* A bug in firmware 1-02 limits gainMode to 2 */
3107 if(cam->params.version.firmwareRevision <= 2 &&
3108 cam->params.exposure.gainMode > 2) {
3109 cam->params.exposure.gainMode = 2;
3112 /* set QX3 detected flag */
3113 cam->params.qx3.qx3_detected = (cam->params.pnpID.vendor == 0x0813 &&
3114 cam->params.pnpID.product == 0x0001);
3116 /* The fatal error checking should be done after
3117 * the camera powers up (developer's guide p 3-38) */
3119 /* Set streamState before transition to high power to avoid bug
3120 * in firmware 1-02 */
3121 do_command(cam, CPIA_COMMAND_ModifyCameraStatus, STREAMSTATE, 0,
3122 STREAM_NOT_READY, 0);
3125 err = goto_high_power(cam);
3129 /* Check the camera status */
3130 if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0))
3133 if (cam->params.status.fatalError) {
3134 DBG("fatal_error: %#04x\n",
3135 cam->params.status.fatalError);
3136 DBG("vp_status: %#04x\n",
3137 cam->params.status.vpStatus);
3138 if (cam->params.status.fatalError & ~(COM_FLAG|CPIA_FLAG)) {
3139 /* Fatal error in camera */
3141 } else if (cam->params.status.fatalError & (COM_FLAG|CPIA_FLAG)) {
3142 /* Firmware 1-02 may do this for parallel port cameras,
3143 * just clear the flags (developer's guide p 3-38) */
3144 do_command(cam, CPIA_COMMAND_ModifyCameraStatus,
3145 FATALERROR, ~(COM_FLAG|CPIA_FLAG), 0, 0);
3149 /* Check the camera status again */
3150 if (cam->params.status.fatalError) {
3151 if (cam->params.status.fatalError)
3155 /* VPVersion can't be retrieved before the camera is in HiPower,
3156 * so get it here instead of in get_version_information. */
3157 do_command(cam, CPIA_COMMAND_GetVPVersion, 0, 0, 0, 0);
3159 /* set camera to a known state */
3160 return set_camera_state(cam);
3163 static void put_cam(struct cpia_camera_ops* ops)
3166 module_put(ops->owner);
3169 /* ------------------------- V4L interface --------------------- */
3170 static int cpia_open(struct inode *inode, struct file *file)
3172 struct video_device *dev = video_devdata(file);
3173 struct cam_data *cam = dev->priv;
3177 DBG("Internal error, cam_data not found!\n");
3181 if (cam->open_count > 0) {
3182 DBG("Camera already open\n");
3186 if (!try_module_get(cam->ops->owner))
3189 down(&cam->busy_lock);
3191 if (!cam->raw_image) {
3192 cam->raw_image = rvmalloc(CPIA_MAX_IMAGE_SIZE);
3193 if (!cam->raw_image)
3197 if (!cam->decompressed_frame.data) {
3198 cam->decompressed_frame.data = rvmalloc(CPIA_MAX_FRAME_SIZE);
3199 if (!cam->decompressed_frame.data)
3205 if (cam->ops->open(cam->lowlevel_data))
3208 /* reset the camera */
3209 if ((err = reset_camera(cam)) != 0) {
3210 cam->ops->close(cam->lowlevel_data);
3215 if(signal_pending(current))
3218 /* Set ownership of /proc/cpia/videoX to current user */
3220 cam->proc_entry->uid = current->uid;
3222 /* set mark for loading first frame uncompressed */
3223 cam->first_frame = 1;
3225 /* init it to something */
3226 cam->mmap_kludge = 0;
3229 file->private_data = dev;
3230 up(&cam->busy_lock);
3234 if (cam->decompressed_frame.data) {
3235 rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE);
3236 cam->decompressed_frame.data = NULL;
3238 if (cam->raw_image) {
3239 rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
3240 cam->raw_image = NULL;
3242 up(&cam->busy_lock);
3247 static int cpia_close(struct inode *inode, struct file *file)
3249 struct video_device *dev = file->private_data;
3250 struct cam_data *cam = dev->priv;
3253 /* Return ownership of /proc/cpia/videoX to root */
3255 cam->proc_entry->uid = 0;
3257 /* save camera state for later open (developers guide ch 3.5.3) */
3258 save_camera_state(cam);
3261 goto_low_power(cam);
3263 /* Update the camera status */
3264 do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0);
3266 /* cleanup internal state stuff */
3267 free_frames(cam->frame);
3270 cam->ops->close(cam->lowlevel_data);
3275 if (--cam->open_count == 0) {
3276 /* clean up capture-buffers */
3277 if (cam->raw_image) {
3278 rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
3279 cam->raw_image = NULL;
3282 if (cam->decompressed_frame.data) {
3283 rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE);
3284 cam->decompressed_frame.data = NULL;
3288 free_frame_buf(cam);
3293 file->private_data = NULL;
3298 static ssize_t cpia_read(struct file *file, char __user *buf,
3299 size_t count, loff_t *ppos)
3301 struct video_device *dev = file->private_data;
3302 struct cam_data *cam = dev->priv;
3305 /* make this _really_ smp and multithread-safe */
3306 if (down_interruptible(&cam->busy_lock))
3311 up(&cam->busy_lock);
3317 up(&cam->busy_lock);
3323 up(&cam->busy_lock);
3328 cam->decompressed_frame.state = FRAME_READY;
3330 if((err = fetch_frame(cam)) != 0) {
3331 DBG("ERROR from fetch_frame: %d\n", err);
3332 up(&cam->busy_lock);
3335 cam->decompressed_frame.state = FRAME_UNUSED;
3337 /* copy data to user space */
3338 if (cam->decompressed_frame.count > count) {
3339 DBG("count wrong: %d, %lu\n", cam->decompressed_frame.count,
3340 (unsigned long) count);
3341 up(&cam->busy_lock);
3344 if (copy_to_user(buf, cam->decompressed_frame.data,
3345 cam->decompressed_frame.count)) {
3346 DBG("copy_to_user failed\n");
3347 up(&cam->busy_lock);
3351 up(&cam->busy_lock);
3352 return cam->decompressed_frame.count;
3355 static int cpia_do_ioctl(struct inode *inode, struct file *file,
3356 unsigned int ioctlnr, void *arg)
3358 struct video_device *dev = file->private_data;
3359 struct cam_data *cam = dev->priv;
3362 if (!cam || !cam->ops)
3365 /* make this _really_ smp-safe */
3366 if (down_interruptible(&cam->busy_lock))
3369 //DBG("cpia_ioctl: %u\n", ioctlnr);
3372 /* query capabilites */
3375 struct video_capability *b = arg;
3377 DBG("VIDIOCGCAP\n");
3378 strcpy(b->name, "CPiA Camera");
3379 b->type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE;
3382 b->maxwidth = 352; /* VIDEOSIZE_CIF */
3384 b->minwidth = 48; /* VIDEOSIZE_48_48 */
3389 /* get/set video source - we are a camera and nothing else */
3392 struct video_channel *v = arg;
3394 DBG("VIDIOCGCHAN\n");
3395 if (v->channel != 0) {
3401 strcpy(v->name, "Camera");
3404 v->type = VIDEO_TYPE_CAMERA;
3411 struct video_channel *v = arg;
3413 DBG("VIDIOCSCHAN\n");
3414 if (v->channel != 0)
3419 /* image properties */
3422 struct video_picture *pic = arg;
3423 DBG("VIDIOCGPICT\n");
3430 struct video_picture *vp = arg;
3432 DBG("VIDIOCSPICT\n");
3434 /* check validity */
3435 DBG("palette: %d\n", vp->palette);
3436 DBG("depth: %d\n", vp->depth);
3437 if (!valid_mode(vp->palette, vp->depth)) {
3442 down(&cam->param_lock);
3443 /* brightness, colour, contrast need no check 0-65535 */
3445 /* update cam->params.colourParams */
3446 cam->params.colourParams.brightness = vp->brightness*100/65535;
3447 cam->params.colourParams.contrast = vp->contrast*100/65535;
3448 cam->params.colourParams.saturation = vp->colour*100/65535;
3449 /* contrast is in steps of 8, so round */
3450 cam->params.colourParams.contrast =
3451 ((cam->params.colourParams.contrast + 3) / 8) * 8;
3452 if (cam->params.version.firmwareVersion == 1 &&
3453 cam->params.version.firmwareRevision == 2 &&
3454 cam->params.colourParams.contrast > 80) {
3455 /* 1-02 firmware limits contrast to 80 */
3456 cam->params.colourParams.contrast = 80;
3459 /* Adjust flicker control if necessary */
3460 if(cam->params.flickerControl.allowableOverExposure < 0)
3461 cam->params.flickerControl.allowableOverExposure =
3462 -find_over_exposure(cam->params.colourParams.brightness);
3463 if(cam->params.flickerControl.flickerMode != 0)
3464 cam->cmd_queue |= COMMAND_SETFLICKERCTRL;
3467 /* queue command to update camera */
3468 cam->cmd_queue |= COMMAND_SETCOLOURPARAMS;
3469 up(&cam->param_lock);
3470 DBG("VIDIOCSPICT: %d / %d // %d / %d / %d / %d\n",
3471 vp->depth, vp->palette, vp->brightness, vp->hue, vp->colour,
3476 /* get/set capture window */
3479 struct video_window *vw = arg;
3480 DBG("VIDIOCGWIN\n");
3488 /* copy_from_user, check validity, copy to internal structure */
3489 struct video_window *vw = arg;
3490 DBG("VIDIOCSWIN\n");
3492 if (vw->clipcount != 0) { /* clipping not supported */
3496 if (vw->clips != NULL) { /* clipping not supported */
3501 /* we set the video window to something smaller or equal to what
3502 * is requested by the user???
3504 down(&cam->param_lock);
3505 if (vw->width != cam->vw.width || vw->height != cam->vw.height) {
3506 int video_size = match_videosize(vw->width, vw->height);
3508 if (video_size < 0) {
3510 up(&cam->param_lock);
3513 cam->video_size = video_size;
3515 /* video size is changing, reset the subcapture area */
3516 memset(&cam->vc, 0, sizeof(cam->vc));
3519 DBG("%d / %d\n", cam->vw.width, cam->vw.height);
3520 cam->cmd_queue |= COMMAND_SETFORMAT;
3523 up(&cam->param_lock);
3525 /* setformat ignored by camera during streaming,
3526 * so stop/dispatch/start */
3527 if (cam->cmd_queue & COMMAND_SETFORMAT) {
3529 dispatch_commands(cam);
3531 DBG("%d/%d:%d\n", cam->video_size,
3532 cam->vw.width, cam->vw.height);
3536 /* mmap interface */
3539 struct video_mbuf *vm = arg;
3542 DBG("VIDIOCGMBUF\n");
3543 memset(vm, 0, sizeof(*vm));
3544 vm->size = CPIA_MAX_FRAME_SIZE*FRAME_NUM;
3545 vm->frames = FRAME_NUM;
3546 for (i = 0; i < FRAME_NUM; i++)
3547 vm->offsets[i] = CPIA_MAX_FRAME_SIZE * i;
3551 case VIDIOCMCAPTURE:
3553 struct video_mmap *vm = arg;
3556 DBG("VIDIOCMCAPTURE: %d / %d / %dx%d\n", vm->format, vm->frame,
3557 vm->width, vm->height);
3558 if (vm->frame<0||vm->frame>=FRAME_NUM) {
3563 /* set video format */
3564 cam->vp.palette = vm->format;
3565 switch(vm->format) {
3566 case VIDEO_PALETTE_GREY:
3569 case VIDEO_PALETTE_RGB555:
3570 case VIDEO_PALETTE_RGB565:
3571 case VIDEO_PALETTE_YUV422:
3572 case VIDEO_PALETTE_YUYV:
3573 case VIDEO_PALETTE_UYVY:
3576 case VIDEO_PALETTE_RGB24:
3579 case VIDEO_PALETTE_RGB32:
3589 /* set video size */
3590 video_size = match_videosize(vm->width, vm->height);
3591 if (video_size < 0) {
3595 if (video_size != cam->video_size) {
3596 cam->video_size = video_size;
3598 /* video size is changing, reset the subcapture area */
3599 memset(&cam->vc, 0, sizeof(cam->vc));
3602 cam->cmd_queue |= COMMAND_SETFORMAT;
3603 dispatch_commands(cam);
3605 /* according to v4l-spec we must start streaming here */
3606 cam->mmap_kludge = 1;
3607 retval = capture_frame(cam, vm);
3616 //DBG("VIDIOCSYNC: %d\n", *frame);
3618 if (*frame<0 || *frame >= FRAME_NUM) {
3623 switch (cam->frame[*frame].state) {
3626 case FRAME_GRABBING:
3627 DBG("sync to unused frame %d\n", *frame);
3632 cam->frame[*frame].state = FRAME_UNUSED;
3633 //DBG("VIDIOCSYNC: %d synced\n", *frame);
3636 if (retval == -EINTR) {
3637 /* FIXME - xawtv does not handle this nice */
3643 case VIDIOCGCAPTURE:
3645 struct video_capture *vc = arg;
3647 DBG("VIDIOCGCAPTURE\n");
3654 case VIDIOCSCAPTURE:
3656 struct video_capture *vc = arg;
3658 DBG("VIDIOCSCAPTURE\n");
3660 if (vc->decimation != 0) { /* How should this be used? */
3664 if (vc->flags != 0) { /* Even/odd grab not supported */
3669 /* Clip to the resolution we can set for the ROI
3670 (every 8 columns and 4 rows) */
3671 vc->x = vc->x & ~(__u32)7;
3672 vc->y = vc->y & ~(__u32)3;
3673 vc->width = vc->width & ~(__u32)7;
3674 vc->height = vc->height & ~(__u32)3;
3676 if(vc->width == 0 || vc->height == 0 ||
3677 vc->x + vc->width > cam->vw.width ||
3678 vc->y + vc->height > cam->vw.height) {
3683 DBG("%d,%d/%dx%d\n", vc->x,vc->y,vc->width, vc->height);
3685 down(&cam->param_lock);
3689 cam->vc.width = vc->width;
3690 cam->vc.height = vc->height;
3693 cam->cmd_queue |= COMMAND_SETFORMAT;
3695 up(&cam->param_lock);
3697 /* setformat ignored by camera during streaming,
3698 * so stop/dispatch/start */
3699 dispatch_commands(cam);
3705 struct video_unit *vu = arg;
3707 DBG("VIDIOCGUNIT\n");
3709 vu->video = cam->vdev.minor;
3710 vu->vbi = VIDEO_NO_UNIT;
3711 vu->radio = VIDEO_NO_UNIT;
3712 vu->audio = VIDEO_NO_UNIT;
3713 vu->teletext = VIDEO_NO_UNIT;
3719 /* pointless to implement overlay with this camera */
3724 /* tuner interface - we have none */
3729 /* audio interface - we have none */
3735 retval = -ENOIOCTLCMD;
3739 up(&cam->busy_lock);
3743 static int cpia_ioctl(struct inode *inode, struct file *file,
3744 unsigned int cmd, unsigned long arg)
3746 return video_usercopy(inode, file, cmd, arg, cpia_do_ioctl);
3751 static int cpia_mmap(struct file *file, struct vm_area_struct *vma)
3753 struct video_device *dev = file->private_data;
3754 unsigned long start = vma->vm_start;
3755 unsigned long size = vma->vm_end - vma->vm_start;
3756 unsigned long page, pos;
3757 struct cam_data *cam = dev->priv;
3760 if (!cam || !cam->ops)
3763 DBG("cpia_mmap: %ld\n", size);
3765 if (size > FRAME_NUM*CPIA_MAX_FRAME_SIZE)
3768 if (!cam || !cam->ops)
3771 /* make this _really_ smp-safe */
3772 if (down_interruptible(&cam->busy_lock))
3775 if (!cam->frame_buf) { /* we do lazy allocation */
3776 if ((retval = allocate_frame_buf(cam))) {
3777 up(&cam->busy_lock);
3782 pos = (unsigned long)(cam->frame_buf);
3784 page = vmalloc_to_pfn((void *)pos);
3785 if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
3786 up(&cam->busy_lock);
3791 if (size > PAGE_SIZE)
3797 DBG("cpia_mmap: %ld\n", size);
3798 up(&cam->busy_lock);
3803 static struct file_operations cpia_fops = {
3804 .owner = THIS_MODULE,
3806 .release = cpia_close,
3809 .ioctl = cpia_ioctl,
3810 .llseek = no_llseek,
3813 static struct video_device cpia_template = {
3814 .owner = THIS_MODULE,
3815 .name = "CPiA Camera",
3816 .type = VID_TYPE_CAPTURE,
3817 .hardware = VID_HARDWARE_CPIA,
3821 /* initialise cam_data structure */
3822 static void reset_camera_struct(struct cam_data *cam)
3824 /* The following parameter values are the defaults from
3825 * "Software Developer's Guide for CPiA Cameras". Any changes
3826 * to the defaults are noted in comments. */
3827 cam->params.colourParams.brightness = 50;
3828 cam->params.colourParams.contrast = 48;
3829 cam->params.colourParams.saturation = 50;
3830 cam->params.exposure.gainMode = 4;
3831 cam->params.exposure.expMode = 2; /* AEC */
3832 cam->params.exposure.compMode = 1;
3833 cam->params.exposure.centreWeight = 1;
3834 cam->params.exposure.gain = 0;
3835 cam->params.exposure.fineExp = 0;
3836 cam->params.exposure.coarseExpLo = 185;
3837 cam->params.exposure.coarseExpHi = 0;
3838 cam->params.exposure.redComp = COMP_RED;
3839 cam->params.exposure.green1Comp = COMP_GREEN1;
3840 cam->params.exposure.green2Comp = COMP_GREEN2;
3841 cam->params.exposure.blueComp = COMP_BLUE;
3842 cam->params.colourBalance.balanceMode = 2; /* ACB */
3843 cam->params.colourBalance.redGain = 32;
3844 cam->params.colourBalance.greenGain = 6;
3845 cam->params.colourBalance.blueGain = 92;
3846 cam->params.apcor.gain1 = 0x18;
3847 cam->params.apcor.gain2 = 0x16;
3848 cam->params.apcor.gain4 = 0x24;
3849 cam->params.apcor.gain8 = 0x34;
3850 cam->params.flickerControl.flickerMode = 0;
3851 cam->params.flickerControl.disabled = 1;
3853 cam->params.flickerControl.coarseJump =
3854 flicker_jumps[cam->mainsFreq]
3855 [cam->params.sensorFps.baserate]
3856 [cam->params.sensorFps.divisor];
3857 cam->params.flickerControl.allowableOverExposure =
3858 -find_over_exposure(cam->params.colourParams.brightness);
3859 cam->params.vlOffset.gain1 = 20;
3860 cam->params.vlOffset.gain2 = 24;
3861 cam->params.vlOffset.gain4 = 26;
3862 cam->params.vlOffset.gain8 = 26;
3863 cam->params.compressionParams.hysteresis = 3;
3864 cam->params.compressionParams.threshMax = 11;
3865 cam->params.compressionParams.smallStep = 1;
3866 cam->params.compressionParams.largeStep = 3;
3867 cam->params.compressionParams.decimationHysteresis = 2;
3868 cam->params.compressionParams.frDiffStepThresh = 5;
3869 cam->params.compressionParams.qDiffStepThresh = 3;
3870 cam->params.compressionParams.decimationThreshMod = 2;
3871 /* End of default values from Software Developer's Guide */
3873 cam->transfer_rate = 0;
3874 cam->exposure_status = EXPOSURE_NORMAL;
3876 /* Set Sensor FPS to 15fps. This seems better than 30fps
3877 * for indoor lighting. */
3878 cam->params.sensorFps.divisor = 1;
3879 cam->params.sensorFps.baserate = 1;
3881 cam->params.yuvThreshold.yThreshold = 6; /* From windows driver */
3882 cam->params.yuvThreshold.uvThreshold = 6; /* From windows driver */
3884 cam->params.format.subSample = SUBSAMPLE_422;
3885 cam->params.format.yuvOrder = YUVORDER_YUYV;
3887 cam->params.compression.mode = CPIA_COMPRESSION_AUTO;
3888 cam->params.compressionTarget.frTargeting =
3889 CPIA_COMPRESSION_TARGET_QUALITY;
3890 cam->params.compressionTarget.targetFR = 15; /* From windows driver */
3891 cam->params.compressionTarget.targetQ = 5; /* From windows driver */
3893 cam->params.qx3.qx3_detected = 0;
3894 cam->params.qx3.toplight = 0;
3895 cam->params.qx3.bottomlight = 0;
3896 cam->params.qx3.button = 0;
3897 cam->params.qx3.cradled = 0;
3899 cam->video_size = VIDEOSIZE_CIF;
3901 cam->vp.colour = 32768; /* 50% */
3902 cam->vp.hue = 32768; /* 50% */
3903 cam->vp.brightness = 32768; /* 50% */
3904 cam->vp.contrast = 32768; /* 50% */
3905 cam->vp.whiteness = 0; /* not used -> grayscale only */
3906 cam->vp.depth = 24; /* to be set by user */
3907 cam->vp.palette = VIDEO_PALETTE_RGB24; /* to be set by user */
3917 cam->vw.chromakey = 0;
3919 cam->vw.clipcount = 0;
3920 cam->vw.clips = NULL;
3922 cam->cmd_queue = COMMAND_NONE;
3923 cam->first_frame = 1;
3928 /* initialize cam_data structure */
3929 static void init_camera_struct(struct cam_data *cam,
3930 struct cpia_camera_ops *ops )
3934 /* Default everything to 0 */
3935 memset(cam, 0, sizeof(struct cam_data));
3938 init_MUTEX(&cam->param_lock);
3939 init_MUTEX(&cam->busy_lock);
3941 reset_camera_struct(cam);
3943 cam->proc_entry = NULL;
3945 memcpy(&cam->vdev, &cpia_template, sizeof(cpia_template));
3946 cam->vdev.priv = cam;
3949 for (i = 0; i < FRAME_NUM; i++) {
3950 cam->frame[i].width = 0;
3951 cam->frame[i].height = 0;
3952 cam->frame[i].state = FRAME_UNUSED;
3953 cam->frame[i].data = NULL;
3955 cam->decompressed_frame.width = 0;
3956 cam->decompressed_frame.height = 0;
3957 cam->decompressed_frame.state = FRAME_UNUSED;
3958 cam->decompressed_frame.data = NULL;
3961 struct cam_data *cpia_register_camera(struct cpia_camera_ops *ops, void *lowlevel)
3963 struct cam_data *camera;
3965 if ((camera = kmalloc(sizeof(struct cam_data), GFP_KERNEL)) == NULL)
3969 init_camera_struct( camera, ops );
3970 camera->lowlevel_data = lowlevel;
3972 /* register v4l device */
3973 if (video_register_device(&camera->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
3975 printk(KERN_DEBUG "video_register_device failed\n");
3979 /* get version information from camera: open/reset/close */
3982 if (camera->ops->open(camera->lowlevel_data))
3985 /* reset the camera */
3986 if (reset_camera(camera) != 0) {
3987 camera->ops->close(camera->lowlevel_data);
3992 camera->ops->close(camera->lowlevel_data);
3994 #ifdef CONFIG_PROC_FS
3995 create_proc_cpia_cam(camera);
3998 printk(KERN_INFO " CPiA Version: %d.%02d (%d.%d)\n",
3999 camera->params.version.firmwareVersion,
4000 camera->params.version.firmwareRevision,
4001 camera->params.version.vcVersion,
4002 camera->params.version.vcRevision);
4003 printk(KERN_INFO " CPiA PnP-ID: %04x:%04x:%04x\n",
4004 camera->params.pnpID.vendor,
4005 camera->params.pnpID.product,
4006 camera->params.pnpID.deviceRevision);
4007 printk(KERN_INFO " VP-Version: %d.%d %04x\n",
4008 camera->params.vpVersion.vpVersion,
4009 camera->params.vpVersion.vpRevision,
4010 camera->params.vpVersion.cameraHeadID);
4015 void cpia_unregister_camera(struct cam_data *cam)
4017 DBG("unregistering video\n");
4018 video_unregister_device(&cam->vdev);
4019 if (cam->open_count) {
4021 DBG("camera open -- setting ops to NULL\n");
4025 #ifdef CONFIG_PROC_FS
4026 DBG("destroying /proc/cpia/video%d\n", cam->vdev.minor);
4027 destroy_proc_cpia_cam(cam);
4029 if (!cam->open_count) {
4030 DBG("freeing camera\n");
4035 static int __init cpia_init(void)
4037 printk(KERN_INFO "%s v%d.%d.%d\n", ABOUT,
4038 CPIA_MAJ_VER, CPIA_MIN_VER, CPIA_PATCH_VER);
4040 printk(KERN_WARNING "Since in-kernel colorspace conversion is not "
4041 "allowed, it is disabled by default now. Users should fix the "
4042 "applications in case they don't work without conversion "
4043 "reenabled by setting the 'colorspace_conv' module "
4046 #ifdef CONFIG_PROC_FS
4050 #ifdef CONFIG_VIDEO_CPIA_PP
4053 #ifdef CONFIG_VIDEO_CPIA_USB
4060 static void __exit cpia_exit(void)
4062 #ifdef CONFIG_PROC_FS
4063 proc_cpia_destroy();
4067 module_init(cpia_init);
4068 module_exit(cpia_exit);
4070 /* Exported symbols for modules. */
4072 EXPORT_SYMBOL(cpia_register_camera);
4073 EXPORT_SYMBOL(cpia_unregister_camera);