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 */
30 #include <linux/module.h>
31 #include <linux/init.h>
33 #include <linux/vmalloc.h>
34 #include <linux/slab.h>
35 #include <linux/proc_fs.h>
36 #include <linux/ctype.h>
37 #include <linux/pagemap.h>
38 #include <linux/delay.h>
40 #include <linux/mutex.h>
43 #include <linux/kmod.h>
48 static int video_nr = -1;
51 module_param(video_nr, int, 0);
52 MODULE_AUTHOR("Scott J. Bertin <sbertin@securenym.net> & Peter Pregler <Peter_Pregler@email.com> & Johannes Erdfelt <johannes@erdfelt.com>");
53 MODULE_DESCRIPTION("V4L-driver for Vision CPiA based cameras");
54 MODULE_LICENSE("GPL");
55 MODULE_SUPPORTED_DEVICE("video");
58 static unsigned short colorspace_conv;
59 module_param(colorspace_conv, ushort, 0444);
60 MODULE_PARM_DESC(colorspace_conv,
61 " Colorspace conversion:"
62 "\n 0 = disable, 1 = enable"
63 "\n Default value is 0"
66 #define ABOUT "V4L-Driver for Vision CPiA based cameras"
68 #define CPIA_MODULE_CPIA (0<<5)
69 #define CPIA_MODULE_SYSTEM (1<<5)
70 #define CPIA_MODULE_VP_CTRL (5<<5)
71 #define CPIA_MODULE_CAPTURE (6<<5)
72 #define CPIA_MODULE_DEBUG (7<<5)
74 #define INPUT (DATA_IN << 8)
75 #define OUTPUT (DATA_OUT << 8)
77 #define CPIA_COMMAND_GetCPIAVersion (INPUT | CPIA_MODULE_CPIA | 1)
78 #define CPIA_COMMAND_GetPnPID (INPUT | CPIA_MODULE_CPIA | 2)
79 #define CPIA_COMMAND_GetCameraStatus (INPUT | CPIA_MODULE_CPIA | 3)
80 #define CPIA_COMMAND_GotoHiPower (OUTPUT | CPIA_MODULE_CPIA | 4)
81 #define CPIA_COMMAND_GotoLoPower (OUTPUT | CPIA_MODULE_CPIA | 5)
82 #define CPIA_COMMAND_GotoSuspend (OUTPUT | CPIA_MODULE_CPIA | 7)
83 #define CPIA_COMMAND_GotoPassThrough (OUTPUT | CPIA_MODULE_CPIA | 8)
84 #define CPIA_COMMAND_ModifyCameraStatus (OUTPUT | CPIA_MODULE_CPIA | 10)
86 #define CPIA_COMMAND_ReadVCRegs (INPUT | CPIA_MODULE_SYSTEM | 1)
87 #define CPIA_COMMAND_WriteVCReg (OUTPUT | CPIA_MODULE_SYSTEM | 2)
88 #define CPIA_COMMAND_ReadMCPorts (INPUT | CPIA_MODULE_SYSTEM | 3)
89 #define CPIA_COMMAND_WriteMCPort (OUTPUT | CPIA_MODULE_SYSTEM | 4)
90 #define CPIA_COMMAND_SetBaudRate (OUTPUT | CPIA_MODULE_SYSTEM | 5)
91 #define CPIA_COMMAND_SetECPTiming (OUTPUT | CPIA_MODULE_SYSTEM | 6)
92 #define CPIA_COMMAND_ReadIDATA (INPUT | CPIA_MODULE_SYSTEM | 7)
93 #define CPIA_COMMAND_WriteIDATA (OUTPUT | CPIA_MODULE_SYSTEM | 8)
94 #define CPIA_COMMAND_GenericCall (OUTPUT | CPIA_MODULE_SYSTEM | 9)
95 #define CPIA_COMMAND_I2CStart (OUTPUT | CPIA_MODULE_SYSTEM | 10)
96 #define CPIA_COMMAND_I2CStop (OUTPUT | CPIA_MODULE_SYSTEM | 11)
97 #define CPIA_COMMAND_I2CWrite (OUTPUT | CPIA_MODULE_SYSTEM | 12)
98 #define CPIA_COMMAND_I2CRead (INPUT | CPIA_MODULE_SYSTEM | 13)
100 #define CPIA_COMMAND_GetVPVersion (INPUT | CPIA_MODULE_VP_CTRL | 1)
101 #define CPIA_COMMAND_ResetFrameCounter (INPUT | CPIA_MODULE_VP_CTRL | 2)
102 #define CPIA_COMMAND_SetColourParams (OUTPUT | CPIA_MODULE_VP_CTRL | 3)
103 #define CPIA_COMMAND_SetExposure (OUTPUT | CPIA_MODULE_VP_CTRL | 4)
104 #define CPIA_COMMAND_SetColourBalance (OUTPUT | CPIA_MODULE_VP_CTRL | 6)
105 #define CPIA_COMMAND_SetSensorFPS (OUTPUT | CPIA_MODULE_VP_CTRL | 7)
106 #define CPIA_COMMAND_SetVPDefaults (OUTPUT | CPIA_MODULE_VP_CTRL | 8)
107 #define CPIA_COMMAND_SetApcor (OUTPUT | CPIA_MODULE_VP_CTRL | 9)
108 #define CPIA_COMMAND_SetFlickerCtrl (OUTPUT | CPIA_MODULE_VP_CTRL | 10)
109 #define CPIA_COMMAND_SetVLOffset (OUTPUT | CPIA_MODULE_VP_CTRL | 11)
110 #define CPIA_COMMAND_GetColourParams (INPUT | CPIA_MODULE_VP_CTRL | 16)
111 #define CPIA_COMMAND_GetColourBalance (INPUT | CPIA_MODULE_VP_CTRL | 17)
112 #define CPIA_COMMAND_GetExposure (INPUT | CPIA_MODULE_VP_CTRL | 18)
113 #define CPIA_COMMAND_SetSensorMatrix (OUTPUT | CPIA_MODULE_VP_CTRL | 19)
114 #define CPIA_COMMAND_ColourBars (OUTPUT | CPIA_MODULE_VP_CTRL | 25)
115 #define CPIA_COMMAND_ReadVPRegs (INPUT | CPIA_MODULE_VP_CTRL | 30)
116 #define CPIA_COMMAND_WriteVPReg (OUTPUT | CPIA_MODULE_VP_CTRL | 31)
118 #define CPIA_COMMAND_GrabFrame (OUTPUT | CPIA_MODULE_CAPTURE | 1)
119 #define CPIA_COMMAND_UploadFrame (OUTPUT | CPIA_MODULE_CAPTURE | 2)
120 #define CPIA_COMMAND_SetGrabMode (OUTPUT | CPIA_MODULE_CAPTURE | 3)
121 #define CPIA_COMMAND_InitStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 4)
122 #define CPIA_COMMAND_FiniStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 5)
123 #define CPIA_COMMAND_StartStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 6)
124 #define CPIA_COMMAND_EndStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 7)
125 #define CPIA_COMMAND_SetFormat (OUTPUT | CPIA_MODULE_CAPTURE | 8)
126 #define CPIA_COMMAND_SetROI (OUTPUT | CPIA_MODULE_CAPTURE | 9)
127 #define CPIA_COMMAND_SetCompression (OUTPUT | CPIA_MODULE_CAPTURE | 10)
128 #define CPIA_COMMAND_SetCompressionTarget (OUTPUT | CPIA_MODULE_CAPTURE | 11)
129 #define CPIA_COMMAND_SetYUVThresh (OUTPUT | CPIA_MODULE_CAPTURE | 12)
130 #define CPIA_COMMAND_SetCompressionParams (OUTPUT | CPIA_MODULE_CAPTURE | 13)
131 #define CPIA_COMMAND_DiscardFrame (OUTPUT | CPIA_MODULE_CAPTURE | 14)
132 #define CPIA_COMMAND_GrabReset (OUTPUT | CPIA_MODULE_CAPTURE | 15)
134 #define CPIA_COMMAND_OutputRS232 (OUTPUT | CPIA_MODULE_DEBUG | 1)
135 #define CPIA_COMMAND_AbortProcess (OUTPUT | CPIA_MODULE_DEBUG | 4)
136 #define CPIA_COMMAND_SetDramPage (OUTPUT | CPIA_MODULE_DEBUG | 5)
137 #define CPIA_COMMAND_StartDramUpload (OUTPUT | CPIA_MODULE_DEBUG | 6)
138 #define CPIA_COMMAND_StartDummyDtream (OUTPUT | CPIA_MODULE_DEBUG | 8)
139 #define CPIA_COMMAND_AbortStream (OUTPUT | CPIA_MODULE_DEBUG | 9)
140 #define CPIA_COMMAND_DownloadDRAM (OUTPUT | CPIA_MODULE_DEBUG | 10)
141 #define CPIA_COMMAND_Null (OUTPUT | CPIA_MODULE_DEBUG | 11)
144 FRAME_READY, /* Ready to grab into */
145 FRAME_GRABBING, /* In the process of being grabbed into */
146 FRAME_DONE, /* Finished grabbing, but not been synced yet */
147 FRAME_UNUSED, /* Unused (no MCAPTURE) */
150 #define COMMAND_NONE 0x0000
151 #define COMMAND_SETCOMPRESSION 0x0001
152 #define COMMAND_SETCOMPRESSIONTARGET 0x0002
153 #define COMMAND_SETCOLOURPARAMS 0x0004
154 #define COMMAND_SETFORMAT 0x0008
155 #define COMMAND_PAUSE 0x0010
156 #define COMMAND_RESUME 0x0020
157 #define COMMAND_SETYUVTHRESH 0x0040
158 #define COMMAND_SETECPTIMING 0x0080
159 #define COMMAND_SETCOMPRESSIONPARAMS 0x0100
160 #define COMMAND_SETEXPOSURE 0x0200
161 #define COMMAND_SETCOLOURBALANCE 0x0400
162 #define COMMAND_SETSENSORFPS 0x0800
163 #define COMMAND_SETAPCOR 0x1000
164 #define COMMAND_SETFLICKERCTRL 0x2000
165 #define COMMAND_SETVLOFFSET 0x4000
166 #define COMMAND_SETLIGHTS 0x8000
168 #define ROUND_UP_EXP_FOR_FLICKER 15
170 /* Constants for automatic frame rate adjustment */
172 #define MAX_EXP_102 255
174 #define VERY_LOW_EXP 70
176 #define EXP_ACC_DARK 50
177 #define EXP_ACC_LIGHT 90
178 #define HIGH_COMP_102 160
183 /* Maximum number of 10ms loops to wait for the stream to become ready */
184 #define READY_TIMEOUT 100
186 /* Developer's Guide Table 5 p 3-34
187 * indexed by [mains][sensorFps.baserate][sensorFps.divisor]*/
188 static u8 flicker_jumps[2][2][4] =
189 { { { 76, 38, 19, 9 }, { 92, 46, 23, 11 } },
190 { { 64, 32, 16, 8 }, { 76, 38, 19, 9} }
193 /* forward declaration of local function */
194 static void reset_camera_struct(struct cam_data *cam);
195 static int find_over_exposure(int brightness);
196 static void set_flicker(struct cam_params *params, volatile u32 *command_flags,
200 /**********************************************************************
204 **********************************************************************/
205 static void *rvmalloc(unsigned long size)
210 size = PAGE_ALIGN(size);
211 mem = vmalloc_32(size);
215 memset(mem, 0, size); /* Clear the ram out, no junk to the user */
216 adr = (unsigned long) mem;
218 SetPageReserved(vmalloc_to_page((void *)adr));
226 static void rvfree(void *mem, unsigned long size)
233 adr = (unsigned long) mem;
234 while ((long) size > 0) {
235 ClearPageReserved(vmalloc_to_page((void *)adr));
242 /**********************************************************************
246 **********************************************************************/
247 #ifdef CONFIG_PROC_FS
248 static struct proc_dir_entry *cpia_proc_root=NULL;
250 static int cpia_read_proc(char *page, char **start, off_t off,
251 int count, int *eof, void *data)
255 struct cam_data *cam = data;
258 /* IMPORTANT: This output MUST be kept under PAGE_SIZE
259 * or we need to get more sophisticated. */
261 out += sprintf(out, "read-only\n-----------------------\n");
262 out += sprintf(out, "V4L Driver version: %d.%d.%d\n",
263 CPIA_MAJ_VER, CPIA_MIN_VER, CPIA_PATCH_VER);
264 out += sprintf(out, "CPIA Version: %d.%02d (%d.%d)\n",
265 cam->params.version.firmwareVersion,
266 cam->params.version.firmwareRevision,
267 cam->params.version.vcVersion,
268 cam->params.version.vcRevision);
269 out += sprintf(out, "CPIA PnP-ID: %04x:%04x:%04x\n",
270 cam->params.pnpID.vendor, cam->params.pnpID.product,
271 cam->params.pnpID.deviceRevision);
272 out += sprintf(out, "VP-Version: %d.%d %04x\n",
273 cam->params.vpVersion.vpVersion,
274 cam->params.vpVersion.vpRevision,
275 cam->params.vpVersion.cameraHeadID);
277 out += sprintf(out, "system_state: %#04x\n",
278 cam->params.status.systemState);
279 out += sprintf(out, "grab_state: %#04x\n",
280 cam->params.status.grabState);
281 out += sprintf(out, "stream_state: %#04x\n",
282 cam->params.status.streamState);
283 out += sprintf(out, "fatal_error: %#04x\n",
284 cam->params.status.fatalError);
285 out += sprintf(out, "cmd_error: %#04x\n",
286 cam->params.status.cmdError);
287 out += sprintf(out, "debug_flags: %#04x\n",
288 cam->params.status.debugFlags);
289 out += sprintf(out, "vp_status: %#04x\n",
290 cam->params.status.vpStatus);
291 out += sprintf(out, "error_code: %#04x\n",
292 cam->params.status.errorCode);
293 /* QX3 specific entries */
294 if (cam->params.qx3.qx3_detected) {
295 out += sprintf(out, "button: %4d\n",
296 cam->params.qx3.button);
297 out += sprintf(out, "cradled: %4d\n",
298 cam->params.qx3.cradled);
300 out += sprintf(out, "video_size: %s\n",
301 cam->params.format.videoSize == VIDEOSIZE_CIF ?
303 out += sprintf(out, "roi: (%3d, %3d) to (%3d, %3d)\n",
304 cam->params.roi.colStart*8,
305 cam->params.roi.rowStart*4,
306 cam->params.roi.colEnd*8,
307 cam->params.roi.rowEnd*4);
308 out += sprintf(out, "actual_fps: %3d\n", cam->fps);
309 out += sprintf(out, "transfer_rate: %4dkB/s\n",
312 out += sprintf(out, "\nread-write\n");
313 out += sprintf(out, "----------------------- current min"
314 " max default comment\n");
315 out += sprintf(out, "brightness: %8d %8d %8d %8d\n",
316 cam->params.colourParams.brightness, 0, 100, 50);
317 if (cam->params.version.firmwareVersion == 1 &&
318 cam->params.version.firmwareRevision == 2)
319 /* 1-02 firmware limits contrast to 80 */
324 out += sprintf(out, "contrast: %8d %8d %8d %8d"
326 cam->params.colourParams.contrast, 0, tmp, 48);
327 out += sprintf(out, "saturation: %8d %8d %8d %8d\n",
328 cam->params.colourParams.saturation, 0, 100, 50);
329 tmp = (25000+5000*cam->params.sensorFps.baserate)/
330 (1<<cam->params.sensorFps.divisor);
331 out += sprintf(out, "sensor_fps: %4d.%03d %8d %8d %8d\n",
332 tmp/1000, tmp%1000, 3, 30, 15);
333 out += sprintf(out, "stream_start_line: %8d %8d %8d %8d\n",
334 2*cam->params.streamStartLine, 0,
335 cam->params.format.videoSize == VIDEOSIZE_CIF ? 288:144,
336 cam->params.format.videoSize == VIDEOSIZE_CIF ? 240:120);
337 out += sprintf(out, "sub_sample: %8s %8s %8s %8s\n",
338 cam->params.format.subSample == SUBSAMPLE_420 ?
339 "420" : "422", "420", "422", "422");
340 out += sprintf(out, "yuv_order: %8s %8s %8s %8s\n",
341 cam->params.format.yuvOrder == YUVORDER_YUYV ?
342 "YUYV" : "UYVY", "YUYV" , "UYVY", "YUYV");
343 out += sprintf(out, "ecp_timing: %8s %8s %8s %8s\n",
344 cam->params.ecpTiming ? "slow" : "normal", "slow",
347 if (cam->params.colourBalance.balanceMode == 2) {
348 sprintf(tmpstr, "auto");
350 sprintf(tmpstr, "manual");
352 out += sprintf(out, "color_balance_mode: %8s %8s %8s"
353 " %8s\n", tmpstr, "manual", "auto", "auto");
354 out += sprintf(out, "red_gain: %8d %8d %8d %8d\n",
355 cam->params.colourBalance.redGain, 0, 212, 32);
356 out += sprintf(out, "green_gain: %8d %8d %8d %8d\n",
357 cam->params.colourBalance.greenGain, 0, 212, 6);
358 out += sprintf(out, "blue_gain: %8d %8d %8d %8d\n",
359 cam->params.colourBalance.blueGain, 0, 212, 92);
361 if (cam->params.version.firmwareVersion == 1 &&
362 cam->params.version.firmwareRevision == 2)
363 /* 1-02 firmware limits gain to 2 */
364 sprintf(tmpstr, "%8d %8d %8d", 1, 2, 2);
366 sprintf(tmpstr, "%8d %8d %8d", 1, 8, 2);
368 if (cam->params.exposure.gainMode == 0)
369 out += sprintf(out, "max_gain: unknown %28s"
370 " powers of 2\n", tmpstr);
372 out += sprintf(out, "max_gain: %8d %28s"
374 1<<(cam->params.exposure.gainMode-1), tmpstr);
376 switch(cam->params.exposure.expMode) {
379 sprintf(tmpstr, "manual");
382 sprintf(tmpstr, "auto");
385 sprintf(tmpstr, "unknown");
388 out += sprintf(out, "exposure_mode: %8s %8s %8s"
389 " %8s\n", tmpstr, "manual", "auto", "auto");
390 out += sprintf(out, "centre_weight: %8s %8s %8s %8s\n",
391 (2-cam->params.exposure.centreWeight) ? "on" : "off",
393 out += sprintf(out, "gain: %8d %8d max_gain %8d 1,2,4,8 possible\n",
394 1<<cam->params.exposure.gain, 1, 1);
395 if (cam->params.version.firmwareVersion == 1 &&
396 cam->params.version.firmwareRevision == 2)
397 /* 1-02 firmware limits fineExp/2 to 127 */
402 out += sprintf(out, "fine_exp: %8d %8d %8d %8d\n",
403 cam->params.exposure.fineExp*2, 0, tmp, 0);
404 if (cam->params.version.firmwareVersion == 1 &&
405 cam->params.version.firmwareRevision == 2)
406 /* 1-02 firmware limits coarseExpHi to 0 */
411 out += sprintf(out, "coarse_exp: %8d %8d %8d"
412 " %8d\n", cam->params.exposure.coarseExpLo+
413 256*cam->params.exposure.coarseExpHi, 0, tmp, 185);
414 out += sprintf(out, "red_comp: %8d %8d %8d %8d\n",
415 cam->params.exposure.redComp, COMP_RED, 255, COMP_RED);
416 out += sprintf(out, "green1_comp: %8d %8d %8d %8d\n",
417 cam->params.exposure.green1Comp, COMP_GREEN1, 255,
419 out += sprintf(out, "green2_comp: %8d %8d %8d %8d\n",
420 cam->params.exposure.green2Comp, COMP_GREEN2, 255,
422 out += sprintf(out, "blue_comp: %8d %8d %8d %8d\n",
423 cam->params.exposure.blueComp, COMP_BLUE, 255, COMP_BLUE);
425 out += sprintf(out, "apcor_gain1: %#8x %#8x %#8x %#8x\n",
426 cam->params.apcor.gain1, 0, 0xff, 0x1c);
427 out += sprintf(out, "apcor_gain2: %#8x %#8x %#8x %#8x\n",
428 cam->params.apcor.gain2, 0, 0xff, 0x1a);
429 out += sprintf(out, "apcor_gain4: %#8x %#8x %#8x %#8x\n",
430 cam->params.apcor.gain4, 0, 0xff, 0x2d);
431 out += sprintf(out, "apcor_gain8: %#8x %#8x %#8x %#8x\n",
432 cam->params.apcor.gain8, 0, 0xff, 0x2a);
433 out += sprintf(out, "vl_offset_gain1: %8d %8d %8d %8d\n",
434 cam->params.vlOffset.gain1, 0, 255, 24);
435 out += sprintf(out, "vl_offset_gain2: %8d %8d %8d %8d\n",
436 cam->params.vlOffset.gain2, 0, 255, 28);
437 out += sprintf(out, "vl_offset_gain4: %8d %8d %8d %8d\n",
438 cam->params.vlOffset.gain4, 0, 255, 30);
439 out += sprintf(out, "vl_offset_gain8: %8d %8d %8d %8d\n",
440 cam->params.vlOffset.gain8, 0, 255, 30);
441 out += sprintf(out, "flicker_control: %8s %8s %8s %8s\n",
442 cam->params.flickerControl.flickerMode ? "on" : "off",
444 out += sprintf(out, "mains_frequency: %8d %8d %8d %8d"
446 cam->mainsFreq ? 60 : 50, 50, 60, 50);
447 if(cam->params.flickerControl.allowableOverExposure < 0)
448 out += sprintf(out, "allowable_overexposure: %4dauto auto %8d auto\n",
449 -cam->params.flickerControl.allowableOverExposure,
452 out += sprintf(out, "allowable_overexposure: %8d auto %8d auto\n",
453 cam->params.flickerControl.allowableOverExposure,
455 out += sprintf(out, "compression_mode: ");
456 switch(cam->params.compression.mode) {
457 case CPIA_COMPRESSION_NONE:
458 out += sprintf(out, "%8s", "none");
460 case CPIA_COMPRESSION_AUTO:
461 out += sprintf(out, "%8s", "auto");
463 case CPIA_COMPRESSION_MANUAL:
464 out += sprintf(out, "%8s", "manual");
467 out += sprintf(out, "%8s", "unknown");
470 out += sprintf(out, " none,auto,manual auto\n");
471 out += sprintf(out, "decimation_enable: %8s %8s %8s %8s\n",
472 cam->params.compression.decimation ==
473 DECIMATION_ENAB ? "on":"off", "off", "on",
475 out += sprintf(out, "compression_target: %9s %9s %9s %9s\n",
476 cam->params.compressionTarget.frTargeting ==
477 CPIA_COMPRESSION_TARGET_FRAMERATE ?
478 "framerate":"quality",
479 "framerate", "quality", "quality");
480 out += sprintf(out, "target_framerate: %8d %8d %8d %8d\n",
481 cam->params.compressionTarget.targetFR, 1, 30, 15);
482 out += sprintf(out, "target_quality: %8d %8d %8d %8d\n",
483 cam->params.compressionTarget.targetQ, 1, 64, 5);
484 out += sprintf(out, "y_threshold: %8d %8d %8d %8d\n",
485 cam->params.yuvThreshold.yThreshold, 0, 31, 6);
486 out += sprintf(out, "uv_threshold: %8d %8d %8d %8d\n",
487 cam->params.yuvThreshold.uvThreshold, 0, 31, 6);
488 out += sprintf(out, "hysteresis: %8d %8d %8d %8d\n",
489 cam->params.compressionParams.hysteresis, 0, 255, 3);
490 out += sprintf(out, "threshold_max: %8d %8d %8d %8d\n",
491 cam->params.compressionParams.threshMax, 0, 255, 11);
492 out += sprintf(out, "small_step: %8d %8d %8d %8d\n",
493 cam->params.compressionParams.smallStep, 0, 255, 1);
494 out += sprintf(out, "large_step: %8d %8d %8d %8d\n",
495 cam->params.compressionParams.largeStep, 0, 255, 3);
496 out += sprintf(out, "decimation_hysteresis: %8d %8d %8d %8d\n",
497 cam->params.compressionParams.decimationHysteresis,
499 out += sprintf(out, "fr_diff_step_thresh: %8d %8d %8d %8d\n",
500 cam->params.compressionParams.frDiffStepThresh,
502 out += sprintf(out, "q_diff_step_thresh: %8d %8d %8d %8d\n",
503 cam->params.compressionParams.qDiffStepThresh,
505 out += sprintf(out, "decimation_thresh_mod: %8d %8d %8d %8d\n",
506 cam->params.compressionParams.decimationThreshMod,
508 /* QX3 specific entries */
509 if (cam->params.qx3.qx3_detected) {
510 out += sprintf(out, "toplight: %8s %8s %8s %8s\n",
511 cam->params.qx3.toplight ? "on" : "off",
513 out += sprintf(out, "bottomlight: %8s %8s %8s %8s\n",
514 cam->params.qx3.bottomlight ? "on" : "off",
522 if (len <= 0) return 0;
531 static int match(char *checkstr, char **buffer, unsigned long *count,
532 int *find_colon, int *err)
534 int ret, colon_found = 1;
535 int len = strlen(checkstr);
536 ret = (len <= *count && strncmp(*buffer, checkstr, len) == 0);
542 while (*count && (**buffer == ' ' || **buffer == '\t' ||
543 (!colon_found && **buffer == ':'))) {
549 if (!*count || !colon_found)
557 static unsigned long int value(char **buffer, unsigned long *count, int *err)
560 unsigned long int ret;
561 ret = simple_strtoul(*buffer, &p, 0);
565 *count -= p - *buffer;
571 static int cpia_write_proc(struct file *file, const char __user *buf,
572 unsigned long count, void *data)
574 struct cam_data *cam = data;
575 struct cam_params new_params;
577 int retval, find_colon;
579 unsigned long val = 0;
580 u32 command_flags = 0;
584 * This code to copy from buf to page is shamelessly copied
585 * from the comx driver
587 if (count > PAGE_SIZE) {
588 printk(KERN_ERR "count is %lu > %d!!!\n", count, (int)PAGE_SIZE);
592 if (!(page = (char *)__get_free_page(GFP_KERNEL))) return -ENOMEM;
594 if(copy_from_user(page, buf, count))
600 if (page[count-1] == '\n')
601 page[count-1] = '\0';
602 else if (count < PAGE_SIZE)
604 else if (page[count]) {
611 if (mutex_lock_interruptible(&cam->param_lock))
615 * Skip over leading whitespace
617 while (count && isspace(*buffer)) {
622 memcpy(&new_params, &cam->params, sizeof(struct cam_params));
623 new_mains = cam->mainsFreq;
625 #define MATCH(x) (match(x, &buffer, &count, &find_colon, &retval))
626 #define VALUE (value(&buffer,&count, &retval))
627 #define FIRMWARE_VERSION(x,y) (new_params.version.firmwareVersion == (x) && \
628 new_params.version.firmwareRevision == (y))
631 while (count && !retval) {
633 if (MATCH("brightness")) {
639 new_params.colourParams.brightness = val;
643 command_flags |= COMMAND_SETCOLOURPARAMS;
644 if(new_params.flickerControl.allowableOverExposure < 0)
645 new_params.flickerControl.allowableOverExposure =
646 -find_over_exposure(new_params.colourParams.brightness);
647 if(new_params.flickerControl.flickerMode != 0)
648 command_flags |= COMMAND_SETFLICKERCTRL;
650 } else if (MATCH("contrast")) {
656 /* contrast is in steps of 8, so round*/
657 val = ((val + 3) / 8) * 8;
658 /* 1-02 firmware limits contrast to 80*/
659 if (FIRMWARE_VERSION(1,2) && val > 80)
662 new_params.colourParams.contrast = val;
666 command_flags |= COMMAND_SETCOLOURPARAMS;
667 } else if (MATCH("saturation")) {
673 new_params.colourParams.saturation = val;
677 command_flags |= COMMAND_SETCOLOURPARAMS;
678 } else if (MATCH("sensor_fps")) {
683 /* find values so that sensorFPS is minimized,
688 new_params.sensorFps.divisor = 0;
689 new_params.sensorFps.baserate = 1;
690 } else if (val > 15) {
691 new_params.sensorFps.divisor = 0;
692 new_params.sensorFps.baserate = 0;
693 } else if (val > 12) {
694 new_params.sensorFps.divisor = 1;
695 new_params.sensorFps.baserate = 1;
696 } else if (val > 7) {
697 new_params.sensorFps.divisor = 1;
698 new_params.sensorFps.baserate = 0;
699 } else if (val > 6) {
700 new_params.sensorFps.divisor = 2;
701 new_params.sensorFps.baserate = 1;
702 } else if (val > 3) {
703 new_params.sensorFps.divisor = 2;
704 new_params.sensorFps.baserate = 0;
706 new_params.sensorFps.divisor = 3;
707 /* Either base rate would work here */
708 new_params.sensorFps.baserate = 1;
710 new_params.flickerControl.coarseJump =
711 flicker_jumps[new_mains]
712 [new_params.sensorFps.baserate]
713 [new_params.sensorFps.divisor];
714 if (new_params.flickerControl.flickerMode)
715 command_flags |= COMMAND_SETFLICKERCTRL;
717 command_flags |= COMMAND_SETSENSORFPS;
718 cam->exposure_status = EXPOSURE_NORMAL;
719 } else if (MATCH("stream_start_line")) {
726 if (new_params.format.videoSize == VIDEOSIZE_QCIF)
729 new_params.streamStartLine = val/2;
733 } else if (MATCH("sub_sample")) {
734 if (!retval && MATCH("420"))
735 new_params.format.subSample = SUBSAMPLE_420;
736 else if (!retval && MATCH("422"))
737 new_params.format.subSample = SUBSAMPLE_422;
741 command_flags |= COMMAND_SETFORMAT;
742 } else if (MATCH("yuv_order")) {
743 if (!retval && MATCH("YUYV"))
744 new_params.format.yuvOrder = YUVORDER_YUYV;
745 else if (!retval && MATCH("UYVY"))
746 new_params.format.yuvOrder = YUVORDER_UYVY;
750 command_flags |= COMMAND_SETFORMAT;
751 } else if (MATCH("ecp_timing")) {
752 if (!retval && MATCH("normal"))
753 new_params.ecpTiming = 0;
754 else if (!retval && MATCH("slow"))
755 new_params.ecpTiming = 1;
759 command_flags |= COMMAND_SETECPTIMING;
760 } else if (MATCH("color_balance_mode")) {
761 if (!retval && MATCH("manual"))
762 new_params.colourBalance.balanceMode = 3;
763 else if (!retval && MATCH("auto"))
764 new_params.colourBalance.balanceMode = 2;
768 command_flags |= COMMAND_SETCOLOURBALANCE;
769 } else if (MATCH("red_gain")) {
775 new_params.colourBalance.redGain = val;
776 new_params.colourBalance.balanceMode = 1;
780 command_flags |= COMMAND_SETCOLOURBALANCE;
781 } else if (MATCH("green_gain")) {
787 new_params.colourBalance.greenGain = val;
788 new_params.colourBalance.balanceMode = 1;
792 command_flags |= COMMAND_SETCOLOURBALANCE;
793 } else if (MATCH("blue_gain")) {
799 new_params.colourBalance.blueGain = val;
800 new_params.colourBalance.balanceMode = 1;
804 command_flags |= COMMAND_SETCOLOURBALANCE;
805 } else if (MATCH("max_gain")) {
810 /* 1-02 firmware limits gain to 2 */
811 if (FIRMWARE_VERSION(1,2) && val > 2)
815 new_params.exposure.gainMode = 1;
818 new_params.exposure.gainMode = 2;
821 new_params.exposure.gainMode = 3;
824 new_params.exposure.gainMode = 4;
831 command_flags |= COMMAND_SETEXPOSURE;
832 } else if (MATCH("exposure_mode")) {
833 if (!retval && MATCH("auto"))
834 new_params.exposure.expMode = 2;
835 else if (!retval && MATCH("manual")) {
836 if (new_params.exposure.expMode == 2)
837 new_params.exposure.expMode = 3;
838 if(new_params.flickerControl.flickerMode != 0)
839 command_flags |= COMMAND_SETFLICKERCTRL;
840 new_params.flickerControl.flickerMode = 0;
844 command_flags |= COMMAND_SETEXPOSURE;
845 } else if (MATCH("centre_weight")) {
846 if (!retval && MATCH("on"))
847 new_params.exposure.centreWeight = 1;
848 else if (!retval && MATCH("off"))
849 new_params.exposure.centreWeight = 2;
853 command_flags |= COMMAND_SETEXPOSURE;
854 } else if (MATCH("gain")) {
861 new_params.exposure.gain = 0;
864 new_params.exposure.gain = 1;
867 new_params.exposure.gain = 2;
870 new_params.exposure.gain = 3;
876 new_params.exposure.expMode = 1;
877 if(new_params.flickerControl.flickerMode != 0)
878 command_flags |= COMMAND_SETFLICKERCTRL;
879 new_params.flickerControl.flickerMode = 0;
880 command_flags |= COMMAND_SETEXPOSURE;
881 if (new_params.exposure.gain >
882 new_params.exposure.gainMode-1)
885 } else if (MATCH("fine_exp")) {
891 /* 1-02 firmware limits fineExp/2 to 127*/
892 if (FIRMWARE_VERSION(1,2) && val > 127)
894 new_params.exposure.fineExp = val;
895 new_params.exposure.expMode = 1;
896 command_flags |= COMMAND_SETEXPOSURE;
897 if(new_params.flickerControl.flickerMode != 0)
898 command_flags |= COMMAND_SETFLICKERCTRL;
899 new_params.flickerControl.flickerMode = 0;
900 command_flags |= COMMAND_SETFLICKERCTRL;
904 } else if (MATCH("coarse_exp")) {
909 if (val <= MAX_EXP) {
910 if (FIRMWARE_VERSION(1,2) &&
913 new_params.exposure.coarseExpLo =
915 new_params.exposure.coarseExpHi =
917 new_params.exposure.expMode = 1;
918 command_flags |= COMMAND_SETEXPOSURE;
919 if(new_params.flickerControl.flickerMode != 0)
920 command_flags |= COMMAND_SETFLICKERCTRL;
921 new_params.flickerControl.flickerMode = 0;
922 command_flags |= COMMAND_SETFLICKERCTRL;
926 } else if (MATCH("red_comp")) {
931 if (val >= COMP_RED && val <= 255) {
932 new_params.exposure.redComp = val;
933 new_params.exposure.compMode = 1;
934 command_flags |= COMMAND_SETEXPOSURE;
938 } else if (MATCH("green1_comp")) {
943 if (val >= COMP_GREEN1 && val <= 255) {
944 new_params.exposure.green1Comp = val;
945 new_params.exposure.compMode = 1;
946 command_flags |= COMMAND_SETEXPOSURE;
950 } else if (MATCH("green2_comp")) {
955 if (val >= COMP_GREEN2 && val <= 255) {
956 new_params.exposure.green2Comp = val;
957 new_params.exposure.compMode = 1;
958 command_flags |= COMMAND_SETEXPOSURE;
962 } else if (MATCH("blue_comp")) {
967 if (val >= COMP_BLUE && val <= 255) {
968 new_params.exposure.blueComp = val;
969 new_params.exposure.compMode = 1;
970 command_flags |= COMMAND_SETEXPOSURE;
974 } else if (MATCH("apcor_gain1")) {
979 command_flags |= COMMAND_SETAPCOR;
981 new_params.apcor.gain1 = val;
985 } else if (MATCH("apcor_gain2")) {
990 command_flags |= COMMAND_SETAPCOR;
992 new_params.apcor.gain2 = val;
996 } else if (MATCH("apcor_gain4")) {
1001 command_flags |= COMMAND_SETAPCOR;
1003 new_params.apcor.gain4 = val;
1007 } else if (MATCH("apcor_gain8")) {
1012 command_flags |= COMMAND_SETAPCOR;
1014 new_params.apcor.gain8 = val;
1018 } else if (MATCH("vl_offset_gain1")) {
1024 new_params.vlOffset.gain1 = val;
1028 command_flags |= COMMAND_SETVLOFFSET;
1029 } else if (MATCH("vl_offset_gain2")) {
1035 new_params.vlOffset.gain2 = val;
1039 command_flags |= COMMAND_SETVLOFFSET;
1040 } else if (MATCH("vl_offset_gain4")) {
1046 new_params.vlOffset.gain4 = val;
1050 command_flags |= COMMAND_SETVLOFFSET;
1051 } else if (MATCH("vl_offset_gain8")) {
1057 new_params.vlOffset.gain8 = val;
1061 command_flags |= COMMAND_SETVLOFFSET;
1062 } else if (MATCH("flicker_control")) {
1063 if (!retval && MATCH("on")) {
1064 set_flicker(&new_params, &command_flags, 1);
1065 } else if (!retval && MATCH("off")) {
1066 set_flicker(&new_params, &command_flags, 0);
1070 command_flags |= COMMAND_SETFLICKERCTRL;
1071 } else if (MATCH("mains_frequency")) {
1072 if (!retval && MATCH("50")) {
1074 new_params.flickerControl.coarseJump =
1075 flicker_jumps[new_mains]
1076 [new_params.sensorFps.baserate]
1077 [new_params.sensorFps.divisor];
1078 if (new_params.flickerControl.flickerMode)
1079 command_flags |= COMMAND_SETFLICKERCTRL;
1080 } else if (!retval && MATCH("60")) {
1082 new_params.flickerControl.coarseJump =
1083 flicker_jumps[new_mains]
1084 [new_params.sensorFps.baserate]
1085 [new_params.sensorFps.divisor];
1086 if (new_params.flickerControl.flickerMode)
1087 command_flags |= COMMAND_SETFLICKERCTRL;
1090 } else if (MATCH("allowable_overexposure")) {
1091 if (!retval && MATCH("auto")) {
1092 new_params.flickerControl.allowableOverExposure =
1093 -find_over_exposure(new_params.colourParams.brightness);
1094 if(new_params.flickerControl.flickerMode != 0)
1095 command_flags |= COMMAND_SETFLICKERCTRL;
1102 new_params.flickerControl.
1103 allowableOverExposure = val;
1104 if(new_params.flickerControl.flickerMode != 0)
1105 command_flags |= COMMAND_SETFLICKERCTRL;
1110 } else if (MATCH("compression_mode")) {
1111 if (!retval && MATCH("none"))
1112 new_params.compression.mode =
1113 CPIA_COMPRESSION_NONE;
1114 else if (!retval && MATCH("auto"))
1115 new_params.compression.mode =
1116 CPIA_COMPRESSION_AUTO;
1117 else if (!retval && MATCH("manual"))
1118 new_params.compression.mode =
1119 CPIA_COMPRESSION_MANUAL;
1123 command_flags |= COMMAND_SETCOMPRESSION;
1124 } else if (MATCH("decimation_enable")) {
1125 if (!retval && MATCH("off"))
1126 new_params.compression.decimation = 0;
1127 else if (!retval && MATCH("on"))
1128 new_params.compression.decimation = 1;
1132 command_flags |= COMMAND_SETCOMPRESSION;
1133 } else if (MATCH("compression_target")) {
1134 if (!retval && MATCH("quality"))
1135 new_params.compressionTarget.frTargeting =
1136 CPIA_COMPRESSION_TARGET_QUALITY;
1137 else if (!retval && MATCH("framerate"))
1138 new_params.compressionTarget.frTargeting =
1139 CPIA_COMPRESSION_TARGET_FRAMERATE;
1143 command_flags |= COMMAND_SETCOMPRESSIONTARGET;
1144 } else if (MATCH("target_framerate")) {
1149 if(val > 0 && val <= 30)
1150 new_params.compressionTarget.targetFR = val;
1154 command_flags |= COMMAND_SETCOMPRESSIONTARGET;
1155 } else if (MATCH("target_quality")) {
1160 if(val > 0 && val <= 64)
1161 new_params.compressionTarget.targetQ = val;
1165 command_flags |= COMMAND_SETCOMPRESSIONTARGET;
1166 } else if (MATCH("y_threshold")) {
1172 new_params.yuvThreshold.yThreshold = val;
1176 command_flags |= COMMAND_SETYUVTHRESH;
1177 } else if (MATCH("uv_threshold")) {
1183 new_params.yuvThreshold.uvThreshold = val;
1187 command_flags |= COMMAND_SETYUVTHRESH;
1188 } else if (MATCH("hysteresis")) {
1194 new_params.compressionParams.hysteresis = val;
1198 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1199 } else if (MATCH("threshold_max")) {
1205 new_params.compressionParams.threshMax = val;
1209 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1210 } else if (MATCH("small_step")) {
1216 new_params.compressionParams.smallStep = val;
1220 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1221 } else if (MATCH("large_step")) {
1227 new_params.compressionParams.largeStep = val;
1231 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1232 } else if (MATCH("decimation_hysteresis")) {
1238 new_params.compressionParams.decimationHysteresis = val;
1242 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1243 } else if (MATCH("fr_diff_step_thresh")) {
1249 new_params.compressionParams.frDiffStepThresh = val;
1253 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1254 } else if (MATCH("q_diff_step_thresh")) {
1260 new_params.compressionParams.qDiffStepThresh = val;
1264 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1265 } else if (MATCH("decimation_thresh_mod")) {
1271 new_params.compressionParams.decimationThreshMod = val;
1275 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1276 } else if (MATCH("toplight")) {
1277 if (!retval && MATCH("on"))
1278 new_params.qx3.toplight = 1;
1279 else if (!retval && MATCH("off"))
1280 new_params.qx3.toplight = 0;
1283 command_flags |= COMMAND_SETLIGHTS;
1284 } else if (MATCH("bottomlight")) {
1285 if (!retval && MATCH("on"))
1286 new_params.qx3.bottomlight = 1;
1287 else if (!retval && MATCH("off"))
1288 new_params.qx3.bottomlight = 0;
1291 command_flags |= COMMAND_SETLIGHTS;
1293 DBG("No match found\n");
1298 while (count && isspace(*buffer) && *buffer != '\n') {
1303 if (*buffer == '\0' && count != 1)
1305 else if (*buffer != '\n' && *buffer != ';' &&
1317 #undef FIRMWARE_VERSION
1319 if (command_flags & COMMAND_SETCOLOURPARAMS) {
1320 /* Adjust cam->vp to reflect these changes */
1321 cam->vp.brightness =
1322 new_params.colourParams.brightness*65535/100;
1324 new_params.colourParams.contrast*65535/100;
1326 new_params.colourParams.saturation*65535/100;
1328 if((command_flags & COMMAND_SETEXPOSURE) &&
1329 new_params.exposure.expMode == 2)
1330 cam->exposure_status = EXPOSURE_NORMAL;
1332 memcpy(&cam->params, &new_params, sizeof(struct cam_params));
1333 cam->mainsFreq = new_mains;
1334 cam->cmd_queue |= command_flags;
1337 DBG("error: %d\n", retval);
1339 mutex_unlock(&cam->param_lock);
1342 free_page((unsigned long)page);
1346 static void create_proc_cpia_cam(struct cam_data *cam)
1348 char name[5 + 1 + 10 + 1];
1349 struct proc_dir_entry *ent;
1351 if (!cpia_proc_root || !cam)
1354 snprintf(name, sizeof(name), "video%d", cam->vdev.minor);
1356 ent = create_proc_entry(name, S_IFREG|S_IRUGO|S_IWUSR, cpia_proc_root);
1361 ent->read_proc = cpia_read_proc;
1362 ent->write_proc = cpia_write_proc;
1364 size of the proc entry is 3736 bytes for the standard webcam;
1365 the extra features of the QX3 microscope add 189 bytes.
1366 (we have not yet probed the camera to see which type it is).
1368 ent->size = 3736 + 189;
1369 cam->proc_entry = ent;
1372 static void destroy_proc_cpia_cam(struct cam_data *cam)
1374 char name[5 + 1 + 10 + 1];
1376 if (!cam || !cam->proc_entry)
1379 snprintf(name, sizeof(name), "video%d", cam->vdev.minor);
1380 remove_proc_entry(name, cpia_proc_root);
1381 cam->proc_entry = NULL;
1384 static void proc_cpia_create(void)
1386 cpia_proc_root = proc_mkdir("cpia", NULL);
1389 cpia_proc_root->owner = THIS_MODULE;
1391 LOG("Unable to initialise /proc/cpia\n");
1394 static void __exit proc_cpia_destroy(void)
1396 remove_proc_entry("cpia", NULL);
1398 #endif /* CONFIG_PROC_FS */
1400 /* ----------------------- debug functions ---------------------- */
1402 #define printstatus(cam) \
1403 DBG("%02x %02x %02x %02x %02x %02x %02x %02x\n",\
1404 cam->params.status.systemState, cam->params.status.grabState, \
1405 cam->params.status.streamState, cam->params.status.fatalError, \
1406 cam->params.status.cmdError, cam->params.status.debugFlags, \
1407 cam->params.status.vpStatus, cam->params.status.errorCode);
1409 /* ----------------------- v4l helpers -------------------------- */
1411 /* supported frame palettes and depths */
1412 static inline int valid_mode(u16 palette, u16 depth)
1414 if ((palette == VIDEO_PALETTE_YUV422 && depth == 16) ||
1415 (palette == VIDEO_PALETTE_YUYV && depth == 16))
1418 if (colorspace_conv)
1419 return (palette == VIDEO_PALETTE_GREY && depth == 8) ||
1420 (palette == VIDEO_PALETTE_RGB555 && depth == 16) ||
1421 (palette == VIDEO_PALETTE_RGB565 && depth == 16) ||
1422 (palette == VIDEO_PALETTE_RGB24 && depth == 24) ||
1423 (palette == VIDEO_PALETTE_RGB32 && depth == 32) ||
1424 (palette == VIDEO_PALETTE_UYVY && depth == 16);
1429 static int match_videosize( int width, int height )
1431 /* return the best match, where 'best' is as always
1432 * the largest that is not bigger than what is requested. */
1433 if (width>=352 && height>=288)
1434 return VIDEOSIZE_352_288; /* CIF */
1436 if (width>=320 && height>=240)
1437 return VIDEOSIZE_320_240; /* SIF */
1439 if (width>=288 && height>=216)
1440 return VIDEOSIZE_288_216;
1442 if (width>=256 && height>=192)
1443 return VIDEOSIZE_256_192;
1445 if (width>=224 && height>=168)
1446 return VIDEOSIZE_224_168;
1448 if (width>=192 && height>=144)
1449 return VIDEOSIZE_192_144;
1451 if (width>=176 && height>=144)
1452 return VIDEOSIZE_176_144; /* QCIF */
1454 if (width>=160 && height>=120)
1455 return VIDEOSIZE_160_120; /* QSIF */
1457 if (width>=128 && height>=96)
1458 return VIDEOSIZE_128_96;
1460 if (width>=88 && height>=72)
1461 return VIDEOSIZE_88_72;
1463 if (width>=64 && height>=48)
1464 return VIDEOSIZE_64_48;
1466 if (width>=48 && height>=48)
1467 return VIDEOSIZE_48_48;
1472 /* these are the capture sizes we support */
1473 static void set_vw_size(struct cam_data *cam)
1475 /* the col/row/start/end values are the result of simple math */
1476 /* study the SetROI-command in cpia developers guide p 2-22 */
1477 /* streamStartLine is set to the recommended value in the cpia */
1478 /* developers guide p 3-37 */
1479 switch(cam->video_size) {
1481 cam->vw.width = 352;
1482 cam->vw.height = 288;
1483 cam->params.format.videoSize=VIDEOSIZE_CIF;
1484 cam->params.roi.colStart=0;
1485 cam->params.roi.rowStart=0;
1486 cam->params.streamStartLine = 120;
1489 cam->vw.width = 320;
1490 cam->vw.height = 240;
1491 cam->params.format.videoSize=VIDEOSIZE_CIF;
1492 cam->params.roi.colStart=2;
1493 cam->params.roi.rowStart=6;
1494 cam->params.streamStartLine = 120;
1496 case VIDEOSIZE_288_216:
1497 cam->vw.width = 288;
1498 cam->vw.height = 216;
1499 cam->params.format.videoSize=VIDEOSIZE_CIF;
1500 cam->params.roi.colStart=4;
1501 cam->params.roi.rowStart=9;
1502 cam->params.streamStartLine = 120;
1504 case VIDEOSIZE_256_192:
1505 cam->vw.width = 256;
1506 cam->vw.height = 192;
1507 cam->params.format.videoSize=VIDEOSIZE_CIF;
1508 cam->params.roi.colStart=6;
1509 cam->params.roi.rowStart=12;
1510 cam->params.streamStartLine = 120;
1512 case VIDEOSIZE_224_168:
1513 cam->vw.width = 224;
1514 cam->vw.height = 168;
1515 cam->params.format.videoSize=VIDEOSIZE_CIF;
1516 cam->params.roi.colStart=8;
1517 cam->params.roi.rowStart=15;
1518 cam->params.streamStartLine = 120;
1520 case VIDEOSIZE_192_144:
1521 cam->vw.width = 192;
1522 cam->vw.height = 144;
1523 cam->params.format.videoSize=VIDEOSIZE_CIF;
1524 cam->params.roi.colStart=10;
1525 cam->params.roi.rowStart=18;
1526 cam->params.streamStartLine = 120;
1528 case VIDEOSIZE_QCIF:
1529 cam->vw.width = 176;
1530 cam->vw.height = 144;
1531 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1532 cam->params.roi.colStart=0;
1533 cam->params.roi.rowStart=0;
1534 cam->params.streamStartLine = 60;
1536 case VIDEOSIZE_QSIF:
1537 cam->vw.width = 160;
1538 cam->vw.height = 120;
1539 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1540 cam->params.roi.colStart=1;
1541 cam->params.roi.rowStart=3;
1542 cam->params.streamStartLine = 60;
1544 case VIDEOSIZE_128_96:
1545 cam->vw.width = 128;
1546 cam->vw.height = 96;
1547 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1548 cam->params.roi.colStart=3;
1549 cam->params.roi.rowStart=6;
1550 cam->params.streamStartLine = 60;
1552 case VIDEOSIZE_88_72:
1554 cam->vw.height = 72;
1555 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1556 cam->params.roi.colStart=5;
1557 cam->params.roi.rowStart=9;
1558 cam->params.streamStartLine = 60;
1560 case VIDEOSIZE_64_48:
1562 cam->vw.height = 48;
1563 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1564 cam->params.roi.colStart=7;
1565 cam->params.roi.rowStart=12;
1566 cam->params.streamStartLine = 60;
1568 case VIDEOSIZE_48_48:
1570 cam->vw.height = 48;
1571 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1572 cam->params.roi.colStart=8;
1573 cam->params.roi.rowStart=6;
1574 cam->params.streamStartLine = 60;
1577 LOG("bad videosize value: %d\n", cam->video_size);
1581 if(cam->vc.width == 0)
1582 cam->vc.width = cam->vw.width;
1583 if(cam->vc.height == 0)
1584 cam->vc.height = cam->vw.height;
1586 cam->params.roi.colStart += cam->vc.x >> 3;
1587 cam->params.roi.colEnd = cam->params.roi.colStart +
1588 (cam->vc.width >> 3);
1589 cam->params.roi.rowStart += cam->vc.y >> 2;
1590 cam->params.roi.rowEnd = cam->params.roi.rowStart +
1591 (cam->vc.height >> 2);
1596 static int allocate_frame_buf(struct cam_data *cam)
1600 cam->frame_buf = rvmalloc(FRAME_NUM * CPIA_MAX_FRAME_SIZE);
1601 if (!cam->frame_buf)
1604 for (i = 0; i < FRAME_NUM; i++)
1605 cam->frame[i].data = cam->frame_buf + i * CPIA_MAX_FRAME_SIZE;
1610 static int free_frame_buf(struct cam_data *cam)
1614 rvfree(cam->frame_buf, FRAME_NUM*CPIA_MAX_FRAME_SIZE);
1615 cam->frame_buf = NULL;
1616 for (i=0; i < FRAME_NUM; i++)
1617 cam->frame[i].data = NULL;
1623 static inline void free_frames(struct cpia_frame frame[FRAME_NUM])
1627 for (i=0; i < FRAME_NUM; i++)
1628 frame[i].state = FRAME_UNUSED;
1632 /**********************************************************************
1636 **********************************************************************/
1637 /* send an arbitrary command to the camera */
1638 static int do_command(struct cam_data *cam, u16 command, u8 a, u8 b, u8 c, u8 d)
1640 int retval, datasize;
1644 case CPIA_COMMAND_GetCPIAVersion:
1645 case CPIA_COMMAND_GetPnPID:
1646 case CPIA_COMMAND_GetCameraStatus:
1647 case CPIA_COMMAND_GetVPVersion:
1650 case CPIA_COMMAND_GetColourParams:
1651 case CPIA_COMMAND_GetColourBalance:
1652 case CPIA_COMMAND_GetExposure:
1653 mutex_lock(&cam->param_lock);
1656 case CPIA_COMMAND_ReadMCPorts:
1657 case CPIA_COMMAND_ReadVCRegs:
1665 cmd[0] = command>>8;
1666 cmd[1] = command&0xff;
1674 retval = cam->ops->transferCmd(cam->lowlevel_data, cmd, data);
1676 DBG("%x - failed, retval=%d\n", command, retval);
1677 if (command == CPIA_COMMAND_GetColourParams ||
1678 command == CPIA_COMMAND_GetColourBalance ||
1679 command == CPIA_COMMAND_GetExposure)
1680 mutex_unlock(&cam->param_lock);
1683 case CPIA_COMMAND_GetCPIAVersion:
1684 cam->params.version.firmwareVersion = data[0];
1685 cam->params.version.firmwareRevision = data[1];
1686 cam->params.version.vcVersion = data[2];
1687 cam->params.version.vcRevision = data[3];
1689 case CPIA_COMMAND_GetPnPID:
1690 cam->params.pnpID.vendor = data[0]+(((u16)data[1])<<8);
1691 cam->params.pnpID.product = data[2]+(((u16)data[3])<<8);
1692 cam->params.pnpID.deviceRevision =
1693 data[4]+(((u16)data[5])<<8);
1695 case CPIA_COMMAND_GetCameraStatus:
1696 cam->params.status.systemState = data[0];
1697 cam->params.status.grabState = data[1];
1698 cam->params.status.streamState = data[2];
1699 cam->params.status.fatalError = data[3];
1700 cam->params.status.cmdError = data[4];
1701 cam->params.status.debugFlags = data[5];
1702 cam->params.status.vpStatus = data[6];
1703 cam->params.status.errorCode = data[7];
1705 case CPIA_COMMAND_GetVPVersion:
1706 cam->params.vpVersion.vpVersion = data[0];
1707 cam->params.vpVersion.vpRevision = data[1];
1708 cam->params.vpVersion.cameraHeadID =
1709 data[2]+(((u16)data[3])<<8);
1711 case CPIA_COMMAND_GetColourParams:
1712 cam->params.colourParams.brightness = data[0];
1713 cam->params.colourParams.contrast = data[1];
1714 cam->params.colourParams.saturation = data[2];
1715 mutex_unlock(&cam->param_lock);
1717 case CPIA_COMMAND_GetColourBalance:
1718 cam->params.colourBalance.redGain = data[0];
1719 cam->params.colourBalance.greenGain = data[1];
1720 cam->params.colourBalance.blueGain = data[2];
1721 mutex_unlock(&cam->param_lock);
1723 case CPIA_COMMAND_GetExposure:
1724 cam->params.exposure.gain = data[0];
1725 cam->params.exposure.fineExp = data[1];
1726 cam->params.exposure.coarseExpLo = data[2];
1727 cam->params.exposure.coarseExpHi = data[3];
1728 cam->params.exposure.redComp = data[4];
1729 cam->params.exposure.green1Comp = data[5];
1730 cam->params.exposure.green2Comp = data[6];
1731 cam->params.exposure.blueComp = data[7];
1732 mutex_unlock(&cam->param_lock);
1735 case CPIA_COMMAND_ReadMCPorts:
1736 if (!cam->params.qx3.qx3_detected)
1738 /* test button press */
1739 cam->params.qx3.button = ((data[1] & 0x02) == 0);
1740 if (cam->params.qx3.button) {
1741 /* button pressed - unlock the latch */
1742 do_command(cam,CPIA_COMMAND_WriteMCPort,3,0xDF,0xDF,0);
1743 do_command(cam,CPIA_COMMAND_WriteMCPort,3,0xFF,0xFF,0);
1746 /* test whether microscope is cradled */
1747 cam->params.qx3.cradled = ((data[2] & 0x40) == 0);
1757 /* send a command to the camera with an additional data transaction */
1758 static int do_command_extended(struct cam_data *cam, u16 command,
1759 u8 a, u8 b, u8 c, u8 d,
1760 u8 e, u8 f, u8 g, u8 h,
1761 u8 i, u8 j, u8 k, u8 l)
1766 cmd[0] = command>>8;
1767 cmd[1] = command&0xff;
1783 retval = cam->ops->transferCmd(cam->lowlevel_data, cmd, data);
1785 DBG("%x - failed\n", command);
1790 /**********************************************************************
1792 * Colorspace conversion
1794 **********************************************************************/
1795 #define LIMIT(x) ((((x)>0xffffff)?0xff0000:(((x)<=0xffff)?0:(x)&0xff0000))>>16)
1797 static int convert420(unsigned char *yuv, unsigned char *rgb, int out_fmt,
1798 int linesize, int mmap_kludge)
1800 int y, u, v, r, g, b, y1;
1802 /* Odd lines use the same u and v as the previous line.
1803 * Because of compression, it is necessary to get this
1804 * information from the decoded image. */
1806 case VIDEO_PALETTE_RGB555:
1807 y = (*yuv++ - 16) * 76310;
1808 y1 = (*yuv - 16) * 76310;
1809 r = ((*(rgb+1-linesize)) & 0x7c) << 1;
1810 g = ((*(rgb-linesize)) & 0xe0) >> 4 |
1811 ((*(rgb+1-linesize)) & 0x03) << 6;
1812 b = ((*(rgb-linesize)) & 0x1f) << 3;
1813 u = (-53294 * r - 104635 * g + 157929 * b) / 5756495;
1814 v = (157968 * r - 132278 * g - 25690 * b) / 5366159;
1816 g = -25690 * u - 53294 * v;
1818 *rgb++ = ((LIMIT(g+y) & 0xf8) << 2) | (LIMIT(b+y) >> 3);
1819 *rgb++ = ((LIMIT(r+y) & 0xf8) >> 1) | (LIMIT(g+y) >> 6);
1820 *rgb++ = ((LIMIT(g+y1) & 0xf8) << 2) | (LIMIT(b+y1) >> 3);
1821 *rgb = ((LIMIT(r+y1) & 0xf8) >> 1) | (LIMIT(g+y1) >> 6);
1823 case VIDEO_PALETTE_RGB565:
1824 y = (*yuv++ - 16) * 76310;
1825 y1 = (*yuv - 16) * 76310;
1826 r = (*(rgb+1-linesize)) & 0xf8;
1827 g = ((*(rgb-linesize)) & 0xe0) >> 3 |
1828 ((*(rgb+1-linesize)) & 0x07) << 5;
1829 b = ((*(rgb-linesize)) & 0x1f) << 3;
1830 u = (-53294 * r - 104635 * g + 157929 * b) / 5756495;
1831 v = (157968 * r - 132278 * g - 25690 * b) / 5366159;
1833 g = -25690 * u - 53294 * v;
1835 *rgb++ = ((LIMIT(g+y) & 0xfc) << 3) | (LIMIT(b+y) >> 3);
1836 *rgb++ = (LIMIT(r+y) & 0xf8) | (LIMIT(g+y) >> 5);
1837 *rgb++ = ((LIMIT(g+y1) & 0xfc) << 3) | (LIMIT(b+y1) >> 3);
1838 *rgb = (LIMIT(r+y1) & 0xf8) | (LIMIT(g+y1) >> 5);
1841 case VIDEO_PALETTE_RGB24:
1842 case VIDEO_PALETTE_RGB32:
1843 y = (*yuv++ - 16) * 76310;
1844 y1 = (*yuv - 16) * 76310;
1846 r = *(rgb+2-linesize);
1847 g = *(rgb+1-linesize);
1848 b = *(rgb-linesize);
1850 r = *(rgb-linesize);
1851 g = *(rgb+1-linesize);
1852 b = *(rgb+2-linesize);
1854 u = (-53294 * r - 104635 * g + 157929 * b) / 5756495;
1855 v = (157968 * r - 132278 * g - 25690 * b) / 5366159;
1857 g = -25690 * u + -53294 * v;
1860 *rgb++ = LIMIT(b+y);
1861 *rgb++ = LIMIT(g+y);
1862 *rgb++ = LIMIT(r+y);
1863 if(out_fmt == VIDEO_PALETTE_RGB32)
1865 *rgb++ = LIMIT(b+y1);
1866 *rgb++ = LIMIT(g+y1);
1869 *rgb++ = LIMIT(r+y);
1870 *rgb++ = LIMIT(g+y);
1871 *rgb++ = LIMIT(b+y);
1872 if(out_fmt == VIDEO_PALETTE_RGB32)
1874 *rgb++ = LIMIT(r+y1);
1875 *rgb++ = LIMIT(g+y1);
1878 if(out_fmt == VIDEO_PALETTE_RGB32)
1881 case VIDEO_PALETTE_YUV422:
1882 case VIDEO_PALETTE_YUYV:
1884 u = *(rgb+1-linesize);
1886 v = *(rgb+3-linesize);
1892 case VIDEO_PALETTE_UYVY:
1893 u = *(rgb-linesize);
1895 v = *(rgb+2-linesize);
1902 case VIDEO_PALETTE_GREY:
1907 DBG("Empty: %d\n", out_fmt);
1913 static int yuvconvert(unsigned char *yuv, unsigned char *rgb, int out_fmt,
1914 int in_uyvy, int mmap_kludge)
1916 int y, u, v, r, g, b, y1;
1919 case VIDEO_PALETTE_RGB555:
1920 case VIDEO_PALETTE_RGB565:
1921 case VIDEO_PALETTE_RGB24:
1922 case VIDEO_PALETTE_RGB32:
1925 y = (*yuv++ - 16) * 76310;
1927 y1 = (*yuv - 16) * 76310;
1929 y = (*yuv++ - 16) * 76310;
1931 y1 = (*yuv++ - 16) * 76310;
1935 g = -25690 * u + -53294 * v;
1943 /* Just to avoid compiler warnings */
1950 case VIDEO_PALETTE_RGB555:
1951 *rgb++ = ((LIMIT(g+y) & 0xf8) << 2) | (LIMIT(b+y) >> 3);
1952 *rgb++ = ((LIMIT(r+y) & 0xf8) >> 1) | (LIMIT(g+y) >> 6);
1953 *rgb++ = ((LIMIT(g+y1) & 0xf8) << 2) | (LIMIT(b+y1) >> 3);
1954 *rgb = ((LIMIT(r+y1) & 0xf8) >> 1) | (LIMIT(g+y1) >> 6);
1956 case VIDEO_PALETTE_RGB565:
1957 *rgb++ = ((LIMIT(g+y) & 0xfc) << 3) | (LIMIT(b+y) >> 3);
1958 *rgb++ = (LIMIT(r+y) & 0xf8) | (LIMIT(g+y) >> 5);
1959 *rgb++ = ((LIMIT(g+y1) & 0xfc) << 3) | (LIMIT(b+y1) >> 3);
1960 *rgb = (LIMIT(r+y1) & 0xf8) | (LIMIT(g+y1) >> 5);
1962 case VIDEO_PALETTE_RGB24:
1964 *rgb++ = LIMIT(b+y);
1965 *rgb++ = LIMIT(g+y);
1966 *rgb++ = LIMIT(r+y);
1967 *rgb++ = LIMIT(b+y1);
1968 *rgb++ = LIMIT(g+y1);
1971 *rgb++ = LIMIT(r+y);
1972 *rgb++ = LIMIT(g+y);
1973 *rgb++ = LIMIT(b+y);
1974 *rgb++ = LIMIT(r+y1);
1975 *rgb++ = LIMIT(g+y1);
1979 case VIDEO_PALETTE_RGB32:
1981 *rgb++ = LIMIT(b+y);
1982 *rgb++ = LIMIT(g+y);
1983 *rgb++ = LIMIT(r+y);
1985 *rgb++ = LIMIT(b+y1);
1986 *rgb++ = LIMIT(g+y1);
1989 *rgb++ = LIMIT(r+y);
1990 *rgb++ = LIMIT(g+y);
1991 *rgb++ = LIMIT(b+y);
1993 *rgb++ = LIMIT(r+y1);
1994 *rgb++ = LIMIT(g+y1);
1998 case VIDEO_PALETTE_GREY:
2002 case VIDEO_PALETTE_YUV422:
2003 case VIDEO_PALETTE_YUYV:
2009 case VIDEO_PALETTE_UYVY:
2016 DBG("Empty: %d\n", out_fmt);
2021 static int skipcount(int count, int fmt)
2024 case VIDEO_PALETTE_GREY:
2026 case VIDEO_PALETTE_RGB555:
2027 case VIDEO_PALETTE_RGB565:
2028 case VIDEO_PALETTE_YUV422:
2029 case VIDEO_PALETTE_YUYV:
2030 case VIDEO_PALETTE_UYVY:
2032 case VIDEO_PALETTE_RGB24:
2034 case VIDEO_PALETTE_RGB32:
2041 static int parse_picture(struct cam_data *cam, int size)
2043 u8 *obuf, *ibuf, *end_obuf;
2044 int ll, in_uyvy, compressed, decimation, even_line, origsize, out_fmt;
2045 int rows, cols, linesize, subsample_422;
2047 /* make sure params don't change while we are decoding */
2048 mutex_lock(&cam->param_lock);
2050 obuf = cam->decompressed_frame.data;
2051 end_obuf = obuf+CPIA_MAX_FRAME_SIZE;
2052 ibuf = cam->raw_image;
2054 out_fmt = cam->vp.palette;
2056 if ((ibuf[0] != MAGIC_0) || (ibuf[1] != MAGIC_1)) {
2057 LOG("header not found\n");
2058 mutex_unlock(&cam->param_lock);
2062 if ((ibuf[16] != VIDEOSIZE_QCIF) && (ibuf[16] != VIDEOSIZE_CIF)) {
2063 LOG("wrong video size\n");
2064 mutex_unlock(&cam->param_lock);
2068 if (ibuf[17] != SUBSAMPLE_420 && ibuf[17] != SUBSAMPLE_422) {
2069 LOG("illegal subtype %d\n",ibuf[17]);
2070 mutex_unlock(&cam->param_lock);
2073 subsample_422 = ibuf[17] == SUBSAMPLE_422;
2075 if (ibuf[18] != YUVORDER_YUYV && ibuf[18] != YUVORDER_UYVY) {
2076 LOG("illegal yuvorder %d\n",ibuf[18]);
2077 mutex_unlock(&cam->param_lock);
2080 in_uyvy = ibuf[18] == YUVORDER_UYVY;
2082 if ((ibuf[24] != cam->params.roi.colStart) ||
2083 (ibuf[25] != cam->params.roi.colEnd) ||
2084 (ibuf[26] != cam->params.roi.rowStart) ||
2085 (ibuf[27] != cam->params.roi.rowEnd)) {
2086 LOG("ROI mismatch\n");
2087 mutex_unlock(&cam->param_lock);
2090 cols = 8*(ibuf[25] - ibuf[24]);
2091 rows = 4*(ibuf[27] - ibuf[26]);
2094 if ((ibuf[28] != NOT_COMPRESSED) && (ibuf[28] != COMPRESSED)) {
2095 LOG("illegal compression %d\n",ibuf[28]);
2096 mutex_unlock(&cam->param_lock);
2099 compressed = (ibuf[28] == COMPRESSED);
2101 if (ibuf[29] != NO_DECIMATION && ibuf[29] != DECIMATION_ENAB) {
2102 LOG("illegal decimation %d\n",ibuf[29]);
2103 mutex_unlock(&cam->param_lock);
2106 decimation = (ibuf[29] == DECIMATION_ENAB);
2108 cam->params.yuvThreshold.yThreshold = ibuf[30];
2109 cam->params.yuvThreshold.uvThreshold = ibuf[31];
2110 cam->params.status.systemState = ibuf[32];
2111 cam->params.status.grabState = ibuf[33];
2112 cam->params.status.streamState = ibuf[34];
2113 cam->params.status.fatalError = ibuf[35];
2114 cam->params.status.cmdError = ibuf[36];
2115 cam->params.status.debugFlags = ibuf[37];
2116 cam->params.status.vpStatus = ibuf[38];
2117 cam->params.status.errorCode = ibuf[39];
2118 cam->fps = ibuf[41];
2119 mutex_unlock(&cam->param_lock);
2121 linesize = skipcount(cols, out_fmt);
2122 ibuf += FRAME_HEADER_SIZE;
2123 size -= FRAME_HEADER_SIZE;
2124 ll = ibuf[0] | (ibuf[1] << 8);
2131 LOG("Insufficient data in buffer\n");
2136 if (!compressed || (compressed && !(*ibuf & 1))) {
2137 if(subsample_422 || even_line) {
2138 obuf += yuvconvert(ibuf, obuf, out_fmt,
2139 in_uyvy, cam->mmap_kludge);
2143 /* SUBSAMPLE_420 on an odd line */
2144 obuf += convert420(ibuf, obuf,
2151 /*skip compressed interval from previous frame*/
2152 obuf += skipcount(*ibuf >> 1, out_fmt);
2153 if (obuf > end_obuf) {
2154 LOG("Insufficient buffer size\n");
2163 DBG("EOL not found giving up after %d/%d"
2164 " bytes\n", origsize-size, origsize);
2168 ++ibuf; /* skip over EOL */
2170 if ((size > 3) && (ibuf[0] == EOI) && (ibuf[1] == EOI) &&
2171 (ibuf[2] == EOI) && (ibuf[3] == EOI)) {
2177 /* skip the odd lines for now */
2182 ll = ibuf[0] | (ibuf[1] << 8);
2183 ibuf += 2; /* skip over line length */
2186 even_line = !even_line;
2188 LOG("line length was not 1 but %d after %d/%d bytes\n",
2189 ll, origsize-size, origsize);
2195 /* interpolate odd rows */
2198 prev = cam->decompressed_frame.data;
2199 obuf = prev+linesize;
2200 next = obuf+linesize;
2201 for(i=1; i<rows-1; i+=2) {
2202 for(j=0; j<linesize; ++j) {
2203 *obuf++ = ((int)*prev++ + *next++) / 2;
2209 /* last row is odd, just copy previous row */
2210 memcpy(obuf, prev, linesize);
2213 cam->decompressed_frame.count = obuf-cam->decompressed_frame.data;
2215 return cam->decompressed_frame.count;
2218 /* InitStreamCap wrapper to select correct start line */
2219 static inline int init_stream_cap(struct cam_data *cam)
2221 return do_command(cam, CPIA_COMMAND_InitStreamCap,
2222 0, cam->params.streamStartLine, 0, 0);
2226 /* find_over_exposure
2227 * Finds a suitable value of OverExposure for use with SetFlickerCtrl
2228 * Some calculation is required because this value changes with the brightness
2229 * set with SetColourParameters
2231 * Parameters: Brightness - last brightness value set with SetColourParameters
2233 * Returns: OverExposure value to use with SetFlickerCtrl
2235 #define FLICKER_MAX_EXPOSURE 250
2236 #define FLICKER_ALLOWABLE_OVER_EXPOSURE 146
2237 #define FLICKER_BRIGHTNESS_CONSTANT 59
2238 static int find_over_exposure(int brightness)
2240 int MaxAllowableOverExposure, OverExposure;
2242 MaxAllowableOverExposure = FLICKER_MAX_EXPOSURE - brightness -
2243 FLICKER_BRIGHTNESS_CONSTANT;
2245 if (MaxAllowableOverExposure < FLICKER_ALLOWABLE_OVER_EXPOSURE) {
2246 OverExposure = MaxAllowableOverExposure;
2248 OverExposure = FLICKER_ALLOWABLE_OVER_EXPOSURE;
2251 return OverExposure;
2253 #undef FLICKER_MAX_EXPOSURE
2254 #undef FLICKER_ALLOWABLE_OVER_EXPOSURE
2255 #undef FLICKER_BRIGHTNESS_CONSTANT
2257 /* update various camera modes and settings */
2258 static void dispatch_commands(struct cam_data *cam)
2260 mutex_lock(&cam->param_lock);
2261 if (cam->cmd_queue==COMMAND_NONE) {
2262 mutex_unlock(&cam->param_lock);
2265 DEB_BYTE(cam->cmd_queue);
2266 DEB_BYTE(cam->cmd_queue>>8);
2267 if (cam->cmd_queue & COMMAND_SETFORMAT) {
2268 do_command(cam, CPIA_COMMAND_SetFormat,
2269 cam->params.format.videoSize,
2270 cam->params.format.subSample,
2271 cam->params.format.yuvOrder, 0);
2272 do_command(cam, CPIA_COMMAND_SetROI,
2273 cam->params.roi.colStart, cam->params.roi.colEnd,
2274 cam->params.roi.rowStart, cam->params.roi.rowEnd);
2275 cam->first_frame = 1;
2278 if (cam->cmd_queue & COMMAND_SETCOLOURPARAMS)
2279 do_command(cam, CPIA_COMMAND_SetColourParams,
2280 cam->params.colourParams.brightness,
2281 cam->params.colourParams.contrast,
2282 cam->params.colourParams.saturation, 0);
2284 if (cam->cmd_queue & COMMAND_SETAPCOR)
2285 do_command(cam, CPIA_COMMAND_SetApcor,
2286 cam->params.apcor.gain1,
2287 cam->params.apcor.gain2,
2288 cam->params.apcor.gain4,
2289 cam->params.apcor.gain8);
2291 if (cam->cmd_queue & COMMAND_SETVLOFFSET)
2292 do_command(cam, CPIA_COMMAND_SetVLOffset,
2293 cam->params.vlOffset.gain1,
2294 cam->params.vlOffset.gain2,
2295 cam->params.vlOffset.gain4,
2296 cam->params.vlOffset.gain8);
2298 if (cam->cmd_queue & COMMAND_SETEXPOSURE) {
2299 do_command_extended(cam, CPIA_COMMAND_SetExposure,
2300 cam->params.exposure.gainMode,
2302 cam->params.exposure.compMode,
2303 cam->params.exposure.centreWeight,
2304 cam->params.exposure.gain,
2305 cam->params.exposure.fineExp,
2306 cam->params.exposure.coarseExpLo,
2307 cam->params.exposure.coarseExpHi,
2308 cam->params.exposure.redComp,
2309 cam->params.exposure.green1Comp,
2310 cam->params.exposure.green2Comp,
2311 cam->params.exposure.blueComp);
2312 if(cam->params.exposure.expMode != 1) {
2313 do_command_extended(cam, CPIA_COMMAND_SetExposure,
2315 cam->params.exposure.expMode,
2317 cam->params.exposure.gain,
2318 cam->params.exposure.fineExp,
2319 cam->params.exposure.coarseExpLo,
2320 cam->params.exposure.coarseExpHi,
2325 if (cam->cmd_queue & COMMAND_SETCOLOURBALANCE) {
2326 if (cam->params.colourBalance.balanceMode == 1) {
2327 do_command(cam, CPIA_COMMAND_SetColourBalance,
2329 cam->params.colourBalance.redGain,
2330 cam->params.colourBalance.greenGain,
2331 cam->params.colourBalance.blueGain);
2332 do_command(cam, CPIA_COMMAND_SetColourBalance,
2335 if (cam->params.colourBalance.balanceMode == 2) {
2336 do_command(cam, CPIA_COMMAND_SetColourBalance,
2339 if (cam->params.colourBalance.balanceMode == 3) {
2340 do_command(cam, CPIA_COMMAND_SetColourBalance,
2345 if (cam->cmd_queue & COMMAND_SETCOMPRESSIONTARGET)
2346 do_command(cam, CPIA_COMMAND_SetCompressionTarget,
2347 cam->params.compressionTarget.frTargeting,
2348 cam->params.compressionTarget.targetFR,
2349 cam->params.compressionTarget.targetQ, 0);
2351 if (cam->cmd_queue & COMMAND_SETYUVTHRESH)
2352 do_command(cam, CPIA_COMMAND_SetYUVThresh,
2353 cam->params.yuvThreshold.yThreshold,
2354 cam->params.yuvThreshold.uvThreshold, 0, 0);
2356 if (cam->cmd_queue & COMMAND_SETCOMPRESSIONPARAMS)
2357 do_command_extended(cam, CPIA_COMMAND_SetCompressionParams,
2359 cam->params.compressionParams.hysteresis,
2360 cam->params.compressionParams.threshMax,
2361 cam->params.compressionParams.smallStep,
2362 cam->params.compressionParams.largeStep,
2363 cam->params.compressionParams.decimationHysteresis,
2364 cam->params.compressionParams.frDiffStepThresh,
2365 cam->params.compressionParams.qDiffStepThresh,
2366 cam->params.compressionParams.decimationThreshMod);
2368 if (cam->cmd_queue & COMMAND_SETCOMPRESSION)
2369 do_command(cam, CPIA_COMMAND_SetCompression,
2370 cam->params.compression.mode,
2371 cam->params.compression.decimation, 0, 0);
2373 if (cam->cmd_queue & COMMAND_SETSENSORFPS)
2374 do_command(cam, CPIA_COMMAND_SetSensorFPS,
2375 cam->params.sensorFps.divisor,
2376 cam->params.sensorFps.baserate, 0, 0);
2378 if (cam->cmd_queue & COMMAND_SETFLICKERCTRL)
2379 do_command(cam, CPIA_COMMAND_SetFlickerCtrl,
2380 cam->params.flickerControl.flickerMode,
2381 cam->params.flickerControl.coarseJump,
2382 abs(cam->params.flickerControl.allowableOverExposure),
2385 if (cam->cmd_queue & COMMAND_SETECPTIMING)
2386 do_command(cam, CPIA_COMMAND_SetECPTiming,
2387 cam->params.ecpTiming, 0, 0, 0);
2389 if (cam->cmd_queue & COMMAND_PAUSE)
2390 do_command(cam, CPIA_COMMAND_EndStreamCap, 0, 0, 0, 0);
2392 if (cam->cmd_queue & COMMAND_RESUME)
2393 init_stream_cap(cam);
2395 if (cam->cmd_queue & COMMAND_SETLIGHTS && cam->params.qx3.qx3_detected)
2397 int p1 = (cam->params.qx3.bottomlight == 0) << 1;
2398 int p2 = (cam->params.qx3.toplight == 0) << 3;
2399 do_command(cam, CPIA_COMMAND_WriteVCReg, 0x90, 0x8F, 0x50, 0);
2400 do_command(cam, CPIA_COMMAND_WriteMCPort, 2, 0, (p1|p2|0xE0), 0);
2403 cam->cmd_queue = COMMAND_NONE;
2404 mutex_unlock(&cam->param_lock);
2410 static void set_flicker(struct cam_params *params, volatile u32 *command_flags,
2413 /* Everything in here is from the Windows driver */
2414 #define FIRMWARE_VERSION(x,y) (params->version.firmwareVersion == (x) && \
2415 params->version.firmwareRevision == (y))
2416 /* define for compgain calculation */
2418 #define COMPGAIN(base, curexp, newexp) \
2419 (u8) ((((float) base - 128.0) * ((float) curexp / (float) newexp)) + 128.5)
2420 #define EXP_FROM_COMP(basecomp, curcomp, curexp) \
2421 (u16)((float)curexp * (float)(u8)(curcomp + 128) / (float)(u8)(basecomp - 128))
2423 /* equivalent functions without floating point math */
2424 #define COMPGAIN(base, curexp, newexp) \
2425 (u8)(128 + (((u32)(2*(base-128)*curexp + newexp)) / (2* newexp)) )
2426 #define EXP_FROM_COMP(basecomp, curcomp, curexp) \
2427 (u16)(((u32)(curexp * (u8)(curcomp + 128)) / (u8)(basecomp - 128)))
2431 int currentexp = params->exposure.coarseExpLo +
2432 params->exposure.coarseExpHi*256;
2435 int cj = params->flickerControl.coarseJump;
2436 params->flickerControl.flickerMode = 1;
2437 params->flickerControl.disabled = 0;
2438 if(params->exposure.expMode != 2)
2439 *command_flags |= COMMAND_SETEXPOSURE;
2440 params->exposure.expMode = 2;
2441 currentexp = currentexp << params->exposure.gain;
2442 params->exposure.gain = 0;
2443 /* round down current exposure to nearest value */
2444 startexp = (currentexp + ROUND_UP_EXP_FOR_FLICKER) / cj;
2447 startexp = (startexp * cj) - 1;
2448 if(FIRMWARE_VERSION(1,2))
2449 while(startexp > MAX_EXP_102)
2452 while(startexp > MAX_EXP)
2454 params->exposure.coarseExpLo = startexp & 0xff;
2455 params->exposure.coarseExpHi = startexp >> 8;
2456 if (currentexp > startexp) {
2457 if (currentexp > (2 * startexp))
2458 currentexp = 2 * startexp;
2459 params->exposure.redComp = COMPGAIN (COMP_RED, currentexp, startexp);
2460 params->exposure.green1Comp = COMPGAIN (COMP_GREEN1, currentexp, startexp);
2461 params->exposure.green2Comp = COMPGAIN (COMP_GREEN2, currentexp, startexp);
2462 params->exposure.blueComp = COMPGAIN (COMP_BLUE, currentexp, startexp);
2464 params->exposure.redComp = COMP_RED;
2465 params->exposure.green1Comp = COMP_GREEN1;
2466 params->exposure.green2Comp = COMP_GREEN2;
2467 params->exposure.blueComp = COMP_BLUE;
2469 if(FIRMWARE_VERSION(1,2))
2470 params->exposure.compMode = 0;
2472 params->exposure.compMode = 1;
2474 params->apcor.gain1 = 0x18;
2475 params->apcor.gain2 = 0x18;
2476 params->apcor.gain4 = 0x16;
2477 params->apcor.gain8 = 0x14;
2478 *command_flags |= COMMAND_SETAPCOR;
2480 params->flickerControl.flickerMode = 0;
2481 params->flickerControl.disabled = 1;
2482 /* Coarse = average of equivalent coarse for each comp channel */
2483 startexp = EXP_FROM_COMP(COMP_RED, params->exposure.redComp, currentexp);
2484 startexp += EXP_FROM_COMP(COMP_GREEN1, params->exposure.green1Comp, currentexp);
2485 startexp += EXP_FROM_COMP(COMP_GREEN2, params->exposure.green2Comp, currentexp);
2486 startexp += EXP_FROM_COMP(COMP_BLUE, params->exposure.blueComp, currentexp);
2487 startexp = startexp >> 2;
2488 while(startexp > MAX_EXP &&
2489 params->exposure.gain < params->exposure.gainMode-1) {
2490 startexp = startexp >> 1;
2491 ++params->exposure.gain;
2493 if(FIRMWARE_VERSION(1,2) && startexp > MAX_EXP_102)
2494 startexp = MAX_EXP_102;
2495 if(startexp > MAX_EXP)
2497 params->exposure.coarseExpLo = startexp&0xff;
2498 params->exposure.coarseExpHi = startexp >> 8;
2499 params->exposure.redComp = COMP_RED;
2500 params->exposure.green1Comp = COMP_GREEN1;
2501 params->exposure.green2Comp = COMP_GREEN2;
2502 params->exposure.blueComp = COMP_BLUE;
2503 params->exposure.compMode = 1;
2504 *command_flags |= COMMAND_SETEXPOSURE;
2505 params->apcor.gain1 = 0x18;
2506 params->apcor.gain2 = 0x16;
2507 params->apcor.gain4 = 0x24;
2508 params->apcor.gain8 = 0x34;
2509 *command_flags |= COMMAND_SETAPCOR;
2511 params->vlOffset.gain1 = 20;
2512 params->vlOffset.gain2 = 24;
2513 params->vlOffset.gain4 = 26;
2514 params->vlOffset.gain8 = 26;
2515 *command_flags |= COMMAND_SETVLOFFSET;
2516 #undef FIRMWARE_VERSION
2517 #undef EXP_FROM_COMP
2521 #define FIRMWARE_VERSION(x,y) (cam->params.version.firmwareVersion == (x) && \
2522 cam->params.version.firmwareRevision == (y))
2523 /* monitor the exposure and adjust the sensor frame rate if needed */
2524 static void monitor_exposure(struct cam_data *cam)
2526 u8 exp_acc, bcomp, gain, coarseL, cmd[8], data[8];
2527 int retval, light_exp, dark_exp, very_dark_exp;
2528 int old_exposure, new_exposure, framerate;
2530 /* get necessary stats and register settings from camera */
2531 /* do_command can't handle this, so do it ourselves */
2532 cmd[0] = CPIA_COMMAND_ReadVPRegs>>8;
2533 cmd[1] = CPIA_COMMAND_ReadVPRegs&0xff;
2540 retval = cam->ops->transferCmd(cam->lowlevel_data, cmd, data);
2542 LOG("ReadVPRegs(30,4,9,8) - failed, retval=%d\n",
2551 mutex_lock(&cam->param_lock);
2552 light_exp = cam->params.colourParams.brightness +
2553 TC - 50 + EXP_ACC_LIGHT;
2556 dark_exp = cam->params.colourParams.brightness +
2557 TC - 50 - EXP_ACC_DARK;
2560 very_dark_exp = dark_exp/2;
2562 old_exposure = cam->params.exposure.coarseExpHi * 256 +
2563 cam->params.exposure.coarseExpLo;
2565 if(!cam->params.flickerControl.disabled) {
2566 /* Flicker control on */
2567 int max_comp = FIRMWARE_VERSION(1,2) ? MAX_COMP : HIGH_COMP_102;
2568 bcomp += 128; /* decode */
2569 if(bcomp >= max_comp && exp_acc < dark_exp) {
2571 if(exp_acc < very_dark_exp) {
2573 if(cam->exposure_status == EXPOSURE_VERY_DARK)
2574 ++cam->exposure_count;
2576 cam->exposure_status = EXPOSURE_VERY_DARK;
2577 cam->exposure_count = 1;
2581 if(cam->exposure_status == EXPOSURE_DARK)
2582 ++cam->exposure_count;
2584 cam->exposure_status = EXPOSURE_DARK;
2585 cam->exposure_count = 1;
2588 } else if(old_exposure <= LOW_EXP || exp_acc > light_exp) {
2590 if(old_exposure <= VERY_LOW_EXP) {
2592 if(cam->exposure_status == EXPOSURE_VERY_LIGHT)
2593 ++cam->exposure_count;
2595 cam->exposure_status = EXPOSURE_VERY_LIGHT;
2596 cam->exposure_count = 1;
2600 if(cam->exposure_status == EXPOSURE_LIGHT)
2601 ++cam->exposure_count;
2603 cam->exposure_status = EXPOSURE_LIGHT;
2604 cam->exposure_count = 1;
2608 /* not dark or light */
2609 cam->exposure_status = EXPOSURE_NORMAL;
2612 /* Flicker control off */
2613 if(old_exposure >= MAX_EXP && exp_acc < dark_exp) {
2615 if(exp_acc < very_dark_exp) {
2617 if(cam->exposure_status == EXPOSURE_VERY_DARK)
2618 ++cam->exposure_count;
2620 cam->exposure_status = EXPOSURE_VERY_DARK;
2621 cam->exposure_count = 1;
2625 if(cam->exposure_status == EXPOSURE_DARK)
2626 ++cam->exposure_count;
2628 cam->exposure_status = EXPOSURE_DARK;
2629 cam->exposure_count = 1;
2632 } else if(old_exposure <= LOW_EXP || exp_acc > light_exp) {
2634 if(old_exposure <= VERY_LOW_EXP) {
2636 if(cam->exposure_status == EXPOSURE_VERY_LIGHT)
2637 ++cam->exposure_count;
2639 cam->exposure_status = EXPOSURE_VERY_LIGHT;
2640 cam->exposure_count = 1;
2644 if(cam->exposure_status == EXPOSURE_LIGHT)
2645 ++cam->exposure_count;
2647 cam->exposure_status = EXPOSURE_LIGHT;
2648 cam->exposure_count = 1;
2652 /* not dark or light */
2653 cam->exposure_status = EXPOSURE_NORMAL;
2657 framerate = cam->fps;
2658 if(framerate > 30 || framerate < 1)
2661 if(!cam->params.flickerControl.disabled) {
2662 /* Flicker control on */
2663 if((cam->exposure_status == EXPOSURE_VERY_DARK ||
2664 cam->exposure_status == EXPOSURE_DARK) &&
2665 cam->exposure_count >= DARK_TIME*framerate &&
2666 cam->params.sensorFps.divisor < 3) {
2668 /* dark for too long */
2669 ++cam->params.sensorFps.divisor;
2670 cam->cmd_queue |= COMMAND_SETSENSORFPS;
2672 cam->params.flickerControl.coarseJump =
2673 flicker_jumps[cam->mainsFreq]
2674 [cam->params.sensorFps.baserate]
2675 [cam->params.sensorFps.divisor];
2676 cam->cmd_queue |= COMMAND_SETFLICKERCTRL;
2678 new_exposure = cam->params.flickerControl.coarseJump-1;
2679 while(new_exposure < old_exposure/2)
2680 new_exposure += cam->params.flickerControl.coarseJump;
2681 cam->params.exposure.coarseExpLo = new_exposure & 0xff;
2682 cam->params.exposure.coarseExpHi = new_exposure >> 8;
2683 cam->cmd_queue |= COMMAND_SETEXPOSURE;
2684 cam->exposure_status = EXPOSURE_NORMAL;
2685 LOG("Automatically decreasing sensor_fps\n");
2687 } else if((cam->exposure_status == EXPOSURE_VERY_LIGHT ||
2688 cam->exposure_status == EXPOSURE_LIGHT) &&
2689 cam->exposure_count >= LIGHT_TIME*framerate &&
2690 cam->params.sensorFps.divisor > 0) {
2692 /* light for too long */
2693 int max_exp = FIRMWARE_VERSION(1,2) ? MAX_EXP_102 : MAX_EXP ;
2695 --cam->params.sensorFps.divisor;
2696 cam->cmd_queue |= COMMAND_SETSENSORFPS;
2698 cam->params.flickerControl.coarseJump =
2699 flicker_jumps[cam->mainsFreq]
2700 [cam->params.sensorFps.baserate]
2701 [cam->params.sensorFps.divisor];
2702 cam->cmd_queue |= COMMAND_SETFLICKERCTRL;
2704 new_exposure = cam->params.flickerControl.coarseJump-1;
2705 while(new_exposure < 2*old_exposure &&
2707 cam->params.flickerControl.coarseJump < max_exp)
2708 new_exposure += cam->params.flickerControl.coarseJump;
2709 cam->params.exposure.coarseExpLo = new_exposure & 0xff;
2710 cam->params.exposure.coarseExpHi = new_exposure >> 8;
2711 cam->cmd_queue |= COMMAND_SETEXPOSURE;
2712 cam->exposure_status = EXPOSURE_NORMAL;
2713 LOG("Automatically increasing sensor_fps\n");
2716 /* Flicker control off */
2717 if((cam->exposure_status == EXPOSURE_VERY_DARK ||
2718 cam->exposure_status == EXPOSURE_DARK) &&
2719 cam->exposure_count >= DARK_TIME*framerate &&
2720 cam->params.sensorFps.divisor < 3) {
2722 /* dark for too long */
2723 ++cam->params.sensorFps.divisor;
2724 cam->cmd_queue |= COMMAND_SETSENSORFPS;
2726 if(cam->params.exposure.gain > 0) {
2727 --cam->params.exposure.gain;
2728 cam->cmd_queue |= COMMAND_SETEXPOSURE;
2730 cam->exposure_status = EXPOSURE_NORMAL;
2731 LOG("Automatically decreasing sensor_fps\n");
2733 } else if((cam->exposure_status == EXPOSURE_VERY_LIGHT ||
2734 cam->exposure_status == EXPOSURE_LIGHT) &&
2735 cam->exposure_count >= LIGHT_TIME*framerate &&
2736 cam->params.sensorFps.divisor > 0) {
2738 /* light for too long */
2739 --cam->params.sensorFps.divisor;
2740 cam->cmd_queue |= COMMAND_SETSENSORFPS;
2742 if(cam->params.exposure.gain <
2743 cam->params.exposure.gainMode-1) {
2744 ++cam->params.exposure.gain;
2745 cam->cmd_queue |= COMMAND_SETEXPOSURE;
2747 cam->exposure_status = EXPOSURE_NORMAL;
2748 LOG("Automatically increasing sensor_fps\n");
2751 mutex_unlock(&cam->param_lock);
2754 /*-----------------------------------------------------------------*/
2755 /* if flicker is switched off, this function switches it back on.It checks,
2756 however, that conditions are suitable before restarting it.
2757 This should only be called for firmware version 1.2.
2759 It also adjust the colour balance when an exposure step is detected - as
2760 long as flicker is running
2762 static void restart_flicker(struct cam_data *cam)
2764 int cam_exposure, old_exp;
2765 if(!FIRMWARE_VERSION(1,2))
2767 mutex_lock(&cam->param_lock);
2768 if(cam->params.flickerControl.flickerMode == 0 ||
2769 cam->raw_image[39] == 0) {
2770 mutex_unlock(&cam->param_lock);
2773 cam_exposure = cam->raw_image[39]*2;
2774 old_exp = cam->params.exposure.coarseExpLo +
2775 cam->params.exposure.coarseExpHi*256;
2777 see how far away camera exposure is from a valid
2778 flicker exposure value
2780 cam_exposure %= cam->params.flickerControl.coarseJump;
2781 if(!cam->params.flickerControl.disabled &&
2782 cam_exposure <= cam->params.flickerControl.coarseJump - 3) {
2783 /* Flicker control auto-disabled */
2784 cam->params.flickerControl.disabled = 1;
2787 if(cam->params.flickerControl.disabled &&
2788 cam->params.flickerControl.flickerMode &&
2789 old_exp > cam->params.flickerControl.coarseJump +
2790 ROUND_UP_EXP_FOR_FLICKER) {
2791 /* exposure is now high enough to switch
2792 flicker control back on */
2793 set_flicker(&cam->params, &cam->cmd_queue, 1);
2794 if((cam->cmd_queue & COMMAND_SETEXPOSURE) &&
2795 cam->params.exposure.expMode == 2)
2796 cam->exposure_status = EXPOSURE_NORMAL;
2799 mutex_unlock(&cam->param_lock);
2801 #undef FIRMWARE_VERSION
2803 static int clear_stall(struct cam_data *cam)
2805 /* FIXME: Does this actually work? */
2806 LOG("Clearing stall\n");
2808 cam->ops->streamRead(cam->lowlevel_data, cam->raw_image, 0);
2809 do_command(cam, CPIA_COMMAND_GetCameraStatus,0,0,0,0);
2810 return cam->params.status.streamState != STREAM_PAUSED;
2813 /* kernel thread function to read image from camera */
2814 static int fetch_frame(void *data)
2816 int image_size, retry;
2817 struct cam_data *cam = (struct cam_data *)data;
2818 unsigned long oldjif, rate, diff;
2820 /* Allow up to two bad images in a row to be read and
2821 * ignored before an error is reported */
2822 for (retry = 0; retry < 3; ++retry) {
2824 DBG("retry=%d\n", retry);
2829 /* load first frame always uncompressed */
2830 if (cam->first_frame &&
2831 cam->params.compression.mode != CPIA_COMPRESSION_NONE) {
2832 do_command(cam, CPIA_COMMAND_SetCompression,
2833 CPIA_COMPRESSION_NONE,
2834 NO_DECIMATION, 0, 0);
2835 /* Trial & error - Discarding a frame prevents the
2836 first frame from having an error in the data. */
2837 do_command(cam, CPIA_COMMAND_DiscardFrame, 0, 0, 0, 0);
2840 /* init camera upload */
2841 if (do_command(cam, CPIA_COMMAND_GrabFrame, 0,
2842 cam->params.streamStartLine, 0, 0))
2845 if (cam->ops->wait_for_stream_ready) {
2846 /* loop until image ready */
2848 do_command(cam, CPIA_COMMAND_GetCameraStatus,0,0,0,0);
2849 while (cam->params.status.streamState != STREAM_READY) {
2850 if(++count > READY_TIMEOUT)
2852 if(cam->params.status.streamState ==
2855 if(!clear_stall(cam))
2861 /* sleep for 10 ms, hopefully ;) */
2862 msleep_interruptible(10);
2863 if (signal_pending(current))
2866 do_command(cam, CPIA_COMMAND_GetCameraStatus,
2869 if(cam->params.status.streamState != STREAM_READY) {
2876 /* grab image from camera */
2878 image_size = cam->ops->streamRead(cam->lowlevel_data,
2880 if (image_size <= 0) {
2881 DBG("streamRead failed: %d\n", image_size);
2885 rate = image_size * HZ / 1024;
2886 diff = jiffies-oldjif;
2887 cam->transfer_rate = diff==0 ? rate : rate/diff;
2888 /* diff==0 ? unlikely but possible */
2890 /* Switch flicker control back on if it got turned off */
2891 restart_flicker(cam);
2893 /* If AEC is enabled, monitor the exposure and
2894 adjust the sensor frame rate if needed */
2895 if(cam->params.exposure.expMode == 2)
2896 monitor_exposure(cam);
2898 /* camera idle now so dispatch queued commands */
2899 dispatch_commands(cam);
2901 /* Update our knowledge of the camera state */
2902 do_command(cam, CPIA_COMMAND_GetColourBalance, 0, 0, 0, 0);
2903 do_command(cam, CPIA_COMMAND_GetExposure, 0, 0, 0, 0);
2904 do_command(cam, CPIA_COMMAND_ReadMCPorts, 0, 0, 0, 0);
2906 /* decompress and convert image to by copying it from
2907 * raw_image to decompressed_frame
2912 cam->image_size = parse_picture(cam, image_size);
2913 if (cam->image_size <= 0) {
2914 DBG("parse_picture failed %d\n", cam->image_size);
2915 if(cam->params.compression.mode !=
2916 CPIA_COMPRESSION_NONE) {
2917 /* Compression may not work right if we
2918 had a bad frame, get the next one
2920 cam->first_frame = 1;
2921 do_command(cam, CPIA_COMMAND_SetGrabMode,
2922 CPIA_GRAB_SINGLE, 0, 0, 0);
2923 /* FIXME: Trial & error - need up to 70ms for
2924 the grab mode change to complete ? */
2925 msleep_interruptible(70);
2926 if (signal_pending(current))
2934 /* FIXME: this only works for double buffering */
2935 if (cam->frame[cam->curframe].state == FRAME_READY) {
2936 memcpy(cam->frame[cam->curframe].data,
2937 cam->decompressed_frame.data,
2938 cam->decompressed_frame.count);
2939 cam->frame[cam->curframe].state = FRAME_DONE;
2941 cam->decompressed_frame.state = FRAME_DONE;
2943 if (cam->first_frame) {
2944 cam->first_frame = 0;
2945 do_command(cam, CPIA_COMMAND_SetCompression,
2946 cam->params.compression.mode,
2947 cam->params.compression.decimation, 0, 0);
2949 /* Switch from single-grab to continuous grab */
2950 do_command(cam, CPIA_COMMAND_SetGrabMode,
2951 CPIA_GRAB_CONTINUOUS, 0, 0, 0);
2958 static int capture_frame(struct cam_data *cam, struct video_mmap *vm)
2960 if (!cam->frame_buf) {
2961 /* we do lazy allocation */
2963 if ((err = allocate_frame_buf(cam)))
2967 cam->curframe = vm->frame;
2968 cam->frame[cam->curframe].state = FRAME_READY;
2969 return fetch_frame(cam);
2972 static int goto_high_power(struct cam_data *cam)
2974 if (do_command(cam, CPIA_COMMAND_GotoHiPower, 0, 0, 0, 0))
2976 msleep_interruptible(40); /* windows driver does it too */
2977 if(signal_pending(current))
2979 if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0))
2981 if (cam->params.status.systemState == HI_POWER_STATE) {
2982 DBG("camera now in HIGH power state\n");
2989 static int goto_low_power(struct cam_data *cam)
2991 if (do_command(cam, CPIA_COMMAND_GotoLoPower, 0, 0, 0, 0))
2993 if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0))
2995 if (cam->params.status.systemState == LO_POWER_STATE) {
2996 DBG("camera now in LOW power state\n");
3003 static void save_camera_state(struct cam_data *cam)
3005 if(!(cam->cmd_queue & COMMAND_SETCOLOURBALANCE))
3006 do_command(cam, CPIA_COMMAND_GetColourBalance, 0, 0, 0, 0);
3007 if(!(cam->cmd_queue & COMMAND_SETEXPOSURE))
3008 do_command(cam, CPIA_COMMAND_GetExposure, 0, 0, 0, 0);
3010 DBG("%d/%d/%d/%d/%d/%d/%d/%d\n",
3011 cam->params.exposure.gain,
3012 cam->params.exposure.fineExp,
3013 cam->params.exposure.coarseExpLo,
3014 cam->params.exposure.coarseExpHi,
3015 cam->params.exposure.redComp,
3016 cam->params.exposure.green1Comp,
3017 cam->params.exposure.green2Comp,
3018 cam->params.exposure.blueComp);
3020 cam->params.colourBalance.redGain,
3021 cam->params.colourBalance.greenGain,
3022 cam->params.colourBalance.blueGain);
3025 static int set_camera_state(struct cam_data *cam)
3027 cam->cmd_queue = COMMAND_SETCOMPRESSION |
3028 COMMAND_SETCOMPRESSIONTARGET |
3029 COMMAND_SETCOLOURPARAMS |
3031 COMMAND_SETYUVTHRESH |
3032 COMMAND_SETECPTIMING |
3033 COMMAND_SETCOMPRESSIONPARAMS |
3034 COMMAND_SETEXPOSURE |
3035 COMMAND_SETCOLOURBALANCE |
3036 COMMAND_SETSENSORFPS |
3038 COMMAND_SETFLICKERCTRL |
3039 COMMAND_SETVLOFFSET;
3041 do_command(cam, CPIA_COMMAND_SetGrabMode, CPIA_GRAB_SINGLE,0,0,0);
3042 dispatch_commands(cam);
3044 /* Wait 6 frames for the sensor to get all settings and
3045 AEC/ACB to settle */
3046 msleep_interruptible(6*(cam->params.sensorFps.baserate ? 33 : 40) *
3047 (1 << cam->params.sensorFps.divisor) + 10);
3049 if(signal_pending(current))
3052 save_camera_state(cam);
3057 static void get_version_information(struct cam_data *cam)
3059 /* GetCPIAVersion */
3060 do_command(cam, CPIA_COMMAND_GetCPIAVersion, 0, 0, 0, 0);
3063 do_command(cam, CPIA_COMMAND_GetPnPID, 0, 0, 0, 0);
3066 /* initialize camera */
3067 static int reset_camera(struct cam_data *cam)
3070 /* Start the camera in low power mode */
3071 if (goto_low_power(cam)) {
3072 if (cam->params.status.systemState != WARM_BOOT_STATE)
3075 /* FIXME: this is just dirty trial and error */
3076 err = goto_high_power(cam);
3079 do_command(cam, CPIA_COMMAND_DiscardFrame, 0, 0, 0, 0);
3080 if (goto_low_power(cam))
3084 /* procedure described in developer's guide p3-28 */
3086 /* Check the firmware version. */
3087 cam->params.version.firmwareVersion = 0;
3088 get_version_information(cam);
3089 if (cam->params.version.firmwareVersion != 1)
3092 /* A bug in firmware 1-02 limits gainMode to 2 */
3093 if(cam->params.version.firmwareRevision <= 2 &&
3094 cam->params.exposure.gainMode > 2) {
3095 cam->params.exposure.gainMode = 2;
3098 /* set QX3 detected flag */
3099 cam->params.qx3.qx3_detected = (cam->params.pnpID.vendor == 0x0813 &&
3100 cam->params.pnpID.product == 0x0001);
3102 /* The fatal error checking should be done after
3103 * the camera powers up (developer's guide p 3-38) */
3105 /* Set streamState before transition to high power to avoid bug
3106 * in firmware 1-02 */
3107 do_command(cam, CPIA_COMMAND_ModifyCameraStatus, STREAMSTATE, 0,
3108 STREAM_NOT_READY, 0);
3111 err = goto_high_power(cam);
3115 /* Check the camera status */
3116 if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0))
3119 if (cam->params.status.fatalError) {
3120 DBG("fatal_error: %#04x\n",
3121 cam->params.status.fatalError);
3122 DBG("vp_status: %#04x\n",
3123 cam->params.status.vpStatus);
3124 if (cam->params.status.fatalError & ~(COM_FLAG|CPIA_FLAG)) {
3125 /* Fatal error in camera */
3127 } else if (cam->params.status.fatalError & (COM_FLAG|CPIA_FLAG)) {
3128 /* Firmware 1-02 may do this for parallel port cameras,
3129 * just clear the flags (developer's guide p 3-38) */
3130 do_command(cam, CPIA_COMMAND_ModifyCameraStatus,
3131 FATALERROR, ~(COM_FLAG|CPIA_FLAG), 0, 0);
3135 /* Check the camera status again */
3136 if (cam->params.status.fatalError) {
3137 if (cam->params.status.fatalError)
3141 /* VPVersion can't be retrieved before the camera is in HiPower,
3142 * so get it here instead of in get_version_information. */
3143 do_command(cam, CPIA_COMMAND_GetVPVersion, 0, 0, 0, 0);
3145 /* set camera to a known state */
3146 return set_camera_state(cam);
3149 static void put_cam(struct cpia_camera_ops* ops)
3151 module_put(ops->owner);
3154 /* ------------------------- V4L interface --------------------- */
3155 static int cpia_open(struct inode *inode, struct file *file)
3157 struct video_device *dev = video_devdata(file);
3158 struct cam_data *cam = dev->priv;
3162 DBG("Internal error, cam_data not found!\n");
3166 if (cam->open_count > 0) {
3167 DBG("Camera already open\n");
3171 if (!try_module_get(cam->ops->owner))
3174 mutex_lock(&cam->busy_lock);
3176 if (!cam->raw_image) {
3177 cam->raw_image = rvmalloc(CPIA_MAX_IMAGE_SIZE);
3178 if (!cam->raw_image)
3182 if (!cam->decompressed_frame.data) {
3183 cam->decompressed_frame.data = rvmalloc(CPIA_MAX_FRAME_SIZE);
3184 if (!cam->decompressed_frame.data)
3190 if (cam->ops->open(cam->lowlevel_data))
3193 /* reset the camera */
3194 if ((err = reset_camera(cam)) != 0) {
3195 cam->ops->close(cam->lowlevel_data);
3200 if(signal_pending(current))
3203 /* Set ownership of /proc/cpia/videoX to current user */
3205 cam->proc_entry->uid = current->uid;
3207 /* set mark for loading first frame uncompressed */
3208 cam->first_frame = 1;
3210 /* init it to something */
3211 cam->mmap_kludge = 0;
3214 file->private_data = dev;
3215 mutex_unlock(&cam->busy_lock);
3219 if (cam->decompressed_frame.data) {
3220 rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE);
3221 cam->decompressed_frame.data = NULL;
3223 if (cam->raw_image) {
3224 rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
3225 cam->raw_image = NULL;
3227 mutex_unlock(&cam->busy_lock);
3232 static int cpia_close(struct inode *inode, struct file *file)
3234 struct video_device *dev = file->private_data;
3235 struct cam_data *cam = dev->priv;
3238 /* Return ownership of /proc/cpia/videoX to root */
3240 cam->proc_entry->uid = 0;
3242 /* save camera state for later open (developers guide ch 3.5.3) */
3243 save_camera_state(cam);
3246 goto_low_power(cam);
3248 /* Update the camera status */
3249 do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0);
3251 /* cleanup internal state stuff */
3252 free_frames(cam->frame);
3255 cam->ops->close(cam->lowlevel_data);
3260 if (--cam->open_count == 0) {
3261 /* clean up capture-buffers */
3262 if (cam->raw_image) {
3263 rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
3264 cam->raw_image = NULL;
3267 if (cam->decompressed_frame.data) {
3268 rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE);
3269 cam->decompressed_frame.data = NULL;
3273 free_frame_buf(cam);
3278 file->private_data = NULL;
3283 static ssize_t cpia_read(struct file *file, char __user *buf,
3284 size_t count, loff_t *ppos)
3286 struct video_device *dev = file->private_data;
3287 struct cam_data *cam = dev->priv;
3290 /* make this _really_ smp and multithread-safe */
3291 if (mutex_lock_interruptible(&cam->busy_lock))
3296 mutex_unlock(&cam->busy_lock);
3302 mutex_unlock(&cam->busy_lock);
3308 mutex_unlock(&cam->busy_lock);
3313 cam->decompressed_frame.state = FRAME_READY;
3315 if((err = fetch_frame(cam)) != 0) {
3316 DBG("ERROR from fetch_frame: %d\n", err);
3317 mutex_unlock(&cam->busy_lock);
3320 cam->decompressed_frame.state = FRAME_UNUSED;
3322 /* copy data to user space */
3323 if (cam->decompressed_frame.count > count) {
3324 DBG("count wrong: %d, %lu\n", cam->decompressed_frame.count,
3325 (unsigned long) count);
3326 mutex_unlock(&cam->busy_lock);
3329 if (copy_to_user(buf, cam->decompressed_frame.data,
3330 cam->decompressed_frame.count)) {
3331 DBG("copy_to_user failed\n");
3332 mutex_unlock(&cam->busy_lock);
3336 mutex_unlock(&cam->busy_lock);
3337 return cam->decompressed_frame.count;
3340 static int cpia_do_ioctl(struct inode *inode, struct file *file,
3341 unsigned int ioctlnr, void *arg)
3343 struct video_device *dev = file->private_data;
3344 struct cam_data *cam = dev->priv;
3347 if (!cam || !cam->ops)
3350 /* make this _really_ smp-safe */
3351 if (mutex_lock_interruptible(&cam->busy_lock))
3354 //DBG("cpia_ioctl: %u\n", ioctlnr);
3357 /* query capabilities */
3360 struct video_capability *b = arg;
3362 DBG("VIDIOCGCAP\n");
3363 strcpy(b->name, "CPiA Camera");
3364 b->type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE;
3367 b->maxwidth = 352; /* VIDEOSIZE_CIF */
3369 b->minwidth = 48; /* VIDEOSIZE_48_48 */
3374 /* get/set video source - we are a camera and nothing else */
3377 struct video_channel *v = arg;
3379 DBG("VIDIOCGCHAN\n");
3380 if (v->channel != 0) {
3386 strcpy(v->name, "Camera");
3389 v->type = VIDEO_TYPE_CAMERA;
3396 struct video_channel *v = arg;
3398 DBG("VIDIOCSCHAN\n");
3399 if (v->channel != 0)
3404 /* image properties */
3407 struct video_picture *pic = arg;
3408 DBG("VIDIOCGPICT\n");
3415 struct video_picture *vp = arg;
3417 DBG("VIDIOCSPICT\n");
3419 /* check validity */
3420 DBG("palette: %d\n", vp->palette);
3421 DBG("depth: %d\n", vp->depth);
3422 if (!valid_mode(vp->palette, vp->depth)) {
3427 mutex_lock(&cam->param_lock);
3428 /* brightness, colour, contrast need no check 0-65535 */
3430 /* update cam->params.colourParams */
3431 cam->params.colourParams.brightness = vp->brightness*100/65535;
3432 cam->params.colourParams.contrast = vp->contrast*100/65535;
3433 cam->params.colourParams.saturation = vp->colour*100/65535;
3434 /* contrast is in steps of 8, so round */
3435 cam->params.colourParams.contrast =
3436 ((cam->params.colourParams.contrast + 3) / 8) * 8;
3437 if (cam->params.version.firmwareVersion == 1 &&
3438 cam->params.version.firmwareRevision == 2 &&
3439 cam->params.colourParams.contrast > 80) {
3440 /* 1-02 firmware limits contrast to 80 */
3441 cam->params.colourParams.contrast = 80;
3444 /* Adjust flicker control if necessary */
3445 if(cam->params.flickerControl.allowableOverExposure < 0)
3446 cam->params.flickerControl.allowableOverExposure =
3447 -find_over_exposure(cam->params.colourParams.brightness);
3448 if(cam->params.flickerControl.flickerMode != 0)
3449 cam->cmd_queue |= COMMAND_SETFLICKERCTRL;
3452 /* queue command to update camera */
3453 cam->cmd_queue |= COMMAND_SETCOLOURPARAMS;
3454 mutex_unlock(&cam->param_lock);
3455 DBG("VIDIOCSPICT: %d / %d // %d / %d / %d / %d\n",
3456 vp->depth, vp->palette, vp->brightness, vp->hue, vp->colour,
3461 /* get/set capture window */
3464 struct video_window *vw = arg;
3465 DBG("VIDIOCGWIN\n");
3473 /* copy_from_user, check validity, copy to internal structure */
3474 struct video_window *vw = arg;
3475 DBG("VIDIOCSWIN\n");
3477 if (vw->clipcount != 0) { /* clipping not supported */
3481 if (vw->clips != NULL) { /* clipping not supported */
3486 /* we set the video window to something smaller or equal to what
3487 * is requested by the user???
3489 mutex_lock(&cam->param_lock);
3490 if (vw->width != cam->vw.width || vw->height != cam->vw.height) {
3491 int video_size = match_videosize(vw->width, vw->height);
3493 if (video_size < 0) {
3495 mutex_unlock(&cam->param_lock);
3498 cam->video_size = video_size;
3500 /* video size is changing, reset the subcapture area */
3501 memset(&cam->vc, 0, sizeof(cam->vc));
3504 DBG("%d / %d\n", cam->vw.width, cam->vw.height);
3505 cam->cmd_queue |= COMMAND_SETFORMAT;
3508 mutex_unlock(&cam->param_lock);
3510 /* setformat ignored by camera during streaming,
3511 * so stop/dispatch/start */
3512 if (cam->cmd_queue & COMMAND_SETFORMAT) {
3514 dispatch_commands(cam);
3516 DBG("%d/%d:%d\n", cam->video_size,
3517 cam->vw.width, cam->vw.height);
3521 /* mmap interface */
3524 struct video_mbuf *vm = arg;
3527 DBG("VIDIOCGMBUF\n");
3528 memset(vm, 0, sizeof(*vm));
3529 vm->size = CPIA_MAX_FRAME_SIZE*FRAME_NUM;
3530 vm->frames = FRAME_NUM;
3531 for (i = 0; i < FRAME_NUM; i++)
3532 vm->offsets[i] = CPIA_MAX_FRAME_SIZE * i;
3536 case VIDIOCMCAPTURE:
3538 struct video_mmap *vm = arg;
3541 DBG("VIDIOCMCAPTURE: %d / %d / %dx%d\n", vm->format, vm->frame,
3542 vm->width, vm->height);
3543 if (vm->frame<0||vm->frame>=FRAME_NUM) {
3548 /* set video format */
3549 cam->vp.palette = vm->format;
3550 switch(vm->format) {
3551 case VIDEO_PALETTE_GREY:
3554 case VIDEO_PALETTE_RGB555:
3555 case VIDEO_PALETTE_RGB565:
3556 case VIDEO_PALETTE_YUV422:
3557 case VIDEO_PALETTE_YUYV:
3558 case VIDEO_PALETTE_UYVY:
3561 case VIDEO_PALETTE_RGB24:
3564 case VIDEO_PALETTE_RGB32:
3574 /* set video size */
3575 video_size = match_videosize(vm->width, vm->height);
3576 if (video_size < 0) {
3580 if (video_size != cam->video_size) {
3581 cam->video_size = video_size;
3583 /* video size is changing, reset the subcapture area */
3584 memset(&cam->vc, 0, sizeof(cam->vc));
3587 cam->cmd_queue |= COMMAND_SETFORMAT;
3588 dispatch_commands(cam);
3590 /* according to v4l-spec we must start streaming here */
3591 cam->mmap_kludge = 1;
3592 retval = capture_frame(cam, vm);
3601 //DBG("VIDIOCSYNC: %d\n", *frame);
3603 if (*frame<0 || *frame >= FRAME_NUM) {
3608 switch (cam->frame[*frame].state) {
3611 case FRAME_GRABBING:
3612 DBG("sync to unused frame %d\n", *frame);
3617 cam->frame[*frame].state = FRAME_UNUSED;
3618 //DBG("VIDIOCSYNC: %d synced\n", *frame);
3621 if (retval == -EINTR) {
3622 /* FIXME - xawtv does not handle this nice */
3628 case VIDIOCGCAPTURE:
3630 struct video_capture *vc = arg;
3632 DBG("VIDIOCGCAPTURE\n");
3639 case VIDIOCSCAPTURE:
3641 struct video_capture *vc = arg;
3643 DBG("VIDIOCSCAPTURE\n");
3645 if (vc->decimation != 0) { /* How should this be used? */
3649 if (vc->flags != 0) { /* Even/odd grab not supported */
3654 /* Clip to the resolution we can set for the ROI
3655 (every 8 columns and 4 rows) */
3656 vc->x = vc->x & ~(__u32)7;
3657 vc->y = vc->y & ~(__u32)3;
3658 vc->width = vc->width & ~(__u32)7;
3659 vc->height = vc->height & ~(__u32)3;
3661 if(vc->width == 0 || vc->height == 0 ||
3662 vc->x + vc->width > cam->vw.width ||
3663 vc->y + vc->height > cam->vw.height) {
3668 DBG("%d,%d/%dx%d\n", vc->x,vc->y,vc->width, vc->height);
3670 mutex_lock(&cam->param_lock);
3674 cam->vc.width = vc->width;
3675 cam->vc.height = vc->height;
3678 cam->cmd_queue |= COMMAND_SETFORMAT;
3680 mutex_unlock(&cam->param_lock);
3682 /* setformat ignored by camera during streaming,
3683 * so stop/dispatch/start */
3684 dispatch_commands(cam);
3690 struct video_unit *vu = arg;
3692 DBG("VIDIOCGUNIT\n");
3694 vu->video = cam->vdev.minor;
3695 vu->vbi = VIDEO_NO_UNIT;
3696 vu->radio = VIDEO_NO_UNIT;
3697 vu->audio = VIDEO_NO_UNIT;
3698 vu->teletext = VIDEO_NO_UNIT;
3704 /* pointless to implement overlay with this camera */
3709 /* tuner interface - we have none */
3714 /* audio interface - we have none */
3720 retval = -ENOIOCTLCMD;
3724 mutex_unlock(&cam->busy_lock);
3728 static int cpia_ioctl(struct inode *inode, struct file *file,
3729 unsigned int cmd, unsigned long arg)
3731 return video_usercopy(inode, file, cmd, arg, cpia_do_ioctl);
3736 static int cpia_mmap(struct file *file, struct vm_area_struct *vma)
3738 struct video_device *dev = file->private_data;
3739 unsigned long start = vma->vm_start;
3740 unsigned long size = vma->vm_end - vma->vm_start;
3741 unsigned long page, pos;
3742 struct cam_data *cam = dev->priv;
3745 if (!cam || !cam->ops)
3748 DBG("cpia_mmap: %ld\n", size);
3750 if (size > FRAME_NUM*CPIA_MAX_FRAME_SIZE)
3753 if (!cam || !cam->ops)
3756 /* make this _really_ smp-safe */
3757 if (mutex_lock_interruptible(&cam->busy_lock))
3760 if (!cam->frame_buf) { /* we do lazy allocation */
3761 if ((retval = allocate_frame_buf(cam))) {
3762 mutex_unlock(&cam->busy_lock);
3767 pos = (unsigned long)(cam->frame_buf);
3769 page = vmalloc_to_pfn((void *)pos);
3770 if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
3771 mutex_unlock(&cam->busy_lock);
3776 if (size > PAGE_SIZE)
3782 DBG("cpia_mmap: %ld\n", size);
3783 mutex_unlock(&cam->busy_lock);
3788 static const struct file_operations cpia_fops = {
3789 .owner = THIS_MODULE,
3791 .release = cpia_close,
3794 .ioctl = cpia_ioctl,
3795 #ifdef CONFIG_COMPAT
3796 .compat_ioctl = v4l_compat_ioctl32,
3798 .llseek = no_llseek,
3801 static struct video_device cpia_template = {
3802 .name = "CPiA Camera",
3806 /* initialise cam_data structure */
3807 static void reset_camera_struct(struct cam_data *cam)
3809 /* The following parameter values are the defaults from
3810 * "Software Developer's Guide for CPiA Cameras". Any changes
3811 * to the defaults are noted in comments. */
3812 cam->params.colourParams.brightness = 50;
3813 cam->params.colourParams.contrast = 48;
3814 cam->params.colourParams.saturation = 50;
3815 cam->params.exposure.gainMode = 4;
3816 cam->params.exposure.expMode = 2; /* AEC */
3817 cam->params.exposure.compMode = 1;
3818 cam->params.exposure.centreWeight = 1;
3819 cam->params.exposure.gain = 0;
3820 cam->params.exposure.fineExp = 0;
3821 cam->params.exposure.coarseExpLo = 185;
3822 cam->params.exposure.coarseExpHi = 0;
3823 cam->params.exposure.redComp = COMP_RED;
3824 cam->params.exposure.green1Comp = COMP_GREEN1;
3825 cam->params.exposure.green2Comp = COMP_GREEN2;
3826 cam->params.exposure.blueComp = COMP_BLUE;
3827 cam->params.colourBalance.balanceMode = 2; /* ACB */
3828 cam->params.colourBalance.redGain = 32;
3829 cam->params.colourBalance.greenGain = 6;
3830 cam->params.colourBalance.blueGain = 92;
3831 cam->params.apcor.gain1 = 0x18;
3832 cam->params.apcor.gain2 = 0x16;
3833 cam->params.apcor.gain4 = 0x24;
3834 cam->params.apcor.gain8 = 0x34;
3835 cam->params.flickerControl.flickerMode = 0;
3836 cam->params.flickerControl.disabled = 1;
3838 cam->params.flickerControl.coarseJump =
3839 flicker_jumps[cam->mainsFreq]
3840 [cam->params.sensorFps.baserate]
3841 [cam->params.sensorFps.divisor];
3842 cam->params.flickerControl.allowableOverExposure =
3843 -find_over_exposure(cam->params.colourParams.brightness);
3844 cam->params.vlOffset.gain1 = 20;
3845 cam->params.vlOffset.gain2 = 24;
3846 cam->params.vlOffset.gain4 = 26;
3847 cam->params.vlOffset.gain8 = 26;
3848 cam->params.compressionParams.hysteresis = 3;
3849 cam->params.compressionParams.threshMax = 11;
3850 cam->params.compressionParams.smallStep = 1;
3851 cam->params.compressionParams.largeStep = 3;
3852 cam->params.compressionParams.decimationHysteresis = 2;
3853 cam->params.compressionParams.frDiffStepThresh = 5;
3854 cam->params.compressionParams.qDiffStepThresh = 3;
3855 cam->params.compressionParams.decimationThreshMod = 2;
3856 /* End of default values from Software Developer's Guide */
3858 cam->transfer_rate = 0;
3859 cam->exposure_status = EXPOSURE_NORMAL;
3861 /* Set Sensor FPS to 15fps. This seems better than 30fps
3862 * for indoor lighting. */
3863 cam->params.sensorFps.divisor = 1;
3864 cam->params.sensorFps.baserate = 1;
3866 cam->params.yuvThreshold.yThreshold = 6; /* From windows driver */
3867 cam->params.yuvThreshold.uvThreshold = 6; /* From windows driver */
3869 cam->params.format.subSample = SUBSAMPLE_422;
3870 cam->params.format.yuvOrder = YUVORDER_YUYV;
3872 cam->params.compression.mode = CPIA_COMPRESSION_AUTO;
3873 cam->params.compressionTarget.frTargeting =
3874 CPIA_COMPRESSION_TARGET_QUALITY;
3875 cam->params.compressionTarget.targetFR = 15; /* From windows driver */
3876 cam->params.compressionTarget.targetQ = 5; /* From windows driver */
3878 cam->params.qx3.qx3_detected = 0;
3879 cam->params.qx3.toplight = 0;
3880 cam->params.qx3.bottomlight = 0;
3881 cam->params.qx3.button = 0;
3882 cam->params.qx3.cradled = 0;
3884 cam->video_size = VIDEOSIZE_CIF;
3886 cam->vp.colour = 32768; /* 50% */
3887 cam->vp.hue = 32768; /* 50% */
3888 cam->vp.brightness = 32768; /* 50% */
3889 cam->vp.contrast = 32768; /* 50% */
3890 cam->vp.whiteness = 0; /* not used -> grayscale only */
3891 cam->vp.depth = 24; /* to be set by user */
3892 cam->vp.palette = VIDEO_PALETTE_RGB24; /* to be set by user */
3902 cam->vw.chromakey = 0;
3904 cam->vw.clipcount = 0;
3905 cam->vw.clips = NULL;
3907 cam->cmd_queue = COMMAND_NONE;
3908 cam->first_frame = 1;
3913 /* initialize cam_data structure */
3914 static void init_camera_struct(struct cam_data *cam,
3915 struct cpia_camera_ops *ops )
3919 /* Default everything to 0 */
3920 memset(cam, 0, sizeof(struct cam_data));
3923 mutex_init(&cam->param_lock);
3924 mutex_init(&cam->busy_lock);
3926 reset_camera_struct(cam);
3928 cam->proc_entry = NULL;
3930 memcpy(&cam->vdev, &cpia_template, sizeof(cpia_template));
3931 cam->vdev.priv = cam;
3934 for (i = 0; i < FRAME_NUM; i++) {
3935 cam->frame[i].width = 0;
3936 cam->frame[i].height = 0;
3937 cam->frame[i].state = FRAME_UNUSED;
3938 cam->frame[i].data = NULL;
3940 cam->decompressed_frame.width = 0;
3941 cam->decompressed_frame.height = 0;
3942 cam->decompressed_frame.state = FRAME_UNUSED;
3943 cam->decompressed_frame.data = NULL;
3946 struct cam_data *cpia_register_camera(struct cpia_camera_ops *ops, void *lowlevel)
3948 struct cam_data *camera;
3950 if ((camera = kmalloc(sizeof(struct cam_data), GFP_KERNEL)) == NULL)
3954 init_camera_struct( camera, ops );
3955 camera->lowlevel_data = lowlevel;
3957 /* register v4l device */
3958 if (video_register_device(&camera->vdev, VFL_TYPE_GRABBER, video_nr) < 0) {
3960 printk(KERN_DEBUG "video_register_device failed\n");
3964 /* get version information from camera: open/reset/close */
3967 if (camera->ops->open(camera->lowlevel_data))
3970 /* reset the camera */
3971 if (reset_camera(camera) != 0) {
3972 camera->ops->close(camera->lowlevel_data);
3977 camera->ops->close(camera->lowlevel_data);
3979 #ifdef CONFIG_PROC_FS
3980 create_proc_cpia_cam(camera);
3983 printk(KERN_INFO " CPiA Version: %d.%02d (%d.%d)\n",
3984 camera->params.version.firmwareVersion,
3985 camera->params.version.firmwareRevision,
3986 camera->params.version.vcVersion,
3987 camera->params.version.vcRevision);
3988 printk(KERN_INFO " CPiA PnP-ID: %04x:%04x:%04x\n",
3989 camera->params.pnpID.vendor,
3990 camera->params.pnpID.product,
3991 camera->params.pnpID.deviceRevision);
3992 printk(KERN_INFO " VP-Version: %d.%d %04x\n",
3993 camera->params.vpVersion.vpVersion,
3994 camera->params.vpVersion.vpRevision,
3995 camera->params.vpVersion.cameraHeadID);
4000 void cpia_unregister_camera(struct cam_data *cam)
4002 DBG("unregistering video\n");
4003 video_unregister_device(&cam->vdev);
4004 if (cam->open_count) {
4006 DBG("camera open -- setting ops to NULL\n");
4010 #ifdef CONFIG_PROC_FS
4011 DBG("destroying /proc/cpia/video%d\n", cam->vdev.minor);
4012 destroy_proc_cpia_cam(cam);
4014 if (!cam->open_count) {
4015 DBG("freeing camera\n");
4020 static int __init cpia_init(void)
4022 printk(KERN_INFO "%s v%d.%d.%d\n", ABOUT,
4023 CPIA_MAJ_VER, CPIA_MIN_VER, CPIA_PATCH_VER);
4025 printk(KERN_WARNING "Since in-kernel colorspace conversion is not "
4026 "allowed, it is disabled by default now. Users should fix the "
4027 "applications in case they don't work without conversion "
4028 "reenabled by setting the 'colorspace_conv' module "
4029 "parameter to 1\n");
4031 #ifdef CONFIG_PROC_FS
4038 static void __exit cpia_exit(void)
4040 #ifdef CONFIG_PROC_FS
4041 proc_cpia_destroy();
4045 module_init(cpia_init);
4046 module_exit(cpia_exit);
4048 /* Exported symbols for modules. */
4050 EXPORT_SYMBOL(cpia_register_camera);
4051 EXPORT_SYMBOL(cpia_unregister_camera);