4 * Supports CPiA based Video Camera's.
6 * (C) Copyright 1999-2000 Peter Pregler
7 * (C) Copyright 1999-2000 Scott J. Bertin
8 * (C) Copyright 1999-2000 Johannes Erdfelt <johannes@erdfelt.com>
9 * (C) Copyright 2000 STMicroelectronics
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 /* define _CPIA_DEBUG_ for verbose debug output (see cpia.h) */
27 /* #define _CPIA_DEBUG_ 1 */
29 #include <linux/config.h>
31 #include <linux/module.h>
32 #include <linux/moduleparam.h>
33 #include <linux/init.h>
35 #include <linux/vmalloc.h>
36 #include <linux/slab.h>
37 #include <linux/proc_fs.h>
38 #include <linux/ctype.h>
39 #include <linux/pagemap.h>
40 #include <linux/delay.h>
42 #include <linux/mutex.h>
45 #include <linux/kmod.h>
50 static int video_nr = -1;
53 module_param(video_nr, int, 0);
54 MODULE_AUTHOR("Scott J. Bertin <sbertin@securenym.net> & Peter Pregler <Peter_Pregler@email.com> & Johannes Erdfelt <johannes@erdfelt.com>");
55 MODULE_DESCRIPTION("V4L-driver for Vision CPiA based cameras");
56 MODULE_LICENSE("GPL");
57 MODULE_SUPPORTED_DEVICE("video");
60 static unsigned short colorspace_conv;
61 module_param(colorspace_conv, ushort, 0444);
62 MODULE_PARM_DESC(colorspace_conv,
63 " Colorspace conversion:"
64 "\n 0 = disable, 1 = enable"
65 "\n Default value is 0"
68 #define ABOUT "V4L-Driver for Vision CPiA based cameras"
70 #ifndef VID_HARDWARE_CPIA
71 #define VID_HARDWARE_CPIA 24 /* FIXME -> from linux/videodev.h */
74 #define CPIA_MODULE_CPIA (0<<5)
75 #define CPIA_MODULE_SYSTEM (1<<5)
76 #define CPIA_MODULE_VP_CTRL (5<<5)
77 #define CPIA_MODULE_CAPTURE (6<<5)
78 #define CPIA_MODULE_DEBUG (7<<5)
80 #define INPUT (DATA_IN << 8)
81 #define OUTPUT (DATA_OUT << 8)
83 #define CPIA_COMMAND_GetCPIAVersion (INPUT | CPIA_MODULE_CPIA | 1)
84 #define CPIA_COMMAND_GetPnPID (INPUT | CPIA_MODULE_CPIA | 2)
85 #define CPIA_COMMAND_GetCameraStatus (INPUT | CPIA_MODULE_CPIA | 3)
86 #define CPIA_COMMAND_GotoHiPower (OUTPUT | CPIA_MODULE_CPIA | 4)
87 #define CPIA_COMMAND_GotoLoPower (OUTPUT | CPIA_MODULE_CPIA | 5)
88 #define CPIA_COMMAND_GotoSuspend (OUTPUT | CPIA_MODULE_CPIA | 7)
89 #define CPIA_COMMAND_GotoPassThrough (OUTPUT | CPIA_MODULE_CPIA | 8)
90 #define CPIA_COMMAND_ModifyCameraStatus (OUTPUT | CPIA_MODULE_CPIA | 10)
92 #define CPIA_COMMAND_ReadVCRegs (INPUT | CPIA_MODULE_SYSTEM | 1)
93 #define CPIA_COMMAND_WriteVCReg (OUTPUT | CPIA_MODULE_SYSTEM | 2)
94 #define CPIA_COMMAND_ReadMCPorts (INPUT | CPIA_MODULE_SYSTEM | 3)
95 #define CPIA_COMMAND_WriteMCPort (OUTPUT | CPIA_MODULE_SYSTEM | 4)
96 #define CPIA_COMMAND_SetBaudRate (OUTPUT | CPIA_MODULE_SYSTEM | 5)
97 #define CPIA_COMMAND_SetECPTiming (OUTPUT | CPIA_MODULE_SYSTEM | 6)
98 #define CPIA_COMMAND_ReadIDATA (INPUT | CPIA_MODULE_SYSTEM | 7)
99 #define CPIA_COMMAND_WriteIDATA (OUTPUT | CPIA_MODULE_SYSTEM | 8)
100 #define CPIA_COMMAND_GenericCall (OUTPUT | CPIA_MODULE_SYSTEM | 9)
101 #define CPIA_COMMAND_I2CStart (OUTPUT | CPIA_MODULE_SYSTEM | 10)
102 #define CPIA_COMMAND_I2CStop (OUTPUT | CPIA_MODULE_SYSTEM | 11)
103 #define CPIA_COMMAND_I2CWrite (OUTPUT | CPIA_MODULE_SYSTEM | 12)
104 #define CPIA_COMMAND_I2CRead (INPUT | CPIA_MODULE_SYSTEM | 13)
106 #define CPIA_COMMAND_GetVPVersion (INPUT | CPIA_MODULE_VP_CTRL | 1)
107 #define CPIA_COMMAND_ResetFrameCounter (INPUT | CPIA_MODULE_VP_CTRL | 2)
108 #define CPIA_COMMAND_SetColourParams (OUTPUT | CPIA_MODULE_VP_CTRL | 3)
109 #define CPIA_COMMAND_SetExposure (OUTPUT | CPIA_MODULE_VP_CTRL | 4)
110 #define CPIA_COMMAND_SetColourBalance (OUTPUT | CPIA_MODULE_VP_CTRL | 6)
111 #define CPIA_COMMAND_SetSensorFPS (OUTPUT | CPIA_MODULE_VP_CTRL | 7)
112 #define CPIA_COMMAND_SetVPDefaults (OUTPUT | CPIA_MODULE_VP_CTRL | 8)
113 #define CPIA_COMMAND_SetApcor (OUTPUT | CPIA_MODULE_VP_CTRL | 9)
114 #define CPIA_COMMAND_SetFlickerCtrl (OUTPUT | CPIA_MODULE_VP_CTRL | 10)
115 #define CPIA_COMMAND_SetVLOffset (OUTPUT | CPIA_MODULE_VP_CTRL | 11)
116 #define CPIA_COMMAND_GetColourParams (INPUT | CPIA_MODULE_VP_CTRL | 16)
117 #define CPIA_COMMAND_GetColourBalance (INPUT | CPIA_MODULE_VP_CTRL | 17)
118 #define CPIA_COMMAND_GetExposure (INPUT | CPIA_MODULE_VP_CTRL | 18)
119 #define CPIA_COMMAND_SetSensorMatrix (OUTPUT | CPIA_MODULE_VP_CTRL | 19)
120 #define CPIA_COMMAND_ColourBars (OUTPUT | CPIA_MODULE_VP_CTRL | 25)
121 #define CPIA_COMMAND_ReadVPRegs (INPUT | CPIA_MODULE_VP_CTRL | 30)
122 #define CPIA_COMMAND_WriteVPReg (OUTPUT | CPIA_MODULE_VP_CTRL | 31)
124 #define CPIA_COMMAND_GrabFrame (OUTPUT | CPIA_MODULE_CAPTURE | 1)
125 #define CPIA_COMMAND_UploadFrame (OUTPUT | CPIA_MODULE_CAPTURE | 2)
126 #define CPIA_COMMAND_SetGrabMode (OUTPUT | CPIA_MODULE_CAPTURE | 3)
127 #define CPIA_COMMAND_InitStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 4)
128 #define CPIA_COMMAND_FiniStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 5)
129 #define CPIA_COMMAND_StartStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 6)
130 #define CPIA_COMMAND_EndStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 7)
131 #define CPIA_COMMAND_SetFormat (OUTPUT | CPIA_MODULE_CAPTURE | 8)
132 #define CPIA_COMMAND_SetROI (OUTPUT | CPIA_MODULE_CAPTURE | 9)
133 #define CPIA_COMMAND_SetCompression (OUTPUT | CPIA_MODULE_CAPTURE | 10)
134 #define CPIA_COMMAND_SetCompressionTarget (OUTPUT | CPIA_MODULE_CAPTURE | 11)
135 #define CPIA_COMMAND_SetYUVThresh (OUTPUT | CPIA_MODULE_CAPTURE | 12)
136 #define CPIA_COMMAND_SetCompressionParams (OUTPUT | CPIA_MODULE_CAPTURE | 13)
137 #define CPIA_COMMAND_DiscardFrame (OUTPUT | CPIA_MODULE_CAPTURE | 14)
138 #define CPIA_COMMAND_GrabReset (OUTPUT | CPIA_MODULE_CAPTURE | 15)
140 #define CPIA_COMMAND_OutputRS232 (OUTPUT | CPIA_MODULE_DEBUG | 1)
141 #define CPIA_COMMAND_AbortProcess (OUTPUT | CPIA_MODULE_DEBUG | 4)
142 #define CPIA_COMMAND_SetDramPage (OUTPUT | CPIA_MODULE_DEBUG | 5)
143 #define CPIA_COMMAND_StartDramUpload (OUTPUT | CPIA_MODULE_DEBUG | 6)
144 #define CPIA_COMMAND_StartDummyDtream (OUTPUT | CPIA_MODULE_DEBUG | 8)
145 #define CPIA_COMMAND_AbortStream (OUTPUT | CPIA_MODULE_DEBUG | 9)
146 #define CPIA_COMMAND_DownloadDRAM (OUTPUT | CPIA_MODULE_DEBUG | 10)
147 #define CPIA_COMMAND_Null (OUTPUT | CPIA_MODULE_DEBUG | 11)
150 FRAME_READY, /* Ready to grab into */
151 FRAME_GRABBING, /* In the process of being grabbed into */
152 FRAME_DONE, /* Finished grabbing, but not been synced yet */
153 FRAME_UNUSED, /* Unused (no MCAPTURE) */
156 #define COMMAND_NONE 0x0000
157 #define COMMAND_SETCOMPRESSION 0x0001
158 #define COMMAND_SETCOMPRESSIONTARGET 0x0002
159 #define COMMAND_SETCOLOURPARAMS 0x0004
160 #define COMMAND_SETFORMAT 0x0008
161 #define COMMAND_PAUSE 0x0010
162 #define COMMAND_RESUME 0x0020
163 #define COMMAND_SETYUVTHRESH 0x0040
164 #define COMMAND_SETECPTIMING 0x0080
165 #define COMMAND_SETCOMPRESSIONPARAMS 0x0100
166 #define COMMAND_SETEXPOSURE 0x0200
167 #define COMMAND_SETCOLOURBALANCE 0x0400
168 #define COMMAND_SETSENSORFPS 0x0800
169 #define COMMAND_SETAPCOR 0x1000
170 #define COMMAND_SETFLICKERCTRL 0x2000
171 #define COMMAND_SETVLOFFSET 0x4000
172 #define COMMAND_SETLIGHTS 0x8000
174 #define ROUND_UP_EXP_FOR_FLICKER 15
176 /* Constants for automatic frame rate adjustment */
178 #define MAX_EXP_102 255
180 #define VERY_LOW_EXP 70
182 #define EXP_ACC_DARK 50
183 #define EXP_ACC_LIGHT 90
184 #define HIGH_COMP_102 160
189 /* Maximum number of 10ms loops to wait for the stream to become ready */
190 #define READY_TIMEOUT 100
192 /* Developer's Guide Table 5 p 3-34
193 * indexed by [mains][sensorFps.baserate][sensorFps.divisor]*/
194 static u8 flicker_jumps[2][2][4] =
195 { { { 76, 38, 19, 9 }, { 92, 46, 23, 11 } },
196 { { 64, 32, 16, 8 }, { 76, 38, 19, 9} }
199 /* forward declaration of local function */
200 static void reset_camera_struct(struct cam_data *cam);
201 static int find_over_exposure(int brightness);
202 static void set_flicker(struct cam_params *params, volatile u32 *command_flags,
206 /**********************************************************************
210 **********************************************************************/
211 static void *rvmalloc(unsigned long size)
216 size = PAGE_ALIGN(size);
217 mem = vmalloc_32(size);
221 memset(mem, 0, size); /* Clear the ram out, no junk to the user */
222 adr = (unsigned long) mem;
224 SetPageReserved(vmalloc_to_page((void *)adr));
232 static void rvfree(void *mem, unsigned long size)
239 adr = (unsigned long) mem;
240 while ((long) size > 0) {
241 ClearPageReserved(vmalloc_to_page((void *)adr));
248 /**********************************************************************
252 **********************************************************************/
253 #ifdef CONFIG_PROC_FS
254 static struct proc_dir_entry *cpia_proc_root=NULL;
256 static int cpia_read_proc(char *page, char **start, off_t off,
257 int count, int *eof, void *data)
261 struct cam_data *cam = data;
264 /* IMPORTANT: This output MUST be kept under PAGE_SIZE
265 * or we need to get more sophisticated. */
267 out += sprintf(out, "read-only\n-----------------------\n");
268 out += sprintf(out, "V4L Driver version: %d.%d.%d\n",
269 CPIA_MAJ_VER, CPIA_MIN_VER, CPIA_PATCH_VER);
270 out += sprintf(out, "CPIA Version: %d.%02d (%d.%d)\n",
271 cam->params.version.firmwareVersion,
272 cam->params.version.firmwareRevision,
273 cam->params.version.vcVersion,
274 cam->params.version.vcRevision);
275 out += sprintf(out, "CPIA PnP-ID: %04x:%04x:%04x\n",
276 cam->params.pnpID.vendor, cam->params.pnpID.product,
277 cam->params.pnpID.deviceRevision);
278 out += sprintf(out, "VP-Version: %d.%d %04x\n",
279 cam->params.vpVersion.vpVersion,
280 cam->params.vpVersion.vpRevision,
281 cam->params.vpVersion.cameraHeadID);
283 out += sprintf(out, "system_state: %#04x\n",
284 cam->params.status.systemState);
285 out += sprintf(out, "grab_state: %#04x\n",
286 cam->params.status.grabState);
287 out += sprintf(out, "stream_state: %#04x\n",
288 cam->params.status.streamState);
289 out += sprintf(out, "fatal_error: %#04x\n",
290 cam->params.status.fatalError);
291 out += sprintf(out, "cmd_error: %#04x\n",
292 cam->params.status.cmdError);
293 out += sprintf(out, "debug_flags: %#04x\n",
294 cam->params.status.debugFlags);
295 out += sprintf(out, "vp_status: %#04x\n",
296 cam->params.status.vpStatus);
297 out += sprintf(out, "error_code: %#04x\n",
298 cam->params.status.errorCode);
299 /* QX3 specific entries */
300 if (cam->params.qx3.qx3_detected) {
301 out += sprintf(out, "button: %4d\n",
302 cam->params.qx3.button);
303 out += sprintf(out, "cradled: %4d\n",
304 cam->params.qx3.cradled);
306 out += sprintf(out, "video_size: %s\n",
307 cam->params.format.videoSize == VIDEOSIZE_CIF ?
309 out += sprintf(out, "roi: (%3d, %3d) to (%3d, %3d)\n",
310 cam->params.roi.colStart*8,
311 cam->params.roi.rowStart*4,
312 cam->params.roi.colEnd*8,
313 cam->params.roi.rowEnd*4);
314 out += sprintf(out, "actual_fps: %3d\n", cam->fps);
315 out += sprintf(out, "transfer_rate: %4dkB/s\n",
318 out += sprintf(out, "\nread-write\n");
319 out += sprintf(out, "----------------------- current min"
320 " max default comment\n");
321 out += sprintf(out, "brightness: %8d %8d %8d %8d\n",
322 cam->params.colourParams.brightness, 0, 100, 50);
323 if (cam->params.version.firmwareVersion == 1 &&
324 cam->params.version.firmwareRevision == 2)
325 /* 1-02 firmware limits contrast to 80 */
330 out += sprintf(out, "contrast: %8d %8d %8d %8d"
332 cam->params.colourParams.contrast, 0, tmp, 48);
333 out += sprintf(out, "saturation: %8d %8d %8d %8d\n",
334 cam->params.colourParams.saturation, 0, 100, 50);
335 tmp = (25000+5000*cam->params.sensorFps.baserate)/
336 (1<<cam->params.sensorFps.divisor);
337 out += sprintf(out, "sensor_fps: %4d.%03d %8d %8d %8d\n",
338 tmp/1000, tmp%1000, 3, 30, 15);
339 out += sprintf(out, "stream_start_line: %8d %8d %8d %8d\n",
340 2*cam->params.streamStartLine, 0,
341 cam->params.format.videoSize == VIDEOSIZE_CIF ? 288:144,
342 cam->params.format.videoSize == VIDEOSIZE_CIF ? 240:120);
343 out += sprintf(out, "sub_sample: %8s %8s %8s %8s\n",
344 cam->params.format.subSample == SUBSAMPLE_420 ?
345 "420" : "422", "420", "422", "422");
346 out += sprintf(out, "yuv_order: %8s %8s %8s %8s\n",
347 cam->params.format.yuvOrder == YUVORDER_YUYV ?
348 "YUYV" : "UYVY", "YUYV" , "UYVY", "YUYV");
349 out += sprintf(out, "ecp_timing: %8s %8s %8s %8s\n",
350 cam->params.ecpTiming ? "slow" : "normal", "slow",
353 if (cam->params.colourBalance.balanceMode == 2) {
354 sprintf(tmpstr, "auto");
356 sprintf(tmpstr, "manual");
358 out += sprintf(out, "color_balance_mode: %8s %8s %8s"
359 " %8s\n", tmpstr, "manual", "auto", "auto");
360 out += sprintf(out, "red_gain: %8d %8d %8d %8d\n",
361 cam->params.colourBalance.redGain, 0, 212, 32);
362 out += sprintf(out, "green_gain: %8d %8d %8d %8d\n",
363 cam->params.colourBalance.greenGain, 0, 212, 6);
364 out += sprintf(out, "blue_gain: %8d %8d %8d %8d\n",
365 cam->params.colourBalance.blueGain, 0, 212, 92);
367 if (cam->params.version.firmwareVersion == 1 &&
368 cam->params.version.firmwareRevision == 2)
369 /* 1-02 firmware limits gain to 2 */
370 sprintf(tmpstr, "%8d %8d %8d", 1, 2, 2);
372 sprintf(tmpstr, "%8d %8d %8d", 1, 8, 2);
374 if (cam->params.exposure.gainMode == 0)
375 out += sprintf(out, "max_gain: unknown %28s"
376 " powers of 2\n", tmpstr);
378 out += sprintf(out, "max_gain: %8d %28s"
380 1<<(cam->params.exposure.gainMode-1), tmpstr);
382 switch(cam->params.exposure.expMode) {
385 sprintf(tmpstr, "manual");
388 sprintf(tmpstr, "auto");
391 sprintf(tmpstr, "unknown");
394 out += sprintf(out, "exposure_mode: %8s %8s %8s"
395 " %8s\n", tmpstr, "manual", "auto", "auto");
396 out += sprintf(out, "centre_weight: %8s %8s %8s %8s\n",
397 (2-cam->params.exposure.centreWeight) ? "on" : "off",
399 out += sprintf(out, "gain: %8d %8d max_gain %8d 1,2,4,8 possible\n",
400 1<<cam->params.exposure.gain, 1, 1);
401 if (cam->params.version.firmwareVersion == 1 &&
402 cam->params.version.firmwareRevision == 2)
403 /* 1-02 firmware limits fineExp/2 to 127 */
408 out += sprintf(out, "fine_exp: %8d %8d %8d %8d\n",
409 cam->params.exposure.fineExp*2, 0, tmp, 0);
410 if (cam->params.version.firmwareVersion == 1 &&
411 cam->params.version.firmwareRevision == 2)
412 /* 1-02 firmware limits coarseExpHi to 0 */
417 out += sprintf(out, "coarse_exp: %8d %8d %8d"
418 " %8d\n", cam->params.exposure.coarseExpLo+
419 256*cam->params.exposure.coarseExpHi, 0, tmp, 185);
420 out += sprintf(out, "red_comp: %8d %8d %8d %8d\n",
421 cam->params.exposure.redComp, COMP_RED, 255, COMP_RED);
422 out += sprintf(out, "green1_comp: %8d %8d %8d %8d\n",
423 cam->params.exposure.green1Comp, COMP_GREEN1, 255,
425 out += sprintf(out, "green2_comp: %8d %8d %8d %8d\n",
426 cam->params.exposure.green2Comp, COMP_GREEN2, 255,
428 out += sprintf(out, "blue_comp: %8d %8d %8d %8d\n",
429 cam->params.exposure.blueComp, COMP_BLUE, 255, COMP_BLUE);
431 out += sprintf(out, "apcor_gain1: %#8x %#8x %#8x %#8x\n",
432 cam->params.apcor.gain1, 0, 0xff, 0x1c);
433 out += sprintf(out, "apcor_gain2: %#8x %#8x %#8x %#8x\n",
434 cam->params.apcor.gain2, 0, 0xff, 0x1a);
435 out += sprintf(out, "apcor_gain4: %#8x %#8x %#8x %#8x\n",
436 cam->params.apcor.gain4, 0, 0xff, 0x2d);
437 out += sprintf(out, "apcor_gain8: %#8x %#8x %#8x %#8x\n",
438 cam->params.apcor.gain8, 0, 0xff, 0x2a);
439 out += sprintf(out, "vl_offset_gain1: %8d %8d %8d %8d\n",
440 cam->params.vlOffset.gain1, 0, 255, 24);
441 out += sprintf(out, "vl_offset_gain2: %8d %8d %8d %8d\n",
442 cam->params.vlOffset.gain2, 0, 255, 28);
443 out += sprintf(out, "vl_offset_gain4: %8d %8d %8d %8d\n",
444 cam->params.vlOffset.gain4, 0, 255, 30);
445 out += sprintf(out, "vl_offset_gain8: %8d %8d %8d %8d\n",
446 cam->params.vlOffset.gain8, 0, 255, 30);
447 out += sprintf(out, "flicker_control: %8s %8s %8s %8s\n",
448 cam->params.flickerControl.flickerMode ? "on" : "off",
450 out += sprintf(out, "mains_frequency: %8d %8d %8d %8d"
452 cam->mainsFreq ? 60 : 50, 50, 60, 50);
453 if(cam->params.flickerControl.allowableOverExposure < 0)
454 out += sprintf(out, "allowable_overexposure: %4dauto auto %8d auto\n",
455 -cam->params.flickerControl.allowableOverExposure,
458 out += sprintf(out, "allowable_overexposure: %8d auto %8d auto\n",
459 cam->params.flickerControl.allowableOverExposure,
461 out += sprintf(out, "compression_mode: ");
462 switch(cam->params.compression.mode) {
463 case CPIA_COMPRESSION_NONE:
464 out += sprintf(out, "%8s", "none");
466 case CPIA_COMPRESSION_AUTO:
467 out += sprintf(out, "%8s", "auto");
469 case CPIA_COMPRESSION_MANUAL:
470 out += sprintf(out, "%8s", "manual");
473 out += sprintf(out, "%8s", "unknown");
476 out += sprintf(out, " none,auto,manual auto\n");
477 out += sprintf(out, "decimation_enable: %8s %8s %8s %8s\n",
478 cam->params.compression.decimation ==
479 DECIMATION_ENAB ? "on":"off", "off", "on",
481 out += sprintf(out, "compression_target: %9s %9s %9s %9s\n",
482 cam->params.compressionTarget.frTargeting ==
483 CPIA_COMPRESSION_TARGET_FRAMERATE ?
484 "framerate":"quality",
485 "framerate", "quality", "quality");
486 out += sprintf(out, "target_framerate: %8d %8d %8d %8d\n",
487 cam->params.compressionTarget.targetFR, 1, 30, 15);
488 out += sprintf(out, "target_quality: %8d %8d %8d %8d\n",
489 cam->params.compressionTarget.targetQ, 1, 64, 5);
490 out += sprintf(out, "y_threshold: %8d %8d %8d %8d\n",
491 cam->params.yuvThreshold.yThreshold, 0, 31, 6);
492 out += sprintf(out, "uv_threshold: %8d %8d %8d %8d\n",
493 cam->params.yuvThreshold.uvThreshold, 0, 31, 6);
494 out += sprintf(out, "hysteresis: %8d %8d %8d %8d\n",
495 cam->params.compressionParams.hysteresis, 0, 255, 3);
496 out += sprintf(out, "threshold_max: %8d %8d %8d %8d\n",
497 cam->params.compressionParams.threshMax, 0, 255, 11);
498 out += sprintf(out, "small_step: %8d %8d %8d %8d\n",
499 cam->params.compressionParams.smallStep, 0, 255, 1);
500 out += sprintf(out, "large_step: %8d %8d %8d %8d\n",
501 cam->params.compressionParams.largeStep, 0, 255, 3);
502 out += sprintf(out, "decimation_hysteresis: %8d %8d %8d %8d\n",
503 cam->params.compressionParams.decimationHysteresis,
505 out += sprintf(out, "fr_diff_step_thresh: %8d %8d %8d %8d\n",
506 cam->params.compressionParams.frDiffStepThresh,
508 out += sprintf(out, "q_diff_step_thresh: %8d %8d %8d %8d\n",
509 cam->params.compressionParams.qDiffStepThresh,
511 out += sprintf(out, "decimation_thresh_mod: %8d %8d %8d %8d\n",
512 cam->params.compressionParams.decimationThreshMod,
514 /* QX3 specific entries */
515 if (cam->params.qx3.qx3_detected) {
516 out += sprintf(out, "toplight: %8s %8s %8s %8s\n",
517 cam->params.qx3.toplight ? "on" : "off",
519 out += sprintf(out, "bottomlight: %8s %8s %8s %8s\n",
520 cam->params.qx3.bottomlight ? "on" : "off",
528 if (len <= 0) return 0;
537 static int match(char *checkstr, char **buffer, unsigned long *count,
538 int *find_colon, int *err)
540 int ret, colon_found = 1;
541 int len = strlen(checkstr);
542 ret = (len <= *count && strncmp(*buffer, checkstr, len) == 0);
548 while (*count && (**buffer == ' ' || **buffer == '\t' ||
549 (!colon_found && **buffer == ':'))) {
555 if (!*count || !colon_found)
563 static unsigned long int value(char **buffer, unsigned long *count, int *err)
566 unsigned long int ret;
567 ret = simple_strtoul(*buffer, &p, 0);
571 *count -= p - *buffer;
577 static int cpia_write_proc(struct file *file, const char __user *buf,
578 unsigned long count, void *data)
580 struct cam_data *cam = data;
581 struct cam_params new_params;
583 int retval, find_colon;
585 unsigned long val = 0;
586 u32 command_flags = 0;
590 * This code to copy from buf to page is shamelessly copied
591 * from the comx driver
593 if (count > PAGE_SIZE) {
594 printk(KERN_ERR "count is %lu > %d!!!\n", count, (int)PAGE_SIZE);
598 if (!(page = (char *)__get_free_page(GFP_KERNEL))) return -ENOMEM;
600 if(copy_from_user(page, buf, count))
606 if (page[count-1] == '\n')
607 page[count-1] = '\0';
608 else if (count < PAGE_SIZE)
610 else if (page[count]) {
617 if (mutex_lock_interruptible(&cam->param_lock))
621 * Skip over leading whitespace
623 while (count && isspace(*buffer)) {
628 memcpy(&new_params, &cam->params, sizeof(struct cam_params));
629 new_mains = cam->mainsFreq;
631 #define MATCH(x) (match(x, &buffer, &count, &find_colon, &retval))
632 #define VALUE (value(&buffer,&count, &retval))
633 #define FIRMWARE_VERSION(x,y) (new_params.version.firmwareVersion == (x) && \
634 new_params.version.firmwareRevision == (y))
637 while (count && !retval) {
639 if (MATCH("brightness")) {
645 new_params.colourParams.brightness = val;
649 command_flags |= COMMAND_SETCOLOURPARAMS;
650 if(new_params.flickerControl.allowableOverExposure < 0)
651 new_params.flickerControl.allowableOverExposure =
652 -find_over_exposure(new_params.colourParams.brightness);
653 if(new_params.flickerControl.flickerMode != 0)
654 command_flags |= COMMAND_SETFLICKERCTRL;
656 } else if (MATCH("contrast")) {
662 /* contrast is in steps of 8, so round*/
663 val = ((val + 3) / 8) * 8;
664 /* 1-02 firmware limits contrast to 80*/
665 if (FIRMWARE_VERSION(1,2) && val > 80)
668 new_params.colourParams.contrast = val;
672 command_flags |= COMMAND_SETCOLOURPARAMS;
673 } else if (MATCH("saturation")) {
679 new_params.colourParams.saturation = val;
683 command_flags |= COMMAND_SETCOLOURPARAMS;
684 } else if (MATCH("sensor_fps")) {
689 /* find values so that sensorFPS is minimized,
694 new_params.sensorFps.divisor = 0;
695 new_params.sensorFps.baserate = 1;
696 } else if (val > 15) {
697 new_params.sensorFps.divisor = 0;
698 new_params.sensorFps.baserate = 0;
699 } else if (val > 12) {
700 new_params.sensorFps.divisor = 1;
701 new_params.sensorFps.baserate = 1;
702 } else if (val > 7) {
703 new_params.sensorFps.divisor = 1;
704 new_params.sensorFps.baserate = 0;
705 } else if (val > 6) {
706 new_params.sensorFps.divisor = 2;
707 new_params.sensorFps.baserate = 1;
708 } else if (val > 3) {
709 new_params.sensorFps.divisor = 2;
710 new_params.sensorFps.baserate = 0;
712 new_params.sensorFps.divisor = 3;
713 /* Either base rate would work here */
714 new_params.sensorFps.baserate = 1;
716 new_params.flickerControl.coarseJump =
717 flicker_jumps[new_mains]
718 [new_params.sensorFps.baserate]
719 [new_params.sensorFps.divisor];
720 if (new_params.flickerControl.flickerMode)
721 command_flags |= COMMAND_SETFLICKERCTRL;
723 command_flags |= COMMAND_SETSENSORFPS;
724 cam->exposure_status = EXPOSURE_NORMAL;
725 } else if (MATCH("stream_start_line")) {
732 if (new_params.format.videoSize == VIDEOSIZE_QCIF)
735 new_params.streamStartLine = val/2;
739 } else if (MATCH("sub_sample")) {
740 if (!retval && MATCH("420"))
741 new_params.format.subSample = SUBSAMPLE_420;
742 else if (!retval && MATCH("422"))
743 new_params.format.subSample = SUBSAMPLE_422;
747 command_flags |= COMMAND_SETFORMAT;
748 } else if (MATCH("yuv_order")) {
749 if (!retval && MATCH("YUYV"))
750 new_params.format.yuvOrder = YUVORDER_YUYV;
751 else if (!retval && MATCH("UYVY"))
752 new_params.format.yuvOrder = YUVORDER_UYVY;
756 command_flags |= COMMAND_SETFORMAT;
757 } else if (MATCH("ecp_timing")) {
758 if (!retval && MATCH("normal"))
759 new_params.ecpTiming = 0;
760 else if (!retval && MATCH("slow"))
761 new_params.ecpTiming = 1;
765 command_flags |= COMMAND_SETECPTIMING;
766 } else if (MATCH("color_balance_mode")) {
767 if (!retval && MATCH("manual"))
768 new_params.colourBalance.balanceMode = 3;
769 else if (!retval && MATCH("auto"))
770 new_params.colourBalance.balanceMode = 2;
774 command_flags |= COMMAND_SETCOLOURBALANCE;
775 } else if (MATCH("red_gain")) {
781 new_params.colourBalance.redGain = val;
782 new_params.colourBalance.balanceMode = 1;
786 command_flags |= COMMAND_SETCOLOURBALANCE;
787 } else if (MATCH("green_gain")) {
793 new_params.colourBalance.greenGain = val;
794 new_params.colourBalance.balanceMode = 1;
798 command_flags |= COMMAND_SETCOLOURBALANCE;
799 } else if (MATCH("blue_gain")) {
805 new_params.colourBalance.blueGain = val;
806 new_params.colourBalance.balanceMode = 1;
810 command_flags |= COMMAND_SETCOLOURBALANCE;
811 } else if (MATCH("max_gain")) {
816 /* 1-02 firmware limits gain to 2 */
817 if (FIRMWARE_VERSION(1,2) && val > 2)
821 new_params.exposure.gainMode = 1;
824 new_params.exposure.gainMode = 2;
827 new_params.exposure.gainMode = 3;
830 new_params.exposure.gainMode = 4;
837 command_flags |= COMMAND_SETEXPOSURE;
838 } else if (MATCH("exposure_mode")) {
839 if (!retval && MATCH("auto"))
840 new_params.exposure.expMode = 2;
841 else if (!retval && MATCH("manual")) {
842 if (new_params.exposure.expMode == 2)
843 new_params.exposure.expMode = 3;
844 if(new_params.flickerControl.flickerMode != 0)
845 command_flags |= COMMAND_SETFLICKERCTRL;
846 new_params.flickerControl.flickerMode = 0;
850 command_flags |= COMMAND_SETEXPOSURE;
851 } else if (MATCH("centre_weight")) {
852 if (!retval && MATCH("on"))
853 new_params.exposure.centreWeight = 1;
854 else if (!retval && MATCH("off"))
855 new_params.exposure.centreWeight = 2;
859 command_flags |= COMMAND_SETEXPOSURE;
860 } else if (MATCH("gain")) {
867 new_params.exposure.gain = 0;
870 new_params.exposure.gain = 1;
873 new_params.exposure.gain = 2;
876 new_params.exposure.gain = 3;
882 new_params.exposure.expMode = 1;
883 if(new_params.flickerControl.flickerMode != 0)
884 command_flags |= COMMAND_SETFLICKERCTRL;
885 new_params.flickerControl.flickerMode = 0;
886 command_flags |= COMMAND_SETEXPOSURE;
887 if (new_params.exposure.gain >
888 new_params.exposure.gainMode-1)
891 } else if (MATCH("fine_exp")) {
897 /* 1-02 firmware limits fineExp/2 to 127*/
898 if (FIRMWARE_VERSION(1,2) && val > 127)
900 new_params.exposure.fineExp = val;
901 new_params.exposure.expMode = 1;
902 command_flags |= COMMAND_SETEXPOSURE;
903 if(new_params.flickerControl.flickerMode != 0)
904 command_flags |= COMMAND_SETFLICKERCTRL;
905 new_params.flickerControl.flickerMode = 0;
906 command_flags |= COMMAND_SETFLICKERCTRL;
910 } else if (MATCH("coarse_exp")) {
915 if (val <= MAX_EXP) {
916 if (FIRMWARE_VERSION(1,2) &&
919 new_params.exposure.coarseExpLo =
921 new_params.exposure.coarseExpHi =
923 new_params.exposure.expMode = 1;
924 command_flags |= COMMAND_SETEXPOSURE;
925 if(new_params.flickerControl.flickerMode != 0)
926 command_flags |= COMMAND_SETFLICKERCTRL;
927 new_params.flickerControl.flickerMode = 0;
928 command_flags |= COMMAND_SETFLICKERCTRL;
932 } else if (MATCH("red_comp")) {
937 if (val >= COMP_RED && val <= 255) {
938 new_params.exposure.redComp = val;
939 new_params.exposure.compMode = 1;
940 command_flags |= COMMAND_SETEXPOSURE;
944 } else if (MATCH("green1_comp")) {
949 if (val >= COMP_GREEN1 && val <= 255) {
950 new_params.exposure.green1Comp = val;
951 new_params.exposure.compMode = 1;
952 command_flags |= COMMAND_SETEXPOSURE;
956 } else if (MATCH("green2_comp")) {
961 if (val >= COMP_GREEN2 && val <= 255) {
962 new_params.exposure.green2Comp = val;
963 new_params.exposure.compMode = 1;
964 command_flags |= COMMAND_SETEXPOSURE;
968 } else if (MATCH("blue_comp")) {
973 if (val >= COMP_BLUE && val <= 255) {
974 new_params.exposure.blueComp = val;
975 new_params.exposure.compMode = 1;
976 command_flags |= COMMAND_SETEXPOSURE;
980 } else if (MATCH("apcor_gain1")) {
985 command_flags |= COMMAND_SETAPCOR;
987 new_params.apcor.gain1 = val;
991 } else if (MATCH("apcor_gain2")) {
996 command_flags |= COMMAND_SETAPCOR;
998 new_params.apcor.gain2 = val;
1002 } else if (MATCH("apcor_gain4")) {
1007 command_flags |= COMMAND_SETAPCOR;
1009 new_params.apcor.gain4 = val;
1013 } else if (MATCH("apcor_gain8")) {
1018 command_flags |= COMMAND_SETAPCOR;
1020 new_params.apcor.gain8 = val;
1024 } else if (MATCH("vl_offset_gain1")) {
1030 new_params.vlOffset.gain1 = val;
1034 command_flags |= COMMAND_SETVLOFFSET;
1035 } else if (MATCH("vl_offset_gain2")) {
1041 new_params.vlOffset.gain2 = val;
1045 command_flags |= COMMAND_SETVLOFFSET;
1046 } else if (MATCH("vl_offset_gain4")) {
1052 new_params.vlOffset.gain4 = val;
1056 command_flags |= COMMAND_SETVLOFFSET;
1057 } else if (MATCH("vl_offset_gain8")) {
1063 new_params.vlOffset.gain8 = val;
1067 command_flags |= COMMAND_SETVLOFFSET;
1068 } else if (MATCH("flicker_control")) {
1069 if (!retval && MATCH("on")) {
1070 set_flicker(&new_params, &command_flags, 1);
1071 } else if (!retval && MATCH("off")) {
1072 set_flicker(&new_params, &command_flags, 0);
1076 command_flags |= COMMAND_SETFLICKERCTRL;
1077 } else if (MATCH("mains_frequency")) {
1078 if (!retval && MATCH("50")) {
1080 new_params.flickerControl.coarseJump =
1081 flicker_jumps[new_mains]
1082 [new_params.sensorFps.baserate]
1083 [new_params.sensorFps.divisor];
1084 if (new_params.flickerControl.flickerMode)
1085 command_flags |= COMMAND_SETFLICKERCTRL;
1086 } else if (!retval && MATCH("60")) {
1088 new_params.flickerControl.coarseJump =
1089 flicker_jumps[new_mains]
1090 [new_params.sensorFps.baserate]
1091 [new_params.sensorFps.divisor];
1092 if (new_params.flickerControl.flickerMode)
1093 command_flags |= COMMAND_SETFLICKERCTRL;
1096 } else if (MATCH("allowable_overexposure")) {
1097 if (!retval && MATCH("auto")) {
1098 new_params.flickerControl.allowableOverExposure =
1099 -find_over_exposure(new_params.colourParams.brightness);
1100 if(new_params.flickerControl.flickerMode != 0)
1101 command_flags |= COMMAND_SETFLICKERCTRL;
1108 new_params.flickerControl.
1109 allowableOverExposure = val;
1110 if(new_params.flickerControl.flickerMode != 0)
1111 command_flags |= COMMAND_SETFLICKERCTRL;
1116 } else if (MATCH("compression_mode")) {
1117 if (!retval && MATCH("none"))
1118 new_params.compression.mode =
1119 CPIA_COMPRESSION_NONE;
1120 else if (!retval && MATCH("auto"))
1121 new_params.compression.mode =
1122 CPIA_COMPRESSION_AUTO;
1123 else if (!retval && MATCH("manual"))
1124 new_params.compression.mode =
1125 CPIA_COMPRESSION_MANUAL;
1129 command_flags |= COMMAND_SETCOMPRESSION;
1130 } else if (MATCH("decimation_enable")) {
1131 if (!retval && MATCH("off"))
1132 new_params.compression.decimation = 0;
1133 else if (!retval && MATCH("on"))
1134 new_params.compression.decimation = 1;
1138 command_flags |= COMMAND_SETCOMPRESSION;
1139 } else if (MATCH("compression_target")) {
1140 if (!retval && MATCH("quality"))
1141 new_params.compressionTarget.frTargeting =
1142 CPIA_COMPRESSION_TARGET_QUALITY;
1143 else if (!retval && MATCH("framerate"))
1144 new_params.compressionTarget.frTargeting =
1145 CPIA_COMPRESSION_TARGET_FRAMERATE;
1149 command_flags |= COMMAND_SETCOMPRESSIONTARGET;
1150 } else if (MATCH("target_framerate")) {
1155 if(val > 0 && val <= 30)
1156 new_params.compressionTarget.targetFR = val;
1160 command_flags |= COMMAND_SETCOMPRESSIONTARGET;
1161 } else if (MATCH("target_quality")) {
1166 if(val > 0 && val <= 64)
1167 new_params.compressionTarget.targetQ = val;
1171 command_flags |= COMMAND_SETCOMPRESSIONTARGET;
1172 } else if (MATCH("y_threshold")) {
1178 new_params.yuvThreshold.yThreshold = val;
1182 command_flags |= COMMAND_SETYUVTHRESH;
1183 } else if (MATCH("uv_threshold")) {
1189 new_params.yuvThreshold.uvThreshold = val;
1193 command_flags |= COMMAND_SETYUVTHRESH;
1194 } else if (MATCH("hysteresis")) {
1200 new_params.compressionParams.hysteresis = val;
1204 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1205 } else if (MATCH("threshold_max")) {
1211 new_params.compressionParams.threshMax = val;
1215 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1216 } else if (MATCH("small_step")) {
1222 new_params.compressionParams.smallStep = val;
1226 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1227 } else if (MATCH("large_step")) {
1233 new_params.compressionParams.largeStep = val;
1237 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1238 } else if (MATCH("decimation_hysteresis")) {
1244 new_params.compressionParams.decimationHysteresis = val;
1248 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1249 } else if (MATCH("fr_diff_step_thresh")) {
1255 new_params.compressionParams.frDiffStepThresh = val;
1259 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1260 } else if (MATCH("q_diff_step_thresh")) {
1266 new_params.compressionParams.qDiffStepThresh = val;
1270 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1271 } else if (MATCH("decimation_thresh_mod")) {
1277 new_params.compressionParams.decimationThreshMod = val;
1281 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1282 } else if (MATCH("toplight")) {
1283 if (!retval && MATCH("on"))
1284 new_params.qx3.toplight = 1;
1285 else if (!retval && MATCH("off"))
1286 new_params.qx3.toplight = 0;
1289 command_flags |= COMMAND_SETLIGHTS;
1290 } else if (MATCH("bottomlight")) {
1291 if (!retval && MATCH("on"))
1292 new_params.qx3.bottomlight = 1;
1293 else if (!retval && MATCH("off"))
1294 new_params.qx3.bottomlight = 0;
1297 command_flags |= COMMAND_SETLIGHTS;
1299 DBG("No match found\n");
1304 while (count && isspace(*buffer) && *buffer != '\n') {
1309 if (*buffer == '\0' && count != 1)
1311 else if (*buffer != '\n' && *buffer != ';' &&
1323 #undef FIRMWARE_VERSION
1325 if (command_flags & COMMAND_SETCOLOURPARAMS) {
1326 /* Adjust cam->vp to reflect these changes */
1327 cam->vp.brightness =
1328 new_params.colourParams.brightness*65535/100;
1330 new_params.colourParams.contrast*65535/100;
1332 new_params.colourParams.saturation*65535/100;
1334 if((command_flags & COMMAND_SETEXPOSURE) &&
1335 new_params.exposure.expMode == 2)
1336 cam->exposure_status = EXPOSURE_NORMAL;
1338 memcpy(&cam->params, &new_params, sizeof(struct cam_params));
1339 cam->mainsFreq = new_mains;
1340 cam->cmd_queue |= command_flags;
1343 DBG("error: %d\n", retval);
1345 mutex_unlock(&cam->param_lock);
1348 free_page((unsigned long)page);
1352 static void create_proc_cpia_cam(struct cam_data *cam)
1355 struct proc_dir_entry *ent;
1357 if (!cpia_proc_root || !cam)
1360 sprintf(name, "video%d", cam->vdev.minor);
1362 ent = create_proc_entry(name, S_IFREG|S_IRUGO|S_IWUSR, cpia_proc_root);
1367 ent->read_proc = cpia_read_proc;
1368 ent->write_proc = cpia_write_proc;
1370 size of the proc entry is 3736 bytes for the standard webcam;
1371 the extra features of the QX3 microscope add 189 bytes.
1372 (we have not yet probed the camera to see which type it is).
1374 ent->size = 3736 + 189;
1375 cam->proc_entry = ent;
1378 static void destroy_proc_cpia_cam(struct cam_data *cam)
1382 if (!cam || !cam->proc_entry)
1385 sprintf(name, "video%d", cam->vdev.minor);
1386 remove_proc_entry(name, cpia_proc_root);
1387 cam->proc_entry = NULL;
1390 static void proc_cpia_create(void)
1392 cpia_proc_root = proc_mkdir("cpia", NULL);
1395 cpia_proc_root->owner = THIS_MODULE;
1397 LOG("Unable to initialise /proc/cpia\n");
1400 static void __exit proc_cpia_destroy(void)
1402 remove_proc_entry("cpia", NULL);
1404 #endif /* CONFIG_PROC_FS */
1406 /* ----------------------- debug functions ---------------------- */
1408 #define printstatus(cam) \
1409 DBG("%02x %02x %02x %02x %02x %02x %02x %02x\n",\
1410 cam->params.status.systemState, cam->params.status.grabState, \
1411 cam->params.status.streamState, cam->params.status.fatalError, \
1412 cam->params.status.cmdError, cam->params.status.debugFlags, \
1413 cam->params.status.vpStatus, cam->params.status.errorCode);
1415 /* ----------------------- v4l helpers -------------------------- */
1417 /* supported frame palettes and depths */
1418 static inline int valid_mode(u16 palette, u16 depth)
1420 if ((palette == VIDEO_PALETTE_YUV422 && depth == 16) ||
1421 (palette == VIDEO_PALETTE_YUYV && depth == 16))
1424 if (colorspace_conv)
1425 return (palette == VIDEO_PALETTE_GREY && depth == 8) ||
1426 (palette == VIDEO_PALETTE_RGB555 && depth == 16) ||
1427 (palette == VIDEO_PALETTE_RGB565 && depth == 16) ||
1428 (palette == VIDEO_PALETTE_RGB24 && depth == 24) ||
1429 (palette == VIDEO_PALETTE_RGB32 && depth == 32) ||
1430 (palette == VIDEO_PALETTE_UYVY && depth == 16);
1435 static int match_videosize( int width, int height )
1437 /* return the best match, where 'best' is as always
1438 * the largest that is not bigger than what is requested. */
1439 if (width>=352 && height>=288)
1440 return VIDEOSIZE_352_288; /* CIF */
1442 if (width>=320 && height>=240)
1443 return VIDEOSIZE_320_240; /* SIF */
1445 if (width>=288 && height>=216)
1446 return VIDEOSIZE_288_216;
1448 if (width>=256 && height>=192)
1449 return VIDEOSIZE_256_192;
1451 if (width>=224 && height>=168)
1452 return VIDEOSIZE_224_168;
1454 if (width>=192 && height>=144)
1455 return VIDEOSIZE_192_144;
1457 if (width>=176 && height>=144)
1458 return VIDEOSIZE_176_144; /* QCIF */
1460 if (width>=160 && height>=120)
1461 return VIDEOSIZE_160_120; /* QSIF */
1463 if (width>=128 && height>=96)
1464 return VIDEOSIZE_128_96;
1466 if (width>=88 && height>=72)
1467 return VIDEOSIZE_88_72;
1469 if (width>=64 && height>=48)
1470 return VIDEOSIZE_64_48;
1472 if (width>=48 && height>=48)
1473 return VIDEOSIZE_48_48;
1478 /* these are the capture sizes we support */
1479 static void set_vw_size(struct cam_data *cam)
1481 /* the col/row/start/end values are the result of simple math */
1482 /* study the SetROI-command in cpia developers guide p 2-22 */
1483 /* streamStartLine is set to the recommended value in the cpia */
1484 /* developers guide p 3-37 */
1485 switch(cam->video_size) {
1487 cam->vw.width = 352;
1488 cam->vw.height = 288;
1489 cam->params.format.videoSize=VIDEOSIZE_CIF;
1490 cam->params.roi.colStart=0;
1491 cam->params.roi.rowStart=0;
1492 cam->params.streamStartLine = 120;
1495 cam->vw.width = 320;
1496 cam->vw.height = 240;
1497 cam->params.format.videoSize=VIDEOSIZE_CIF;
1498 cam->params.roi.colStart=2;
1499 cam->params.roi.rowStart=6;
1500 cam->params.streamStartLine = 120;
1502 case VIDEOSIZE_288_216:
1503 cam->vw.width = 288;
1504 cam->vw.height = 216;
1505 cam->params.format.videoSize=VIDEOSIZE_CIF;
1506 cam->params.roi.colStart=4;
1507 cam->params.roi.rowStart=9;
1508 cam->params.streamStartLine = 120;
1510 case VIDEOSIZE_256_192:
1511 cam->vw.width = 256;
1512 cam->vw.height = 192;
1513 cam->params.format.videoSize=VIDEOSIZE_CIF;
1514 cam->params.roi.colStart=6;
1515 cam->params.roi.rowStart=12;
1516 cam->params.streamStartLine = 120;
1518 case VIDEOSIZE_224_168:
1519 cam->vw.width = 224;
1520 cam->vw.height = 168;
1521 cam->params.format.videoSize=VIDEOSIZE_CIF;
1522 cam->params.roi.colStart=8;
1523 cam->params.roi.rowStart=15;
1524 cam->params.streamStartLine = 120;
1526 case VIDEOSIZE_192_144:
1527 cam->vw.width = 192;
1528 cam->vw.height = 144;
1529 cam->params.format.videoSize=VIDEOSIZE_CIF;
1530 cam->params.roi.colStart=10;
1531 cam->params.roi.rowStart=18;
1532 cam->params.streamStartLine = 120;
1534 case VIDEOSIZE_QCIF:
1535 cam->vw.width = 176;
1536 cam->vw.height = 144;
1537 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1538 cam->params.roi.colStart=0;
1539 cam->params.roi.rowStart=0;
1540 cam->params.streamStartLine = 60;
1542 case VIDEOSIZE_QSIF:
1543 cam->vw.width = 160;
1544 cam->vw.height = 120;
1545 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1546 cam->params.roi.colStart=1;
1547 cam->params.roi.rowStart=3;
1548 cam->params.streamStartLine = 60;
1550 case VIDEOSIZE_128_96:
1551 cam->vw.width = 128;
1552 cam->vw.height = 96;
1553 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1554 cam->params.roi.colStart=3;
1555 cam->params.roi.rowStart=6;
1556 cam->params.streamStartLine = 60;
1558 case VIDEOSIZE_88_72:
1560 cam->vw.height = 72;
1561 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1562 cam->params.roi.colStart=5;
1563 cam->params.roi.rowStart=9;
1564 cam->params.streamStartLine = 60;
1566 case VIDEOSIZE_64_48:
1568 cam->vw.height = 48;
1569 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1570 cam->params.roi.colStart=7;
1571 cam->params.roi.rowStart=12;
1572 cam->params.streamStartLine = 60;
1574 case VIDEOSIZE_48_48:
1576 cam->vw.height = 48;
1577 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1578 cam->params.roi.colStart=8;
1579 cam->params.roi.rowStart=6;
1580 cam->params.streamStartLine = 60;
1583 LOG("bad videosize value: %d\n", cam->video_size);
1587 if(cam->vc.width == 0)
1588 cam->vc.width = cam->vw.width;
1589 if(cam->vc.height == 0)
1590 cam->vc.height = cam->vw.height;
1592 cam->params.roi.colStart += cam->vc.x >> 3;
1593 cam->params.roi.colEnd = cam->params.roi.colStart +
1594 (cam->vc.width >> 3);
1595 cam->params.roi.rowStart += cam->vc.y >> 2;
1596 cam->params.roi.rowEnd = cam->params.roi.rowStart +
1597 (cam->vc.height >> 2);
1602 static int allocate_frame_buf(struct cam_data *cam)
1606 cam->frame_buf = rvmalloc(FRAME_NUM * CPIA_MAX_FRAME_SIZE);
1607 if (!cam->frame_buf)
1610 for (i = 0; i < FRAME_NUM; i++)
1611 cam->frame[i].data = cam->frame_buf + i * CPIA_MAX_FRAME_SIZE;
1616 static int free_frame_buf(struct cam_data *cam)
1620 rvfree(cam->frame_buf, FRAME_NUM*CPIA_MAX_FRAME_SIZE);
1621 cam->frame_buf = NULL;
1622 for (i=0; i < FRAME_NUM; i++)
1623 cam->frame[i].data = NULL;
1629 static inline void free_frames(struct cpia_frame frame[FRAME_NUM])
1633 for (i=0; i < FRAME_NUM; i++)
1634 frame[i].state = FRAME_UNUSED;
1638 /**********************************************************************
1642 **********************************************************************/
1643 /* send an arbitrary command to the camera */
1644 static int do_command(struct cam_data *cam, u16 command, u8 a, u8 b, u8 c, u8 d)
1646 int retval, datasize;
1650 case CPIA_COMMAND_GetCPIAVersion:
1651 case CPIA_COMMAND_GetPnPID:
1652 case CPIA_COMMAND_GetCameraStatus:
1653 case CPIA_COMMAND_GetVPVersion:
1656 case CPIA_COMMAND_GetColourParams:
1657 case CPIA_COMMAND_GetColourBalance:
1658 case CPIA_COMMAND_GetExposure:
1659 mutex_lock(&cam->param_lock);
1662 case CPIA_COMMAND_ReadMCPorts:
1663 case CPIA_COMMAND_ReadVCRegs:
1671 cmd[0] = command>>8;
1672 cmd[1] = command&0xff;
1680 retval = cam->ops->transferCmd(cam->lowlevel_data, cmd, data);
1682 DBG("%x - failed, retval=%d\n", command, retval);
1683 if (command == CPIA_COMMAND_GetColourParams ||
1684 command == CPIA_COMMAND_GetColourBalance ||
1685 command == CPIA_COMMAND_GetExposure)
1686 mutex_unlock(&cam->param_lock);
1689 case CPIA_COMMAND_GetCPIAVersion:
1690 cam->params.version.firmwareVersion = data[0];
1691 cam->params.version.firmwareRevision = data[1];
1692 cam->params.version.vcVersion = data[2];
1693 cam->params.version.vcRevision = data[3];
1695 case CPIA_COMMAND_GetPnPID:
1696 cam->params.pnpID.vendor = data[0]+(((u16)data[1])<<8);
1697 cam->params.pnpID.product = data[2]+(((u16)data[3])<<8);
1698 cam->params.pnpID.deviceRevision =
1699 data[4]+(((u16)data[5])<<8);
1701 case CPIA_COMMAND_GetCameraStatus:
1702 cam->params.status.systemState = data[0];
1703 cam->params.status.grabState = data[1];
1704 cam->params.status.streamState = data[2];
1705 cam->params.status.fatalError = data[3];
1706 cam->params.status.cmdError = data[4];
1707 cam->params.status.debugFlags = data[5];
1708 cam->params.status.vpStatus = data[6];
1709 cam->params.status.errorCode = data[7];
1711 case CPIA_COMMAND_GetVPVersion:
1712 cam->params.vpVersion.vpVersion = data[0];
1713 cam->params.vpVersion.vpRevision = data[1];
1714 cam->params.vpVersion.cameraHeadID =
1715 data[2]+(((u16)data[3])<<8);
1717 case CPIA_COMMAND_GetColourParams:
1718 cam->params.colourParams.brightness = data[0];
1719 cam->params.colourParams.contrast = data[1];
1720 cam->params.colourParams.saturation = data[2];
1721 mutex_unlock(&cam->param_lock);
1723 case CPIA_COMMAND_GetColourBalance:
1724 cam->params.colourBalance.redGain = data[0];
1725 cam->params.colourBalance.greenGain = data[1];
1726 cam->params.colourBalance.blueGain = data[2];
1727 mutex_unlock(&cam->param_lock);
1729 case CPIA_COMMAND_GetExposure:
1730 cam->params.exposure.gain = data[0];
1731 cam->params.exposure.fineExp = data[1];
1732 cam->params.exposure.coarseExpLo = data[2];
1733 cam->params.exposure.coarseExpHi = data[3];
1734 cam->params.exposure.redComp = data[4];
1735 cam->params.exposure.green1Comp = data[5];
1736 cam->params.exposure.green2Comp = data[6];
1737 cam->params.exposure.blueComp = data[7];
1738 mutex_unlock(&cam->param_lock);
1741 case CPIA_COMMAND_ReadMCPorts:
1742 if (!cam->params.qx3.qx3_detected)
1744 /* test button press */
1745 cam->params.qx3.button = ((data[1] & 0x02) == 0);
1746 if (cam->params.qx3.button) {
1747 /* button pressed - unlock the latch */
1748 do_command(cam,CPIA_COMMAND_WriteMCPort,3,0xDF,0xDF,0);
1749 do_command(cam,CPIA_COMMAND_WriteMCPort,3,0xFF,0xFF,0);
1752 /* test whether microscope is cradled */
1753 cam->params.qx3.cradled = ((data[2] & 0x40) == 0);
1763 /* send a command to the camera with an additional data transaction */
1764 static int do_command_extended(struct cam_data *cam, u16 command,
1765 u8 a, u8 b, u8 c, u8 d,
1766 u8 e, u8 f, u8 g, u8 h,
1767 u8 i, u8 j, u8 k, u8 l)
1772 cmd[0] = command>>8;
1773 cmd[1] = command&0xff;
1789 retval = cam->ops->transferCmd(cam->lowlevel_data, cmd, data);
1791 DBG("%x - failed\n", command);
1796 /**********************************************************************
1798 * Colorspace conversion
1800 **********************************************************************/
1801 #define LIMIT(x) ((((x)>0xffffff)?0xff0000:(((x)<=0xffff)?0:(x)&0xff0000))>>16)
1803 static int convert420(unsigned char *yuv, unsigned char *rgb, int out_fmt,
1804 int linesize, int mmap_kludge)
1806 int y, u, v, r, g, b, y1;
1808 /* Odd lines use the same u and v as the previous line.
1809 * Because of compression, it is necessary to get this
1810 * information from the decoded image. */
1812 case VIDEO_PALETTE_RGB555:
1813 y = (*yuv++ - 16) * 76310;
1814 y1 = (*yuv - 16) * 76310;
1815 r = ((*(rgb+1-linesize)) & 0x7c) << 1;
1816 g = ((*(rgb-linesize)) & 0xe0) >> 4 |
1817 ((*(rgb+1-linesize)) & 0x03) << 6;
1818 b = ((*(rgb-linesize)) & 0x1f) << 3;
1819 u = (-53294 * r - 104635 * g + 157929 * b) / 5756495;
1820 v = (157968 * r - 132278 * g - 25690 * b) / 5366159;
1822 g = -25690 * u - 53294 * v;
1824 *rgb++ = ((LIMIT(g+y) & 0xf8) << 2) | (LIMIT(b+y) >> 3);
1825 *rgb++ = ((LIMIT(r+y) & 0xf8) >> 1) | (LIMIT(g+y) >> 6);
1826 *rgb++ = ((LIMIT(g+y1) & 0xf8) << 2) | (LIMIT(b+y1) >> 3);
1827 *rgb = ((LIMIT(r+y1) & 0xf8) >> 1) | (LIMIT(g+y1) >> 6);
1829 case VIDEO_PALETTE_RGB565:
1830 y = (*yuv++ - 16) * 76310;
1831 y1 = (*yuv - 16) * 76310;
1832 r = (*(rgb+1-linesize)) & 0xf8;
1833 g = ((*(rgb-linesize)) & 0xe0) >> 3 |
1834 ((*(rgb+1-linesize)) & 0x07) << 5;
1835 b = ((*(rgb-linesize)) & 0x1f) << 3;
1836 u = (-53294 * r - 104635 * g + 157929 * b) / 5756495;
1837 v = (157968 * r - 132278 * g - 25690 * b) / 5366159;
1839 g = -25690 * u - 53294 * v;
1841 *rgb++ = ((LIMIT(g+y) & 0xfc) << 3) | (LIMIT(b+y) >> 3);
1842 *rgb++ = (LIMIT(r+y) & 0xf8) | (LIMIT(g+y) >> 5);
1843 *rgb++ = ((LIMIT(g+y1) & 0xfc) << 3) | (LIMIT(b+y1) >> 3);
1844 *rgb = (LIMIT(r+y1) & 0xf8) | (LIMIT(g+y1) >> 5);
1847 case VIDEO_PALETTE_RGB24:
1848 case VIDEO_PALETTE_RGB32:
1849 y = (*yuv++ - 16) * 76310;
1850 y1 = (*yuv - 16) * 76310;
1852 r = *(rgb+2-linesize);
1853 g = *(rgb+1-linesize);
1854 b = *(rgb-linesize);
1856 r = *(rgb-linesize);
1857 g = *(rgb+1-linesize);
1858 b = *(rgb+2-linesize);
1860 u = (-53294 * r - 104635 * g + 157929 * b) / 5756495;
1861 v = (157968 * r - 132278 * g - 25690 * b) / 5366159;
1863 g = -25690 * u + -53294 * v;
1866 *rgb++ = LIMIT(b+y);
1867 *rgb++ = LIMIT(g+y);
1868 *rgb++ = LIMIT(r+y);
1869 if(out_fmt == VIDEO_PALETTE_RGB32)
1871 *rgb++ = LIMIT(b+y1);
1872 *rgb++ = LIMIT(g+y1);
1875 *rgb++ = LIMIT(r+y);
1876 *rgb++ = LIMIT(g+y);
1877 *rgb++ = LIMIT(b+y);
1878 if(out_fmt == VIDEO_PALETTE_RGB32)
1880 *rgb++ = LIMIT(r+y1);
1881 *rgb++ = LIMIT(g+y1);
1884 if(out_fmt == VIDEO_PALETTE_RGB32)
1887 case VIDEO_PALETTE_YUV422:
1888 case VIDEO_PALETTE_YUYV:
1890 u = *(rgb+1-linesize);
1892 v = *(rgb+3-linesize);
1898 case VIDEO_PALETTE_UYVY:
1899 u = *(rgb-linesize);
1901 v = *(rgb+2-linesize);
1908 case VIDEO_PALETTE_GREY:
1913 DBG("Empty: %d\n", out_fmt);
1919 static int yuvconvert(unsigned char *yuv, unsigned char *rgb, int out_fmt,
1920 int in_uyvy, int mmap_kludge)
1922 int y, u, v, r, g, b, y1;
1925 case VIDEO_PALETTE_RGB555:
1926 case VIDEO_PALETTE_RGB565:
1927 case VIDEO_PALETTE_RGB24:
1928 case VIDEO_PALETTE_RGB32:
1931 y = (*yuv++ - 16) * 76310;
1933 y1 = (*yuv - 16) * 76310;
1935 y = (*yuv++ - 16) * 76310;
1937 y1 = (*yuv++ - 16) * 76310;
1941 g = -25690 * u + -53294 * v;
1949 /* Just to avoid compiler warnings */
1956 case VIDEO_PALETTE_RGB555:
1957 *rgb++ = ((LIMIT(g+y) & 0xf8) << 2) | (LIMIT(b+y) >> 3);
1958 *rgb++ = ((LIMIT(r+y) & 0xf8) >> 1) | (LIMIT(g+y) >> 6);
1959 *rgb++ = ((LIMIT(g+y1) & 0xf8) << 2) | (LIMIT(b+y1) >> 3);
1960 *rgb = ((LIMIT(r+y1) & 0xf8) >> 1) | (LIMIT(g+y1) >> 6);
1962 case VIDEO_PALETTE_RGB565:
1963 *rgb++ = ((LIMIT(g+y) & 0xfc) << 3) | (LIMIT(b+y) >> 3);
1964 *rgb++ = (LIMIT(r+y) & 0xf8) | (LIMIT(g+y) >> 5);
1965 *rgb++ = ((LIMIT(g+y1) & 0xfc) << 3) | (LIMIT(b+y1) >> 3);
1966 *rgb = (LIMIT(r+y1) & 0xf8) | (LIMIT(g+y1) >> 5);
1968 case VIDEO_PALETTE_RGB24:
1970 *rgb++ = LIMIT(b+y);
1971 *rgb++ = LIMIT(g+y);
1972 *rgb++ = LIMIT(r+y);
1973 *rgb++ = LIMIT(b+y1);
1974 *rgb++ = LIMIT(g+y1);
1977 *rgb++ = LIMIT(r+y);
1978 *rgb++ = LIMIT(g+y);
1979 *rgb++ = LIMIT(b+y);
1980 *rgb++ = LIMIT(r+y1);
1981 *rgb++ = LIMIT(g+y1);
1985 case VIDEO_PALETTE_RGB32:
1987 *rgb++ = LIMIT(b+y);
1988 *rgb++ = LIMIT(g+y);
1989 *rgb++ = LIMIT(r+y);
1991 *rgb++ = LIMIT(b+y1);
1992 *rgb++ = LIMIT(g+y1);
1995 *rgb++ = LIMIT(r+y);
1996 *rgb++ = LIMIT(g+y);
1997 *rgb++ = LIMIT(b+y);
1999 *rgb++ = LIMIT(r+y1);
2000 *rgb++ = LIMIT(g+y1);
2004 case VIDEO_PALETTE_GREY:
2008 case VIDEO_PALETTE_YUV422:
2009 case VIDEO_PALETTE_YUYV:
2015 case VIDEO_PALETTE_UYVY:
2022 DBG("Empty: %d\n", out_fmt);
2027 static int skipcount(int count, int fmt)
2030 case VIDEO_PALETTE_GREY:
2032 case VIDEO_PALETTE_RGB555:
2033 case VIDEO_PALETTE_RGB565:
2034 case VIDEO_PALETTE_YUV422:
2035 case VIDEO_PALETTE_YUYV:
2036 case VIDEO_PALETTE_UYVY:
2038 case VIDEO_PALETTE_RGB24:
2040 case VIDEO_PALETTE_RGB32:
2047 static int parse_picture(struct cam_data *cam, int size)
2049 u8 *obuf, *ibuf, *end_obuf;
2050 int ll, in_uyvy, compressed, decimation, even_line, origsize, out_fmt;
2051 int rows, cols, linesize, subsample_422;
2053 /* make sure params don't change while we are decoding */
2054 mutex_lock(&cam->param_lock);
2056 obuf = cam->decompressed_frame.data;
2057 end_obuf = obuf+CPIA_MAX_FRAME_SIZE;
2058 ibuf = cam->raw_image;
2060 out_fmt = cam->vp.palette;
2062 if ((ibuf[0] != MAGIC_0) || (ibuf[1] != MAGIC_1)) {
2063 LOG("header not found\n");
2064 mutex_unlock(&cam->param_lock);
2068 if ((ibuf[16] != VIDEOSIZE_QCIF) && (ibuf[16] != VIDEOSIZE_CIF)) {
2069 LOG("wrong video size\n");
2070 mutex_unlock(&cam->param_lock);
2074 if (ibuf[17] != SUBSAMPLE_420 && ibuf[17] != SUBSAMPLE_422) {
2075 LOG("illegal subtype %d\n",ibuf[17]);
2076 mutex_unlock(&cam->param_lock);
2079 subsample_422 = ibuf[17] == SUBSAMPLE_422;
2081 if (ibuf[18] != YUVORDER_YUYV && ibuf[18] != YUVORDER_UYVY) {
2082 LOG("illegal yuvorder %d\n",ibuf[18]);
2083 mutex_unlock(&cam->param_lock);
2086 in_uyvy = ibuf[18] == YUVORDER_UYVY;
2088 if ((ibuf[24] != cam->params.roi.colStart) ||
2089 (ibuf[25] != cam->params.roi.colEnd) ||
2090 (ibuf[26] != cam->params.roi.rowStart) ||
2091 (ibuf[27] != cam->params.roi.rowEnd)) {
2092 LOG("ROI mismatch\n");
2093 mutex_unlock(&cam->param_lock);
2096 cols = 8*(ibuf[25] - ibuf[24]);
2097 rows = 4*(ibuf[27] - ibuf[26]);
2100 if ((ibuf[28] != NOT_COMPRESSED) && (ibuf[28] != COMPRESSED)) {
2101 LOG("illegal compression %d\n",ibuf[28]);
2102 mutex_unlock(&cam->param_lock);
2105 compressed = (ibuf[28] == COMPRESSED);
2107 if (ibuf[29] != NO_DECIMATION && ibuf[29] != DECIMATION_ENAB) {
2108 LOG("illegal decimation %d\n",ibuf[29]);
2109 mutex_unlock(&cam->param_lock);
2112 decimation = (ibuf[29] == DECIMATION_ENAB);
2114 cam->params.yuvThreshold.yThreshold = ibuf[30];
2115 cam->params.yuvThreshold.uvThreshold = ibuf[31];
2116 cam->params.status.systemState = ibuf[32];
2117 cam->params.status.grabState = ibuf[33];
2118 cam->params.status.streamState = ibuf[34];
2119 cam->params.status.fatalError = ibuf[35];
2120 cam->params.status.cmdError = ibuf[36];
2121 cam->params.status.debugFlags = ibuf[37];
2122 cam->params.status.vpStatus = ibuf[38];
2123 cam->params.status.errorCode = ibuf[39];
2124 cam->fps = ibuf[41];
2125 mutex_unlock(&cam->param_lock);
2127 linesize = skipcount(cols, out_fmt);
2128 ibuf += FRAME_HEADER_SIZE;
2129 size -= FRAME_HEADER_SIZE;
2130 ll = ibuf[0] | (ibuf[1] << 8);
2137 LOG("Insufficient data in buffer\n");
2142 if (!compressed || (compressed && !(*ibuf & 1))) {
2143 if(subsample_422 || even_line) {
2144 obuf += yuvconvert(ibuf, obuf, out_fmt,
2145 in_uyvy, cam->mmap_kludge);
2149 /* SUBSAMPLE_420 on an odd line */
2150 obuf += convert420(ibuf, obuf,
2157 /*skip compressed interval from previous frame*/
2158 obuf += skipcount(*ibuf >> 1, out_fmt);
2159 if (obuf > end_obuf) {
2160 LOG("Insufficient buffer size\n");
2169 DBG("EOL not found giving up after %d/%d"
2170 " bytes\n", origsize-size, origsize);
2174 ++ibuf; /* skip over EOL */
2176 if ((size > 3) && (ibuf[0] == EOI) && (ibuf[1] == EOI) &&
2177 (ibuf[2] == EOI) && (ibuf[3] == EOI)) {
2183 /* skip the odd lines for now */
2188 ll = ibuf[0] | (ibuf[1] << 8);
2189 ibuf += 2; /* skip over line length */
2192 even_line = !even_line;
2194 LOG("line length was not 1 but %d after %d/%d bytes\n",
2195 ll, origsize-size, origsize);
2201 /* interpolate odd rows */
2204 prev = cam->decompressed_frame.data;
2205 obuf = prev+linesize;
2206 next = obuf+linesize;
2207 for(i=1; i<rows-1; i+=2) {
2208 for(j=0; j<linesize; ++j) {
2209 *obuf++ = ((int)*prev++ + *next++) / 2;
2215 /* last row is odd, just copy previous row */
2216 memcpy(obuf, prev, linesize);
2219 cam->decompressed_frame.count = obuf-cam->decompressed_frame.data;
2221 return cam->decompressed_frame.count;
2224 /* InitStreamCap wrapper to select correct start line */
2225 static inline int init_stream_cap(struct cam_data *cam)
2227 return do_command(cam, CPIA_COMMAND_InitStreamCap,
2228 0, cam->params.streamStartLine, 0, 0);
2232 /* find_over_exposure
2233 * Finds a suitable value of OverExposure for use with SetFlickerCtrl
2234 * Some calculation is required because this value changes with the brightness
2235 * set with SetColourParameters
2237 * Parameters: Brightness - last brightness value set with SetColourParameters
2239 * Returns: OverExposure value to use with SetFlickerCtrl
2241 #define FLICKER_MAX_EXPOSURE 250
2242 #define FLICKER_ALLOWABLE_OVER_EXPOSURE 146
2243 #define FLICKER_BRIGHTNESS_CONSTANT 59
2244 static int find_over_exposure(int brightness)
2246 int MaxAllowableOverExposure, OverExposure;
2248 MaxAllowableOverExposure = FLICKER_MAX_EXPOSURE - brightness -
2249 FLICKER_BRIGHTNESS_CONSTANT;
2251 if (MaxAllowableOverExposure < FLICKER_ALLOWABLE_OVER_EXPOSURE) {
2252 OverExposure = MaxAllowableOverExposure;
2254 OverExposure = FLICKER_ALLOWABLE_OVER_EXPOSURE;
2257 return OverExposure;
2259 #undef FLICKER_MAX_EXPOSURE
2260 #undef FLICKER_ALLOWABLE_OVER_EXPOSURE
2261 #undef FLICKER_BRIGHTNESS_CONSTANT
2263 /* update various camera modes and settings */
2264 static void dispatch_commands(struct cam_data *cam)
2266 mutex_lock(&cam->param_lock);
2267 if (cam->cmd_queue==COMMAND_NONE) {
2268 mutex_unlock(&cam->param_lock);
2271 DEB_BYTE(cam->cmd_queue);
2272 DEB_BYTE(cam->cmd_queue>>8);
2273 if (cam->cmd_queue & COMMAND_SETFORMAT) {
2274 do_command(cam, CPIA_COMMAND_SetFormat,
2275 cam->params.format.videoSize,
2276 cam->params.format.subSample,
2277 cam->params.format.yuvOrder, 0);
2278 do_command(cam, CPIA_COMMAND_SetROI,
2279 cam->params.roi.colStart, cam->params.roi.colEnd,
2280 cam->params.roi.rowStart, cam->params.roi.rowEnd);
2281 cam->first_frame = 1;
2284 if (cam->cmd_queue & COMMAND_SETCOLOURPARAMS)
2285 do_command(cam, CPIA_COMMAND_SetColourParams,
2286 cam->params.colourParams.brightness,
2287 cam->params.colourParams.contrast,
2288 cam->params.colourParams.saturation, 0);
2290 if (cam->cmd_queue & COMMAND_SETAPCOR)
2291 do_command(cam, CPIA_COMMAND_SetApcor,
2292 cam->params.apcor.gain1,
2293 cam->params.apcor.gain2,
2294 cam->params.apcor.gain4,
2295 cam->params.apcor.gain8);
2297 if (cam->cmd_queue & COMMAND_SETVLOFFSET)
2298 do_command(cam, CPIA_COMMAND_SetVLOffset,
2299 cam->params.vlOffset.gain1,
2300 cam->params.vlOffset.gain2,
2301 cam->params.vlOffset.gain4,
2302 cam->params.vlOffset.gain8);
2304 if (cam->cmd_queue & COMMAND_SETEXPOSURE) {
2305 do_command_extended(cam, CPIA_COMMAND_SetExposure,
2306 cam->params.exposure.gainMode,
2308 cam->params.exposure.compMode,
2309 cam->params.exposure.centreWeight,
2310 cam->params.exposure.gain,
2311 cam->params.exposure.fineExp,
2312 cam->params.exposure.coarseExpLo,
2313 cam->params.exposure.coarseExpHi,
2314 cam->params.exposure.redComp,
2315 cam->params.exposure.green1Comp,
2316 cam->params.exposure.green2Comp,
2317 cam->params.exposure.blueComp);
2318 if(cam->params.exposure.expMode != 1) {
2319 do_command_extended(cam, CPIA_COMMAND_SetExposure,
2321 cam->params.exposure.expMode,
2323 cam->params.exposure.gain,
2324 cam->params.exposure.fineExp,
2325 cam->params.exposure.coarseExpLo,
2326 cam->params.exposure.coarseExpHi,
2331 if (cam->cmd_queue & COMMAND_SETCOLOURBALANCE) {
2332 if (cam->params.colourBalance.balanceMode == 1) {
2333 do_command(cam, CPIA_COMMAND_SetColourBalance,
2335 cam->params.colourBalance.redGain,
2336 cam->params.colourBalance.greenGain,
2337 cam->params.colourBalance.blueGain);
2338 do_command(cam, CPIA_COMMAND_SetColourBalance,
2341 if (cam->params.colourBalance.balanceMode == 2) {
2342 do_command(cam, CPIA_COMMAND_SetColourBalance,
2345 if (cam->params.colourBalance.balanceMode == 3) {
2346 do_command(cam, CPIA_COMMAND_SetColourBalance,
2351 if (cam->cmd_queue & COMMAND_SETCOMPRESSIONTARGET)
2352 do_command(cam, CPIA_COMMAND_SetCompressionTarget,
2353 cam->params.compressionTarget.frTargeting,
2354 cam->params.compressionTarget.targetFR,
2355 cam->params.compressionTarget.targetQ, 0);
2357 if (cam->cmd_queue & COMMAND_SETYUVTHRESH)
2358 do_command(cam, CPIA_COMMAND_SetYUVThresh,
2359 cam->params.yuvThreshold.yThreshold,
2360 cam->params.yuvThreshold.uvThreshold, 0, 0);
2362 if (cam->cmd_queue & COMMAND_SETCOMPRESSIONPARAMS)
2363 do_command_extended(cam, CPIA_COMMAND_SetCompressionParams,
2365 cam->params.compressionParams.hysteresis,
2366 cam->params.compressionParams.threshMax,
2367 cam->params.compressionParams.smallStep,
2368 cam->params.compressionParams.largeStep,
2369 cam->params.compressionParams.decimationHysteresis,
2370 cam->params.compressionParams.frDiffStepThresh,
2371 cam->params.compressionParams.qDiffStepThresh,
2372 cam->params.compressionParams.decimationThreshMod);
2374 if (cam->cmd_queue & COMMAND_SETCOMPRESSION)
2375 do_command(cam, CPIA_COMMAND_SetCompression,
2376 cam->params.compression.mode,
2377 cam->params.compression.decimation, 0, 0);
2379 if (cam->cmd_queue & COMMAND_SETSENSORFPS)
2380 do_command(cam, CPIA_COMMAND_SetSensorFPS,
2381 cam->params.sensorFps.divisor,
2382 cam->params.sensorFps.baserate, 0, 0);
2384 if (cam->cmd_queue & COMMAND_SETFLICKERCTRL)
2385 do_command(cam, CPIA_COMMAND_SetFlickerCtrl,
2386 cam->params.flickerControl.flickerMode,
2387 cam->params.flickerControl.coarseJump,
2388 abs(cam->params.flickerControl.allowableOverExposure),
2391 if (cam->cmd_queue & COMMAND_SETECPTIMING)
2392 do_command(cam, CPIA_COMMAND_SetECPTiming,
2393 cam->params.ecpTiming, 0, 0, 0);
2395 if (cam->cmd_queue & COMMAND_PAUSE)
2396 do_command(cam, CPIA_COMMAND_EndStreamCap, 0, 0, 0, 0);
2398 if (cam->cmd_queue & COMMAND_RESUME)
2399 init_stream_cap(cam);
2401 if (cam->cmd_queue & COMMAND_SETLIGHTS && cam->params.qx3.qx3_detected)
2403 int p1 = (cam->params.qx3.bottomlight == 0) << 1;
2404 int p2 = (cam->params.qx3.toplight == 0) << 3;
2405 do_command(cam, CPIA_COMMAND_WriteVCReg, 0x90, 0x8F, 0x50, 0);
2406 do_command(cam, CPIA_COMMAND_WriteMCPort, 2, 0, (p1|p2|0xE0), 0);
2409 cam->cmd_queue = COMMAND_NONE;
2410 mutex_unlock(&cam->param_lock);
2416 static void set_flicker(struct cam_params *params, volatile u32 *command_flags,
2419 /* Everything in here is from the Windows driver */
2420 #define FIRMWARE_VERSION(x,y) (params->version.firmwareVersion == (x) && \
2421 params->version.firmwareRevision == (y))
2422 /* define for compgain calculation */
2424 #define COMPGAIN(base, curexp, newexp) \
2425 (u8) ((((float) base - 128.0) * ((float) curexp / (float) newexp)) + 128.5)
2426 #define EXP_FROM_COMP(basecomp, curcomp, curexp) \
2427 (u16)((float)curexp * (float)(u8)(curcomp + 128) / (float)(u8)(basecomp - 128))
2429 /* equivalent functions without floating point math */
2430 #define COMPGAIN(base, curexp, newexp) \
2431 (u8)(128 + (((u32)(2*(base-128)*curexp + newexp)) / (2* newexp)) )
2432 #define EXP_FROM_COMP(basecomp, curcomp, curexp) \
2433 (u16)(((u32)(curexp * (u8)(curcomp + 128)) / (u8)(basecomp - 128)))
2437 int currentexp = params->exposure.coarseExpLo +
2438 params->exposure.coarseExpHi*256;
2441 int cj = params->flickerControl.coarseJump;
2442 params->flickerControl.flickerMode = 1;
2443 params->flickerControl.disabled = 0;
2444 if(params->exposure.expMode != 2)
2445 *command_flags |= COMMAND_SETEXPOSURE;
2446 params->exposure.expMode = 2;
2447 currentexp = currentexp << params->exposure.gain;
2448 params->exposure.gain = 0;
2449 /* round down current exposure to nearest value */
2450 startexp = (currentexp + ROUND_UP_EXP_FOR_FLICKER) / cj;
2453 startexp = (startexp * cj) - 1;
2454 if(FIRMWARE_VERSION(1,2))
2455 while(startexp > MAX_EXP_102)
2458 while(startexp > MAX_EXP)
2460 params->exposure.coarseExpLo = startexp & 0xff;
2461 params->exposure.coarseExpHi = startexp >> 8;
2462 if (currentexp > startexp) {
2463 if (currentexp > (2 * startexp))
2464 currentexp = 2 * startexp;
2465 params->exposure.redComp = COMPGAIN (COMP_RED, currentexp, startexp);
2466 params->exposure.green1Comp = COMPGAIN (COMP_GREEN1, currentexp, startexp);
2467 params->exposure.green2Comp = COMPGAIN (COMP_GREEN2, currentexp, startexp);
2468 params->exposure.blueComp = COMPGAIN (COMP_BLUE, currentexp, startexp);
2470 params->exposure.redComp = COMP_RED;
2471 params->exposure.green1Comp = COMP_GREEN1;
2472 params->exposure.green2Comp = COMP_GREEN2;
2473 params->exposure.blueComp = COMP_BLUE;
2475 if(FIRMWARE_VERSION(1,2))
2476 params->exposure.compMode = 0;
2478 params->exposure.compMode = 1;
2480 params->apcor.gain1 = 0x18;
2481 params->apcor.gain2 = 0x18;
2482 params->apcor.gain4 = 0x16;
2483 params->apcor.gain8 = 0x14;
2484 *command_flags |= COMMAND_SETAPCOR;
2486 params->flickerControl.flickerMode = 0;
2487 params->flickerControl.disabled = 1;
2488 /* Coarse = average of equivalent coarse for each comp channel */
2489 startexp = EXP_FROM_COMP(COMP_RED, params->exposure.redComp, currentexp);
2490 startexp += EXP_FROM_COMP(COMP_GREEN1, params->exposure.green1Comp, currentexp);
2491 startexp += EXP_FROM_COMP(COMP_GREEN2, params->exposure.green2Comp, currentexp);
2492 startexp += EXP_FROM_COMP(COMP_BLUE, params->exposure.blueComp, currentexp);
2493 startexp = startexp >> 2;
2494 while(startexp > MAX_EXP &&
2495 params->exposure.gain < params->exposure.gainMode-1) {
2496 startexp = startexp >> 1;
2497 ++params->exposure.gain;
2499 if(FIRMWARE_VERSION(1,2) && startexp > MAX_EXP_102)
2500 startexp = MAX_EXP_102;
2501 if(startexp > MAX_EXP)
2503 params->exposure.coarseExpLo = startexp&0xff;
2504 params->exposure.coarseExpHi = startexp >> 8;
2505 params->exposure.redComp = COMP_RED;
2506 params->exposure.green1Comp = COMP_GREEN1;
2507 params->exposure.green2Comp = COMP_GREEN2;
2508 params->exposure.blueComp = COMP_BLUE;
2509 params->exposure.compMode = 1;
2510 *command_flags |= COMMAND_SETEXPOSURE;
2511 params->apcor.gain1 = 0x18;
2512 params->apcor.gain2 = 0x16;
2513 params->apcor.gain4 = 0x24;
2514 params->apcor.gain8 = 0x34;
2515 *command_flags |= COMMAND_SETAPCOR;
2517 params->vlOffset.gain1 = 20;
2518 params->vlOffset.gain2 = 24;
2519 params->vlOffset.gain4 = 26;
2520 params->vlOffset.gain8 = 26;
2521 *command_flags |= COMMAND_SETVLOFFSET;
2522 #undef FIRMWARE_VERSION
2523 #undef EXP_FROM_COMP
2527 #define FIRMWARE_VERSION(x,y) (cam->params.version.firmwareVersion == (x) && \
2528 cam->params.version.firmwareRevision == (y))
2529 /* monitor the exposure and adjust the sensor frame rate if needed */
2530 static void monitor_exposure(struct cam_data *cam)
2532 u8 exp_acc, bcomp, gain, coarseL, cmd[8], data[8];
2533 int retval, light_exp, dark_exp, very_dark_exp;
2534 int old_exposure, new_exposure, framerate;
2536 /* get necessary stats and register settings from camera */
2537 /* do_command can't handle this, so do it ourselves */
2538 cmd[0] = CPIA_COMMAND_ReadVPRegs>>8;
2539 cmd[1] = CPIA_COMMAND_ReadVPRegs&0xff;
2546 retval = cam->ops->transferCmd(cam->lowlevel_data, cmd, data);
2548 LOG("ReadVPRegs(30,4,9,8) - failed, retval=%d\n",
2557 mutex_lock(&cam->param_lock);
2558 light_exp = cam->params.colourParams.brightness +
2559 TC - 50 + EXP_ACC_LIGHT;
2562 dark_exp = cam->params.colourParams.brightness +
2563 TC - 50 - EXP_ACC_DARK;
2566 very_dark_exp = dark_exp/2;
2568 old_exposure = cam->params.exposure.coarseExpHi * 256 +
2569 cam->params.exposure.coarseExpLo;
2571 if(!cam->params.flickerControl.disabled) {
2572 /* Flicker control on */
2573 int max_comp = FIRMWARE_VERSION(1,2) ? MAX_COMP : HIGH_COMP_102;
2574 bcomp += 128; /* decode */
2575 if(bcomp >= max_comp && exp_acc < dark_exp) {
2577 if(exp_acc < very_dark_exp) {
2579 if(cam->exposure_status == EXPOSURE_VERY_DARK)
2580 ++cam->exposure_count;
2582 cam->exposure_status = EXPOSURE_VERY_DARK;
2583 cam->exposure_count = 1;
2587 if(cam->exposure_status == EXPOSURE_DARK)
2588 ++cam->exposure_count;
2590 cam->exposure_status = EXPOSURE_DARK;
2591 cam->exposure_count = 1;
2594 } else if(old_exposure <= LOW_EXP || exp_acc > light_exp) {
2596 if(old_exposure <= VERY_LOW_EXP) {
2598 if(cam->exposure_status == EXPOSURE_VERY_LIGHT)
2599 ++cam->exposure_count;
2601 cam->exposure_status = EXPOSURE_VERY_LIGHT;
2602 cam->exposure_count = 1;
2606 if(cam->exposure_status == EXPOSURE_LIGHT)
2607 ++cam->exposure_count;
2609 cam->exposure_status = EXPOSURE_LIGHT;
2610 cam->exposure_count = 1;
2614 /* not dark or light */
2615 cam->exposure_status = EXPOSURE_NORMAL;
2618 /* Flicker control off */
2619 if(old_exposure >= MAX_EXP && exp_acc < dark_exp) {
2621 if(exp_acc < very_dark_exp) {
2623 if(cam->exposure_status == EXPOSURE_VERY_DARK)
2624 ++cam->exposure_count;
2626 cam->exposure_status = EXPOSURE_VERY_DARK;
2627 cam->exposure_count = 1;
2631 if(cam->exposure_status == EXPOSURE_DARK)
2632 ++cam->exposure_count;
2634 cam->exposure_status = EXPOSURE_DARK;
2635 cam->exposure_count = 1;
2638 } else if(old_exposure <= LOW_EXP || exp_acc > light_exp) {
2640 if(old_exposure <= VERY_LOW_EXP) {
2642 if(cam->exposure_status == EXPOSURE_VERY_LIGHT)
2643 ++cam->exposure_count;
2645 cam->exposure_status = EXPOSURE_VERY_LIGHT;
2646 cam->exposure_count = 1;
2650 if(cam->exposure_status == EXPOSURE_LIGHT)
2651 ++cam->exposure_count;
2653 cam->exposure_status = EXPOSURE_LIGHT;
2654 cam->exposure_count = 1;
2658 /* not dark or light */
2659 cam->exposure_status = EXPOSURE_NORMAL;
2663 framerate = cam->fps;
2664 if(framerate > 30 || framerate < 1)
2667 if(!cam->params.flickerControl.disabled) {
2668 /* Flicker control on */
2669 if((cam->exposure_status == EXPOSURE_VERY_DARK ||
2670 cam->exposure_status == EXPOSURE_DARK) &&
2671 cam->exposure_count >= DARK_TIME*framerate &&
2672 cam->params.sensorFps.divisor < 3) {
2674 /* dark for too long */
2675 ++cam->params.sensorFps.divisor;
2676 cam->cmd_queue |= COMMAND_SETSENSORFPS;
2678 cam->params.flickerControl.coarseJump =
2679 flicker_jumps[cam->mainsFreq]
2680 [cam->params.sensorFps.baserate]
2681 [cam->params.sensorFps.divisor];
2682 cam->cmd_queue |= COMMAND_SETFLICKERCTRL;
2684 new_exposure = cam->params.flickerControl.coarseJump-1;
2685 while(new_exposure < old_exposure/2)
2686 new_exposure += cam->params.flickerControl.coarseJump;
2687 cam->params.exposure.coarseExpLo = new_exposure & 0xff;
2688 cam->params.exposure.coarseExpHi = new_exposure >> 8;
2689 cam->cmd_queue |= COMMAND_SETEXPOSURE;
2690 cam->exposure_status = EXPOSURE_NORMAL;
2691 LOG("Automatically decreasing sensor_fps\n");
2693 } else if((cam->exposure_status == EXPOSURE_VERY_LIGHT ||
2694 cam->exposure_status == EXPOSURE_LIGHT) &&
2695 cam->exposure_count >= LIGHT_TIME*framerate &&
2696 cam->params.sensorFps.divisor > 0) {
2698 /* light for too long */
2699 int max_exp = FIRMWARE_VERSION(1,2) ? MAX_EXP_102 : MAX_EXP ;
2701 --cam->params.sensorFps.divisor;
2702 cam->cmd_queue |= COMMAND_SETSENSORFPS;
2704 cam->params.flickerControl.coarseJump =
2705 flicker_jumps[cam->mainsFreq]
2706 [cam->params.sensorFps.baserate]
2707 [cam->params.sensorFps.divisor];
2708 cam->cmd_queue |= COMMAND_SETFLICKERCTRL;
2710 new_exposure = cam->params.flickerControl.coarseJump-1;
2711 while(new_exposure < 2*old_exposure &&
2713 cam->params.flickerControl.coarseJump < max_exp)
2714 new_exposure += cam->params.flickerControl.coarseJump;
2715 cam->params.exposure.coarseExpLo = new_exposure & 0xff;
2716 cam->params.exposure.coarseExpHi = new_exposure >> 8;
2717 cam->cmd_queue |= COMMAND_SETEXPOSURE;
2718 cam->exposure_status = EXPOSURE_NORMAL;
2719 LOG("Automatically increasing sensor_fps\n");
2722 /* Flicker control off */
2723 if((cam->exposure_status == EXPOSURE_VERY_DARK ||
2724 cam->exposure_status == EXPOSURE_DARK) &&
2725 cam->exposure_count >= DARK_TIME*framerate &&
2726 cam->params.sensorFps.divisor < 3) {
2728 /* dark for too long */
2729 ++cam->params.sensorFps.divisor;
2730 cam->cmd_queue |= COMMAND_SETSENSORFPS;
2732 if(cam->params.exposure.gain > 0) {
2733 --cam->params.exposure.gain;
2734 cam->cmd_queue |= COMMAND_SETEXPOSURE;
2736 cam->exposure_status = EXPOSURE_NORMAL;
2737 LOG("Automatically decreasing sensor_fps\n");
2739 } else if((cam->exposure_status == EXPOSURE_VERY_LIGHT ||
2740 cam->exposure_status == EXPOSURE_LIGHT) &&
2741 cam->exposure_count >= LIGHT_TIME*framerate &&
2742 cam->params.sensorFps.divisor > 0) {
2744 /* light for too long */
2745 --cam->params.sensorFps.divisor;
2746 cam->cmd_queue |= COMMAND_SETSENSORFPS;
2748 if(cam->params.exposure.gain <
2749 cam->params.exposure.gainMode-1) {
2750 ++cam->params.exposure.gain;
2751 cam->cmd_queue |= COMMAND_SETEXPOSURE;
2753 cam->exposure_status = EXPOSURE_NORMAL;
2754 LOG("Automatically increasing sensor_fps\n");
2757 mutex_unlock(&cam->param_lock);
2760 /*-----------------------------------------------------------------*/
2761 /* if flicker is switched off, this function switches it back on.It checks,
2762 however, that conditions are suitable before restarting it.
2763 This should only be called for firmware version 1.2.
2765 It also adjust the colour balance when an exposure step is detected - as
2766 long as flicker is running
2768 static void restart_flicker(struct cam_data *cam)
2770 int cam_exposure, old_exp;
2771 if(!FIRMWARE_VERSION(1,2))
2773 mutex_lock(&cam->param_lock);
2774 if(cam->params.flickerControl.flickerMode == 0 ||
2775 cam->raw_image[39] == 0) {
2776 mutex_unlock(&cam->param_lock);
2779 cam_exposure = cam->raw_image[39]*2;
2780 old_exp = cam->params.exposure.coarseExpLo +
2781 cam->params.exposure.coarseExpHi*256;
2783 see how far away camera exposure is from a valid
2784 flicker exposure value
2786 cam_exposure %= cam->params.flickerControl.coarseJump;
2787 if(!cam->params.flickerControl.disabled &&
2788 cam_exposure <= cam->params.flickerControl.coarseJump - 3) {
2789 /* Flicker control auto-disabled */
2790 cam->params.flickerControl.disabled = 1;
2793 if(cam->params.flickerControl.disabled &&
2794 cam->params.flickerControl.flickerMode &&
2795 old_exp > cam->params.flickerControl.coarseJump +
2796 ROUND_UP_EXP_FOR_FLICKER) {
2797 /* exposure is now high enough to switch
2798 flicker control back on */
2799 set_flicker(&cam->params, &cam->cmd_queue, 1);
2800 if((cam->cmd_queue & COMMAND_SETEXPOSURE) &&
2801 cam->params.exposure.expMode == 2)
2802 cam->exposure_status = EXPOSURE_NORMAL;
2805 mutex_unlock(&cam->param_lock);
2807 #undef FIRMWARE_VERSION
2809 static int clear_stall(struct cam_data *cam)
2811 /* FIXME: Does this actually work? */
2812 LOG("Clearing stall\n");
2814 cam->ops->streamRead(cam->lowlevel_data, cam->raw_image, 0);
2815 do_command(cam, CPIA_COMMAND_GetCameraStatus,0,0,0,0);
2816 return cam->params.status.streamState != STREAM_PAUSED;
2819 /* kernel thread function to read image from camera */
2820 static int fetch_frame(void *data)
2822 int image_size, retry;
2823 struct cam_data *cam = (struct cam_data *)data;
2824 unsigned long oldjif, rate, diff;
2826 /* Allow up to two bad images in a row to be read and
2827 * ignored before an error is reported */
2828 for (retry = 0; retry < 3; ++retry) {
2830 DBG("retry=%d\n", retry);
2835 /* load first frame always uncompressed */
2836 if (cam->first_frame &&
2837 cam->params.compression.mode != CPIA_COMPRESSION_NONE) {
2838 do_command(cam, CPIA_COMMAND_SetCompression,
2839 CPIA_COMPRESSION_NONE,
2840 NO_DECIMATION, 0, 0);
2841 /* Trial & error - Discarding a frame prevents the
2842 first frame from having an error in the data. */
2843 do_command(cam, CPIA_COMMAND_DiscardFrame, 0, 0, 0, 0);
2846 /* init camera upload */
2847 if (do_command(cam, CPIA_COMMAND_GrabFrame, 0,
2848 cam->params.streamStartLine, 0, 0))
2851 if (cam->ops->wait_for_stream_ready) {
2852 /* loop until image ready */
2854 do_command(cam, CPIA_COMMAND_GetCameraStatus,0,0,0,0);
2855 while (cam->params.status.streamState != STREAM_READY) {
2856 if(++count > READY_TIMEOUT)
2858 if(cam->params.status.streamState ==
2861 if(!clear_stall(cam))
2867 /* sleep for 10 ms, hopefully ;) */
2868 msleep_interruptible(10);
2869 if (signal_pending(current))
2872 do_command(cam, CPIA_COMMAND_GetCameraStatus,
2875 if(cam->params.status.streamState != STREAM_READY) {
2882 /* grab image from camera */
2884 image_size = cam->ops->streamRead(cam->lowlevel_data,
2886 if (image_size <= 0) {
2887 DBG("streamRead failed: %d\n", image_size);
2891 rate = image_size * HZ / 1024;
2892 diff = jiffies-oldjif;
2893 cam->transfer_rate = diff==0 ? rate : rate/diff;
2894 /* diff==0 ? unlikely but possible */
2896 /* Switch flicker control back on if it got turned off */
2897 restart_flicker(cam);
2899 /* If AEC is enabled, monitor the exposure and
2900 adjust the sensor frame rate if needed */
2901 if(cam->params.exposure.expMode == 2)
2902 monitor_exposure(cam);
2904 /* camera idle now so dispatch queued commands */
2905 dispatch_commands(cam);
2907 /* Update our knowledge of the camera state */
2908 do_command(cam, CPIA_COMMAND_GetColourBalance, 0, 0, 0, 0);
2909 do_command(cam, CPIA_COMMAND_GetExposure, 0, 0, 0, 0);
2910 do_command(cam, CPIA_COMMAND_ReadMCPorts, 0, 0, 0, 0);
2912 /* decompress and convert image to by copying it from
2913 * raw_image to decompressed_frame
2918 cam->image_size = parse_picture(cam, image_size);
2919 if (cam->image_size <= 0) {
2920 DBG("parse_picture failed %d\n", cam->image_size);
2921 if(cam->params.compression.mode !=
2922 CPIA_COMPRESSION_NONE) {
2923 /* Compression may not work right if we
2924 had a bad frame, get the next one
2926 cam->first_frame = 1;
2927 do_command(cam, CPIA_COMMAND_SetGrabMode,
2928 CPIA_GRAB_SINGLE, 0, 0, 0);
2929 /* FIXME: Trial & error - need up to 70ms for
2930 the grab mode change to complete ? */
2931 msleep_interruptible(70);
2932 if (signal_pending(current))
2940 /* FIXME: this only works for double buffering */
2941 if (cam->frame[cam->curframe].state == FRAME_READY) {
2942 memcpy(cam->frame[cam->curframe].data,
2943 cam->decompressed_frame.data,
2944 cam->decompressed_frame.count);
2945 cam->frame[cam->curframe].state = FRAME_DONE;
2947 cam->decompressed_frame.state = FRAME_DONE;
2949 if (cam->first_frame) {
2950 cam->first_frame = 0;
2951 do_command(cam, CPIA_COMMAND_SetCompression,
2952 cam->params.compression.mode,
2953 cam->params.compression.decimation, 0, 0);
2955 /* Switch from single-grab to continuous grab */
2956 do_command(cam, CPIA_COMMAND_SetGrabMode,
2957 CPIA_GRAB_CONTINUOUS, 0, 0, 0);
2964 static int capture_frame(struct cam_data *cam, struct video_mmap *vm)
2966 if (!cam->frame_buf) {
2967 /* we do lazy allocation */
2969 if ((err = allocate_frame_buf(cam)))
2973 cam->curframe = vm->frame;
2974 cam->frame[cam->curframe].state = FRAME_READY;
2975 return fetch_frame(cam);
2978 static int goto_high_power(struct cam_data *cam)
2980 if (do_command(cam, CPIA_COMMAND_GotoHiPower, 0, 0, 0, 0))
2982 msleep_interruptible(40); /* windows driver does it too */
2983 if(signal_pending(current))
2985 if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0))
2987 if (cam->params.status.systemState == HI_POWER_STATE) {
2988 DBG("camera now in HIGH power state\n");
2995 static int goto_low_power(struct cam_data *cam)
2997 if (do_command(cam, CPIA_COMMAND_GotoLoPower, 0, 0, 0, 0))
2999 if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0))
3001 if (cam->params.status.systemState == LO_POWER_STATE) {
3002 DBG("camera now in LOW power state\n");
3009 static void save_camera_state(struct cam_data *cam)
3011 if(!(cam->cmd_queue & COMMAND_SETCOLOURBALANCE))
3012 do_command(cam, CPIA_COMMAND_GetColourBalance, 0, 0, 0, 0);
3013 if(!(cam->cmd_queue & COMMAND_SETEXPOSURE))
3014 do_command(cam, CPIA_COMMAND_GetExposure, 0, 0, 0, 0);
3016 DBG("%d/%d/%d/%d/%d/%d/%d/%d\n",
3017 cam->params.exposure.gain,
3018 cam->params.exposure.fineExp,
3019 cam->params.exposure.coarseExpLo,
3020 cam->params.exposure.coarseExpHi,
3021 cam->params.exposure.redComp,
3022 cam->params.exposure.green1Comp,
3023 cam->params.exposure.green2Comp,
3024 cam->params.exposure.blueComp);
3026 cam->params.colourBalance.redGain,
3027 cam->params.colourBalance.greenGain,
3028 cam->params.colourBalance.blueGain);
3031 static int set_camera_state(struct cam_data *cam)
3033 cam->cmd_queue = COMMAND_SETCOMPRESSION |
3034 COMMAND_SETCOMPRESSIONTARGET |
3035 COMMAND_SETCOLOURPARAMS |
3037 COMMAND_SETYUVTHRESH |
3038 COMMAND_SETECPTIMING |
3039 COMMAND_SETCOMPRESSIONPARAMS |
3040 COMMAND_SETEXPOSURE |
3041 COMMAND_SETCOLOURBALANCE |
3042 COMMAND_SETSENSORFPS |
3044 COMMAND_SETFLICKERCTRL |
3045 COMMAND_SETVLOFFSET;
3047 do_command(cam, CPIA_COMMAND_SetGrabMode, CPIA_GRAB_SINGLE,0,0,0);
3048 dispatch_commands(cam);
3050 /* Wait 6 frames for the sensor to get all settings and
3051 AEC/ACB to settle */
3052 msleep_interruptible(6*(cam->params.sensorFps.baserate ? 33 : 40) *
3053 (1 << cam->params.sensorFps.divisor) + 10);
3055 if(signal_pending(current))
3058 save_camera_state(cam);
3063 static void get_version_information(struct cam_data *cam)
3065 /* GetCPIAVersion */
3066 do_command(cam, CPIA_COMMAND_GetCPIAVersion, 0, 0, 0, 0);
3069 do_command(cam, CPIA_COMMAND_GetPnPID, 0, 0, 0, 0);
3072 /* initialize camera */
3073 static int reset_camera(struct cam_data *cam)
3076 /* Start the camera in low power mode */
3077 if (goto_low_power(cam)) {
3078 if (cam->params.status.systemState != WARM_BOOT_STATE)
3081 /* FIXME: this is just dirty trial and error */
3082 err = goto_high_power(cam);
3085 do_command(cam, CPIA_COMMAND_DiscardFrame, 0, 0, 0, 0);
3086 if (goto_low_power(cam))
3090 /* procedure described in developer's guide p3-28 */
3092 /* Check the firmware version. */
3093 cam->params.version.firmwareVersion = 0;
3094 get_version_information(cam);
3095 if (cam->params.version.firmwareVersion != 1)
3098 /* A bug in firmware 1-02 limits gainMode to 2 */
3099 if(cam->params.version.firmwareRevision <= 2 &&
3100 cam->params.exposure.gainMode > 2) {
3101 cam->params.exposure.gainMode = 2;
3104 /* set QX3 detected flag */
3105 cam->params.qx3.qx3_detected = (cam->params.pnpID.vendor == 0x0813 &&
3106 cam->params.pnpID.product == 0x0001);
3108 /* The fatal error checking should be done after
3109 * the camera powers up (developer's guide p 3-38) */
3111 /* Set streamState before transition to high power to avoid bug
3112 * in firmware 1-02 */
3113 do_command(cam, CPIA_COMMAND_ModifyCameraStatus, STREAMSTATE, 0,
3114 STREAM_NOT_READY, 0);
3117 err = goto_high_power(cam);
3121 /* Check the camera status */
3122 if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0))
3125 if (cam->params.status.fatalError) {
3126 DBG("fatal_error: %#04x\n",
3127 cam->params.status.fatalError);
3128 DBG("vp_status: %#04x\n",
3129 cam->params.status.vpStatus);
3130 if (cam->params.status.fatalError & ~(COM_FLAG|CPIA_FLAG)) {
3131 /* Fatal error in camera */
3133 } else if (cam->params.status.fatalError & (COM_FLAG|CPIA_FLAG)) {
3134 /* Firmware 1-02 may do this for parallel port cameras,
3135 * just clear the flags (developer's guide p 3-38) */
3136 do_command(cam, CPIA_COMMAND_ModifyCameraStatus,
3137 FATALERROR, ~(COM_FLAG|CPIA_FLAG), 0, 0);
3141 /* Check the camera status again */
3142 if (cam->params.status.fatalError) {
3143 if (cam->params.status.fatalError)
3147 /* VPVersion can't be retrieved before the camera is in HiPower,
3148 * so get it here instead of in get_version_information. */
3149 do_command(cam, CPIA_COMMAND_GetVPVersion, 0, 0, 0, 0);
3151 /* set camera to a known state */
3152 return set_camera_state(cam);
3155 static void put_cam(struct cpia_camera_ops* ops)
3158 module_put(ops->owner);
3161 /* ------------------------- V4L interface --------------------- */
3162 static int cpia_open(struct inode *inode, struct file *file)
3164 struct video_device *dev = video_devdata(file);
3165 struct cam_data *cam = dev->priv;
3169 DBG("Internal error, cam_data not found!\n");
3173 if (cam->open_count > 0) {
3174 DBG("Camera already open\n");
3178 if (!try_module_get(cam->ops->owner))
3181 mutex_lock(&cam->busy_lock);
3183 if (!cam->raw_image) {
3184 cam->raw_image = rvmalloc(CPIA_MAX_IMAGE_SIZE);
3185 if (!cam->raw_image)
3189 if (!cam->decompressed_frame.data) {
3190 cam->decompressed_frame.data = rvmalloc(CPIA_MAX_FRAME_SIZE);
3191 if (!cam->decompressed_frame.data)
3197 if (cam->ops->open(cam->lowlevel_data))
3200 /* reset the camera */
3201 if ((err = reset_camera(cam)) != 0) {
3202 cam->ops->close(cam->lowlevel_data);
3207 if(signal_pending(current))
3210 /* Set ownership of /proc/cpia/videoX to current user */
3212 cam->proc_entry->uid = current->uid;
3214 /* set mark for loading first frame uncompressed */
3215 cam->first_frame = 1;
3217 /* init it to something */
3218 cam->mmap_kludge = 0;
3221 file->private_data = dev;
3222 mutex_unlock(&cam->busy_lock);
3226 if (cam->decompressed_frame.data) {
3227 rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE);
3228 cam->decompressed_frame.data = NULL;
3230 if (cam->raw_image) {
3231 rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
3232 cam->raw_image = NULL;
3234 mutex_unlock(&cam->busy_lock);
3239 static int cpia_close(struct inode *inode, struct file *file)
3241 struct video_device *dev = file->private_data;
3242 struct cam_data *cam = dev->priv;
3245 /* Return ownership of /proc/cpia/videoX to root */
3247 cam->proc_entry->uid = 0;
3249 /* save camera state for later open (developers guide ch 3.5.3) */
3250 save_camera_state(cam);
3253 goto_low_power(cam);
3255 /* Update the camera status */
3256 do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0);
3258 /* cleanup internal state stuff */
3259 free_frames(cam->frame);
3262 cam->ops->close(cam->lowlevel_data);
3267 if (--cam->open_count == 0) {
3268 /* clean up capture-buffers */
3269 if (cam->raw_image) {
3270 rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
3271 cam->raw_image = NULL;
3274 if (cam->decompressed_frame.data) {
3275 rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE);
3276 cam->decompressed_frame.data = NULL;
3280 free_frame_buf(cam);
3285 file->private_data = NULL;
3290 static ssize_t cpia_read(struct file *file, char __user *buf,
3291 size_t count, loff_t *ppos)
3293 struct video_device *dev = file->private_data;
3294 struct cam_data *cam = dev->priv;
3297 /* make this _really_ smp and multithread-safe */
3298 if (mutex_lock_interruptible(&cam->busy_lock))
3303 mutex_unlock(&cam->busy_lock);
3309 mutex_unlock(&cam->busy_lock);
3315 mutex_unlock(&cam->busy_lock);
3320 cam->decompressed_frame.state = FRAME_READY;
3322 if((err = fetch_frame(cam)) != 0) {
3323 DBG("ERROR from fetch_frame: %d\n", err);
3324 mutex_unlock(&cam->busy_lock);
3327 cam->decompressed_frame.state = FRAME_UNUSED;
3329 /* copy data to user space */
3330 if (cam->decompressed_frame.count > count) {
3331 DBG("count wrong: %d, %lu\n", cam->decompressed_frame.count,
3332 (unsigned long) count);
3333 mutex_unlock(&cam->busy_lock);
3336 if (copy_to_user(buf, cam->decompressed_frame.data,
3337 cam->decompressed_frame.count)) {
3338 DBG("copy_to_user failed\n");
3339 mutex_unlock(&cam->busy_lock);
3343 mutex_unlock(&cam->busy_lock);
3344 return cam->decompressed_frame.count;
3347 static int cpia_do_ioctl(struct inode *inode, struct file *file,
3348 unsigned int ioctlnr, void *arg)
3350 struct video_device *dev = file->private_data;
3351 struct cam_data *cam = dev->priv;
3354 if (!cam || !cam->ops)
3357 /* make this _really_ smp-safe */
3358 if (mutex_lock_interruptible(&cam->busy_lock))
3361 //DBG("cpia_ioctl: %u\n", ioctlnr);
3364 /* query capabilities */
3367 struct video_capability *b = arg;
3369 DBG("VIDIOCGCAP\n");
3370 strcpy(b->name, "CPiA Camera");
3371 b->type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE;
3374 b->maxwidth = 352; /* VIDEOSIZE_CIF */
3376 b->minwidth = 48; /* VIDEOSIZE_48_48 */
3381 /* get/set video source - we are a camera and nothing else */
3384 struct video_channel *v = arg;
3386 DBG("VIDIOCGCHAN\n");
3387 if (v->channel != 0) {
3393 strcpy(v->name, "Camera");
3396 v->type = VIDEO_TYPE_CAMERA;
3403 struct video_channel *v = arg;
3405 DBG("VIDIOCSCHAN\n");
3406 if (v->channel != 0)
3411 /* image properties */
3414 struct video_picture *pic = arg;
3415 DBG("VIDIOCGPICT\n");
3422 struct video_picture *vp = arg;
3424 DBG("VIDIOCSPICT\n");
3426 /* check validity */
3427 DBG("palette: %d\n", vp->palette);
3428 DBG("depth: %d\n", vp->depth);
3429 if (!valid_mode(vp->palette, vp->depth)) {
3434 mutex_lock(&cam->param_lock);
3435 /* brightness, colour, contrast need no check 0-65535 */
3437 /* update cam->params.colourParams */
3438 cam->params.colourParams.brightness = vp->brightness*100/65535;
3439 cam->params.colourParams.contrast = vp->contrast*100/65535;
3440 cam->params.colourParams.saturation = vp->colour*100/65535;
3441 /* contrast is in steps of 8, so round */
3442 cam->params.colourParams.contrast =
3443 ((cam->params.colourParams.contrast + 3) / 8) * 8;
3444 if (cam->params.version.firmwareVersion == 1 &&
3445 cam->params.version.firmwareRevision == 2 &&
3446 cam->params.colourParams.contrast > 80) {
3447 /* 1-02 firmware limits contrast to 80 */
3448 cam->params.colourParams.contrast = 80;
3451 /* Adjust flicker control if necessary */
3452 if(cam->params.flickerControl.allowableOverExposure < 0)
3453 cam->params.flickerControl.allowableOverExposure =
3454 -find_over_exposure(cam->params.colourParams.brightness);
3455 if(cam->params.flickerControl.flickerMode != 0)
3456 cam->cmd_queue |= COMMAND_SETFLICKERCTRL;
3459 /* queue command to update camera */
3460 cam->cmd_queue |= COMMAND_SETCOLOURPARAMS;
3461 mutex_unlock(&cam->param_lock);
3462 DBG("VIDIOCSPICT: %d / %d // %d / %d / %d / %d\n",
3463 vp->depth, vp->palette, vp->brightness, vp->hue, vp->colour,
3468 /* get/set capture window */
3471 struct video_window *vw = arg;
3472 DBG("VIDIOCGWIN\n");
3480 /* copy_from_user, check validity, copy to internal structure */
3481 struct video_window *vw = arg;
3482 DBG("VIDIOCSWIN\n");
3484 if (vw->clipcount != 0) { /* clipping not supported */
3488 if (vw->clips != NULL) { /* clipping not supported */
3493 /* we set the video window to something smaller or equal to what
3494 * is requested by the user???
3496 mutex_lock(&cam->param_lock);
3497 if (vw->width != cam->vw.width || vw->height != cam->vw.height) {
3498 int video_size = match_videosize(vw->width, vw->height);
3500 if (video_size < 0) {
3502 mutex_unlock(&cam->param_lock);
3505 cam->video_size = video_size;
3507 /* video size is changing, reset the subcapture area */
3508 memset(&cam->vc, 0, sizeof(cam->vc));
3511 DBG("%d / %d\n", cam->vw.width, cam->vw.height);
3512 cam->cmd_queue |= COMMAND_SETFORMAT;
3515 mutex_unlock(&cam->param_lock);
3517 /* setformat ignored by camera during streaming,
3518 * so stop/dispatch/start */
3519 if (cam->cmd_queue & COMMAND_SETFORMAT) {
3521 dispatch_commands(cam);
3523 DBG("%d/%d:%d\n", cam->video_size,
3524 cam->vw.width, cam->vw.height);
3528 /* mmap interface */
3531 struct video_mbuf *vm = arg;
3534 DBG("VIDIOCGMBUF\n");
3535 memset(vm, 0, sizeof(*vm));
3536 vm->size = CPIA_MAX_FRAME_SIZE*FRAME_NUM;
3537 vm->frames = FRAME_NUM;
3538 for (i = 0; i < FRAME_NUM; i++)
3539 vm->offsets[i] = CPIA_MAX_FRAME_SIZE * i;
3543 case VIDIOCMCAPTURE:
3545 struct video_mmap *vm = arg;
3548 DBG("VIDIOCMCAPTURE: %d / %d / %dx%d\n", vm->format, vm->frame,
3549 vm->width, vm->height);
3550 if (vm->frame<0||vm->frame>=FRAME_NUM) {
3555 /* set video format */
3556 cam->vp.palette = vm->format;
3557 switch(vm->format) {
3558 case VIDEO_PALETTE_GREY:
3561 case VIDEO_PALETTE_RGB555:
3562 case VIDEO_PALETTE_RGB565:
3563 case VIDEO_PALETTE_YUV422:
3564 case VIDEO_PALETTE_YUYV:
3565 case VIDEO_PALETTE_UYVY:
3568 case VIDEO_PALETTE_RGB24:
3571 case VIDEO_PALETTE_RGB32:
3581 /* set video size */
3582 video_size = match_videosize(vm->width, vm->height);
3583 if (video_size < 0) {
3587 if (video_size != cam->video_size) {
3588 cam->video_size = video_size;
3590 /* video size is changing, reset the subcapture area */
3591 memset(&cam->vc, 0, sizeof(cam->vc));
3594 cam->cmd_queue |= COMMAND_SETFORMAT;
3595 dispatch_commands(cam);
3597 /* according to v4l-spec we must start streaming here */
3598 cam->mmap_kludge = 1;
3599 retval = capture_frame(cam, vm);
3608 //DBG("VIDIOCSYNC: %d\n", *frame);
3610 if (*frame<0 || *frame >= FRAME_NUM) {
3615 switch (cam->frame[*frame].state) {
3618 case FRAME_GRABBING:
3619 DBG("sync to unused frame %d\n", *frame);
3624 cam->frame[*frame].state = FRAME_UNUSED;
3625 //DBG("VIDIOCSYNC: %d synced\n", *frame);
3628 if (retval == -EINTR) {
3629 /* FIXME - xawtv does not handle this nice */
3635 case VIDIOCGCAPTURE:
3637 struct video_capture *vc = arg;
3639 DBG("VIDIOCGCAPTURE\n");
3646 case VIDIOCSCAPTURE:
3648 struct video_capture *vc = arg;
3650 DBG("VIDIOCSCAPTURE\n");
3652 if (vc->decimation != 0) { /* How should this be used? */
3656 if (vc->flags != 0) { /* Even/odd grab not supported */
3661 /* Clip to the resolution we can set for the ROI
3662 (every 8 columns and 4 rows) */
3663 vc->x = vc->x & ~(__u32)7;
3664 vc->y = vc->y & ~(__u32)3;
3665 vc->width = vc->width & ~(__u32)7;
3666 vc->height = vc->height & ~(__u32)3;
3668 if(vc->width == 0 || vc->height == 0 ||
3669 vc->x + vc->width > cam->vw.width ||
3670 vc->y + vc->height > cam->vw.height) {
3675 DBG("%d,%d/%dx%d\n", vc->x,vc->y,vc->width, vc->height);
3677 mutex_lock(&cam->param_lock);
3681 cam->vc.width = vc->width;
3682 cam->vc.height = vc->height;
3685 cam->cmd_queue |= COMMAND_SETFORMAT;
3687 mutex_unlock(&cam->param_lock);
3689 /* setformat ignored by camera during streaming,
3690 * so stop/dispatch/start */
3691 dispatch_commands(cam);
3697 struct video_unit *vu = arg;
3699 DBG("VIDIOCGUNIT\n");
3701 vu->video = cam->vdev.minor;
3702 vu->vbi = VIDEO_NO_UNIT;
3703 vu->radio = VIDEO_NO_UNIT;
3704 vu->audio = VIDEO_NO_UNIT;
3705 vu->teletext = VIDEO_NO_UNIT;
3711 /* pointless to implement overlay with this camera */
3716 /* tuner interface - we have none */
3721 /* audio interface - we have none */
3727 retval = -ENOIOCTLCMD;
3731 mutex_unlock(&cam->busy_lock);
3735 static int cpia_ioctl(struct inode *inode, struct file *file,
3736 unsigned int cmd, unsigned long arg)
3738 return video_usercopy(inode, file, cmd, arg, cpia_do_ioctl);
3743 static int cpia_mmap(struct file *file, struct vm_area_struct *vma)
3745 struct video_device *dev = file->private_data;
3746 unsigned long start = vma->vm_start;
3747 unsigned long size = vma->vm_end - vma->vm_start;
3748 unsigned long page, pos;
3749 struct cam_data *cam = dev->priv;
3752 if (!cam || !cam->ops)
3755 DBG("cpia_mmap: %ld\n", size);
3757 if (size > FRAME_NUM*CPIA_MAX_FRAME_SIZE)
3760 if (!cam || !cam->ops)
3763 /* make this _really_ smp-safe */
3764 if (mutex_lock_interruptible(&cam->busy_lock))
3767 if (!cam->frame_buf) { /* we do lazy allocation */
3768 if ((retval = allocate_frame_buf(cam))) {
3769 mutex_unlock(&cam->busy_lock);
3774 pos = (unsigned long)(cam->frame_buf);
3776 page = vmalloc_to_pfn((void *)pos);
3777 if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
3778 mutex_unlock(&cam->busy_lock);
3783 if (size > PAGE_SIZE)
3789 DBG("cpia_mmap: %ld\n", size);
3790 mutex_unlock(&cam->busy_lock);
3795 static struct file_operations cpia_fops = {
3796 .owner = THIS_MODULE,
3798 .release = cpia_close,
3801 .ioctl = cpia_ioctl,
3802 .compat_ioctl = v4l_compat_ioctl32,
3803 .llseek = no_llseek,
3806 static struct video_device cpia_template = {
3807 .owner = THIS_MODULE,
3808 .name = "CPiA Camera",
3809 .type = VID_TYPE_CAPTURE,
3810 .hardware = VID_HARDWARE_CPIA,
3814 /* initialise cam_data structure */
3815 static void reset_camera_struct(struct cam_data *cam)
3817 /* The following parameter values are the defaults from
3818 * "Software Developer's Guide for CPiA Cameras". Any changes
3819 * to the defaults are noted in comments. */
3820 cam->params.colourParams.brightness = 50;
3821 cam->params.colourParams.contrast = 48;
3822 cam->params.colourParams.saturation = 50;
3823 cam->params.exposure.gainMode = 4;
3824 cam->params.exposure.expMode = 2; /* AEC */
3825 cam->params.exposure.compMode = 1;
3826 cam->params.exposure.centreWeight = 1;
3827 cam->params.exposure.gain = 0;
3828 cam->params.exposure.fineExp = 0;
3829 cam->params.exposure.coarseExpLo = 185;
3830 cam->params.exposure.coarseExpHi = 0;
3831 cam->params.exposure.redComp = COMP_RED;
3832 cam->params.exposure.green1Comp = COMP_GREEN1;
3833 cam->params.exposure.green2Comp = COMP_GREEN2;
3834 cam->params.exposure.blueComp = COMP_BLUE;
3835 cam->params.colourBalance.balanceMode = 2; /* ACB */
3836 cam->params.colourBalance.redGain = 32;
3837 cam->params.colourBalance.greenGain = 6;
3838 cam->params.colourBalance.blueGain = 92;
3839 cam->params.apcor.gain1 = 0x18;
3840 cam->params.apcor.gain2 = 0x16;
3841 cam->params.apcor.gain4 = 0x24;
3842 cam->params.apcor.gain8 = 0x34;
3843 cam->params.flickerControl.flickerMode = 0;
3844 cam->params.flickerControl.disabled = 1;
3846 cam->params.flickerControl.coarseJump =
3847 flicker_jumps[cam->mainsFreq]
3848 [cam->params.sensorFps.baserate]
3849 [cam->params.sensorFps.divisor];
3850 cam->params.flickerControl.allowableOverExposure =
3851 -find_over_exposure(cam->params.colourParams.brightness);
3852 cam->params.vlOffset.gain1 = 20;
3853 cam->params.vlOffset.gain2 = 24;
3854 cam->params.vlOffset.gain4 = 26;
3855 cam->params.vlOffset.gain8 = 26;
3856 cam->params.compressionParams.hysteresis = 3;
3857 cam->params.compressionParams.threshMax = 11;
3858 cam->params.compressionParams.smallStep = 1;
3859 cam->params.compressionParams.largeStep = 3;
3860 cam->params.compressionParams.decimationHysteresis = 2;
3861 cam->params.compressionParams.frDiffStepThresh = 5;
3862 cam->params.compressionParams.qDiffStepThresh = 3;
3863 cam->params.compressionParams.decimationThreshMod = 2;
3864 /* End of default values from Software Developer's Guide */
3866 cam->transfer_rate = 0;
3867 cam->exposure_status = EXPOSURE_NORMAL;
3869 /* Set Sensor FPS to 15fps. This seems better than 30fps
3870 * for indoor lighting. */
3871 cam->params.sensorFps.divisor = 1;
3872 cam->params.sensorFps.baserate = 1;
3874 cam->params.yuvThreshold.yThreshold = 6; /* From windows driver */
3875 cam->params.yuvThreshold.uvThreshold = 6; /* From windows driver */
3877 cam->params.format.subSample = SUBSAMPLE_422;
3878 cam->params.format.yuvOrder = YUVORDER_YUYV;
3880 cam->params.compression.mode = CPIA_COMPRESSION_AUTO;
3881 cam->params.compressionTarget.frTargeting =
3882 CPIA_COMPRESSION_TARGET_QUALITY;
3883 cam->params.compressionTarget.targetFR = 15; /* From windows driver */
3884 cam->params.compressionTarget.targetQ = 5; /* From windows driver */
3886 cam->params.qx3.qx3_detected = 0;
3887 cam->params.qx3.toplight = 0;
3888 cam->params.qx3.bottomlight = 0;
3889 cam->params.qx3.button = 0;
3890 cam->params.qx3.cradled = 0;
3892 cam->video_size = VIDEOSIZE_CIF;
3894 cam->vp.colour = 32768; /* 50% */
3895 cam->vp.hue = 32768; /* 50% */
3896 cam->vp.brightness = 32768; /* 50% */
3897 cam->vp.contrast = 32768; /* 50% */
3898 cam->vp.whiteness = 0; /* not used -> grayscale only */
3899 cam->vp.depth = 24; /* to be set by user */
3900 cam->vp.palette = VIDEO_PALETTE_RGB24; /* to be set by user */
3910 cam->vw.chromakey = 0;
3912 cam->vw.clipcount = 0;
3913 cam->vw.clips = NULL;
3915 cam->cmd_queue = COMMAND_NONE;
3916 cam->first_frame = 1;
3921 /* initialize cam_data structure */
3922 static void init_camera_struct(struct cam_data *cam,
3923 struct cpia_camera_ops *ops )
3927 /* Default everything to 0 */
3928 memset(cam, 0, sizeof(struct cam_data));
3931 mutex_init(&cam->param_lock);
3932 mutex_init(&cam->busy_lock);
3934 reset_camera_struct(cam);
3936 cam->proc_entry = NULL;
3938 memcpy(&cam->vdev, &cpia_template, sizeof(cpia_template));
3939 cam->vdev.priv = cam;
3942 for (i = 0; i < FRAME_NUM; i++) {
3943 cam->frame[i].width = 0;
3944 cam->frame[i].height = 0;
3945 cam->frame[i].state = FRAME_UNUSED;
3946 cam->frame[i].data = NULL;
3948 cam->decompressed_frame.width = 0;
3949 cam->decompressed_frame.height = 0;
3950 cam->decompressed_frame.state = FRAME_UNUSED;
3951 cam->decompressed_frame.data = NULL;
3954 struct cam_data *cpia_register_camera(struct cpia_camera_ops *ops, void *lowlevel)
3956 struct cam_data *camera;
3958 if ((camera = kmalloc(sizeof(struct cam_data), GFP_KERNEL)) == NULL)
3962 init_camera_struct( camera, ops );
3963 camera->lowlevel_data = lowlevel;
3965 /* register v4l device */
3966 if (video_register_device(&camera->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
3968 printk(KERN_DEBUG "video_register_device failed\n");
3972 /* get version information from camera: open/reset/close */
3975 if (camera->ops->open(camera->lowlevel_data))
3978 /* reset the camera */
3979 if (reset_camera(camera) != 0) {
3980 camera->ops->close(camera->lowlevel_data);
3985 camera->ops->close(camera->lowlevel_data);
3987 #ifdef CONFIG_PROC_FS
3988 create_proc_cpia_cam(camera);
3991 printk(KERN_INFO " CPiA Version: %d.%02d (%d.%d)\n",
3992 camera->params.version.firmwareVersion,
3993 camera->params.version.firmwareRevision,
3994 camera->params.version.vcVersion,
3995 camera->params.version.vcRevision);
3996 printk(KERN_INFO " CPiA PnP-ID: %04x:%04x:%04x\n",
3997 camera->params.pnpID.vendor,
3998 camera->params.pnpID.product,
3999 camera->params.pnpID.deviceRevision);
4000 printk(KERN_INFO " VP-Version: %d.%d %04x\n",
4001 camera->params.vpVersion.vpVersion,
4002 camera->params.vpVersion.vpRevision,
4003 camera->params.vpVersion.cameraHeadID);
4008 void cpia_unregister_camera(struct cam_data *cam)
4010 DBG("unregistering video\n");
4011 video_unregister_device(&cam->vdev);
4012 if (cam->open_count) {
4014 DBG("camera open -- setting ops to NULL\n");
4018 #ifdef CONFIG_PROC_FS
4019 DBG("destroying /proc/cpia/video%d\n", cam->vdev.minor);
4020 destroy_proc_cpia_cam(cam);
4022 if (!cam->open_count) {
4023 DBG("freeing camera\n");
4028 static int __init cpia_init(void)
4030 printk(KERN_INFO "%s v%d.%d.%d\n", ABOUT,
4031 CPIA_MAJ_VER, CPIA_MIN_VER, CPIA_PATCH_VER);
4033 printk(KERN_WARNING "Since in-kernel colorspace conversion is not "
4034 "allowed, it is disabled by default now. Users should fix the "
4035 "applications in case they don't work without conversion "
4036 "reenabled by setting the 'colorspace_conv' module "
4037 "parameter to 1\n");
4039 #ifdef CONFIG_PROC_FS
4046 static void __exit cpia_exit(void)
4048 #ifdef CONFIG_PROC_FS
4049 proc_cpia_destroy();
4053 module_init(cpia_init);
4054 module_exit(cpia_exit);
4056 /* Exported symbols for modules. */
4058 EXPORT_SYMBOL(cpia_register_camera);
4059 EXPORT_SYMBOL(cpia_unregister_camera);