4 * Supports CPiA based Video Camera's.
6 * (C) Copyright 1999-2000 Peter Pregler
7 * (C) Copyright 1999-2000 Scott J. Bertin
8 * (C) Copyright 1999-2000 Johannes Erdfelt <johannes@erdfelt.com>
9 * (C) Copyright 2000 STMicroelectronics
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 /* define _CPIA_DEBUG_ for verbose debug output (see cpia.h) */
27 /* #define _CPIA_DEBUG_ 1 */
30 #include <linux/module.h>
31 #include <linux/init.h>
33 #include <linux/vmalloc.h>
34 #include <linux/slab.h>
35 #include <linux/proc_fs.h>
36 #include <linux/ctype.h>
37 #include <linux/pagemap.h>
38 #include <linux/delay.h>
40 #include <linux/mutex.h>
43 #include <linux/kmod.h>
48 static int video_nr = -1;
51 module_param(video_nr, int, 0);
52 MODULE_AUTHOR("Scott J. Bertin <sbertin@securenym.net> & Peter Pregler <Peter_Pregler@email.com> & Johannes Erdfelt <johannes@erdfelt.com>");
53 MODULE_DESCRIPTION("V4L-driver for Vision CPiA based cameras");
54 MODULE_LICENSE("GPL");
55 MODULE_SUPPORTED_DEVICE("video");
58 static unsigned short colorspace_conv;
59 module_param(colorspace_conv, ushort, 0444);
60 MODULE_PARM_DESC(colorspace_conv,
61 " Colorspace conversion:"
62 "\n 0 = disable, 1 = enable"
63 "\n Default value is 0"
66 #define ABOUT "V4L-Driver for Vision CPiA based cameras"
68 #ifndef VID_HARDWARE_CPIA
69 #define VID_HARDWARE_CPIA 24 /* FIXME -> from linux/videodev.h */
72 #define CPIA_MODULE_CPIA (0<<5)
73 #define CPIA_MODULE_SYSTEM (1<<5)
74 #define CPIA_MODULE_VP_CTRL (5<<5)
75 #define CPIA_MODULE_CAPTURE (6<<5)
76 #define CPIA_MODULE_DEBUG (7<<5)
78 #define INPUT (DATA_IN << 8)
79 #define OUTPUT (DATA_OUT << 8)
81 #define CPIA_COMMAND_GetCPIAVersion (INPUT | CPIA_MODULE_CPIA | 1)
82 #define CPIA_COMMAND_GetPnPID (INPUT | CPIA_MODULE_CPIA | 2)
83 #define CPIA_COMMAND_GetCameraStatus (INPUT | CPIA_MODULE_CPIA | 3)
84 #define CPIA_COMMAND_GotoHiPower (OUTPUT | CPIA_MODULE_CPIA | 4)
85 #define CPIA_COMMAND_GotoLoPower (OUTPUT | CPIA_MODULE_CPIA | 5)
86 #define CPIA_COMMAND_GotoSuspend (OUTPUT | CPIA_MODULE_CPIA | 7)
87 #define CPIA_COMMAND_GotoPassThrough (OUTPUT | CPIA_MODULE_CPIA | 8)
88 #define CPIA_COMMAND_ModifyCameraStatus (OUTPUT | CPIA_MODULE_CPIA | 10)
90 #define CPIA_COMMAND_ReadVCRegs (INPUT | CPIA_MODULE_SYSTEM | 1)
91 #define CPIA_COMMAND_WriteVCReg (OUTPUT | CPIA_MODULE_SYSTEM | 2)
92 #define CPIA_COMMAND_ReadMCPorts (INPUT | CPIA_MODULE_SYSTEM | 3)
93 #define CPIA_COMMAND_WriteMCPort (OUTPUT | CPIA_MODULE_SYSTEM | 4)
94 #define CPIA_COMMAND_SetBaudRate (OUTPUT | CPIA_MODULE_SYSTEM | 5)
95 #define CPIA_COMMAND_SetECPTiming (OUTPUT | CPIA_MODULE_SYSTEM | 6)
96 #define CPIA_COMMAND_ReadIDATA (INPUT | CPIA_MODULE_SYSTEM | 7)
97 #define CPIA_COMMAND_WriteIDATA (OUTPUT | CPIA_MODULE_SYSTEM | 8)
98 #define CPIA_COMMAND_GenericCall (OUTPUT | CPIA_MODULE_SYSTEM | 9)
99 #define CPIA_COMMAND_I2CStart (OUTPUT | CPIA_MODULE_SYSTEM | 10)
100 #define CPIA_COMMAND_I2CStop (OUTPUT | CPIA_MODULE_SYSTEM | 11)
101 #define CPIA_COMMAND_I2CWrite (OUTPUT | CPIA_MODULE_SYSTEM | 12)
102 #define CPIA_COMMAND_I2CRead (INPUT | CPIA_MODULE_SYSTEM | 13)
104 #define CPIA_COMMAND_GetVPVersion (INPUT | CPIA_MODULE_VP_CTRL | 1)
105 #define CPIA_COMMAND_ResetFrameCounter (INPUT | CPIA_MODULE_VP_CTRL | 2)
106 #define CPIA_COMMAND_SetColourParams (OUTPUT | CPIA_MODULE_VP_CTRL | 3)
107 #define CPIA_COMMAND_SetExposure (OUTPUT | CPIA_MODULE_VP_CTRL | 4)
108 #define CPIA_COMMAND_SetColourBalance (OUTPUT | CPIA_MODULE_VP_CTRL | 6)
109 #define CPIA_COMMAND_SetSensorFPS (OUTPUT | CPIA_MODULE_VP_CTRL | 7)
110 #define CPIA_COMMAND_SetVPDefaults (OUTPUT | CPIA_MODULE_VP_CTRL | 8)
111 #define CPIA_COMMAND_SetApcor (OUTPUT | CPIA_MODULE_VP_CTRL | 9)
112 #define CPIA_COMMAND_SetFlickerCtrl (OUTPUT | CPIA_MODULE_VP_CTRL | 10)
113 #define CPIA_COMMAND_SetVLOffset (OUTPUT | CPIA_MODULE_VP_CTRL | 11)
114 #define CPIA_COMMAND_GetColourParams (INPUT | CPIA_MODULE_VP_CTRL | 16)
115 #define CPIA_COMMAND_GetColourBalance (INPUT | CPIA_MODULE_VP_CTRL | 17)
116 #define CPIA_COMMAND_GetExposure (INPUT | CPIA_MODULE_VP_CTRL | 18)
117 #define CPIA_COMMAND_SetSensorMatrix (OUTPUT | CPIA_MODULE_VP_CTRL | 19)
118 #define CPIA_COMMAND_ColourBars (OUTPUT | CPIA_MODULE_VP_CTRL | 25)
119 #define CPIA_COMMAND_ReadVPRegs (INPUT | CPIA_MODULE_VP_CTRL | 30)
120 #define CPIA_COMMAND_WriteVPReg (OUTPUT | CPIA_MODULE_VP_CTRL | 31)
122 #define CPIA_COMMAND_GrabFrame (OUTPUT | CPIA_MODULE_CAPTURE | 1)
123 #define CPIA_COMMAND_UploadFrame (OUTPUT | CPIA_MODULE_CAPTURE | 2)
124 #define CPIA_COMMAND_SetGrabMode (OUTPUT | CPIA_MODULE_CAPTURE | 3)
125 #define CPIA_COMMAND_InitStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 4)
126 #define CPIA_COMMAND_FiniStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 5)
127 #define CPIA_COMMAND_StartStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 6)
128 #define CPIA_COMMAND_EndStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 7)
129 #define CPIA_COMMAND_SetFormat (OUTPUT | CPIA_MODULE_CAPTURE | 8)
130 #define CPIA_COMMAND_SetROI (OUTPUT | CPIA_MODULE_CAPTURE | 9)
131 #define CPIA_COMMAND_SetCompression (OUTPUT | CPIA_MODULE_CAPTURE | 10)
132 #define CPIA_COMMAND_SetCompressionTarget (OUTPUT | CPIA_MODULE_CAPTURE | 11)
133 #define CPIA_COMMAND_SetYUVThresh (OUTPUT | CPIA_MODULE_CAPTURE | 12)
134 #define CPIA_COMMAND_SetCompressionParams (OUTPUT | CPIA_MODULE_CAPTURE | 13)
135 #define CPIA_COMMAND_DiscardFrame (OUTPUT | CPIA_MODULE_CAPTURE | 14)
136 #define CPIA_COMMAND_GrabReset (OUTPUT | CPIA_MODULE_CAPTURE | 15)
138 #define CPIA_COMMAND_OutputRS232 (OUTPUT | CPIA_MODULE_DEBUG | 1)
139 #define CPIA_COMMAND_AbortProcess (OUTPUT | CPIA_MODULE_DEBUG | 4)
140 #define CPIA_COMMAND_SetDramPage (OUTPUT | CPIA_MODULE_DEBUG | 5)
141 #define CPIA_COMMAND_StartDramUpload (OUTPUT | CPIA_MODULE_DEBUG | 6)
142 #define CPIA_COMMAND_StartDummyDtream (OUTPUT | CPIA_MODULE_DEBUG | 8)
143 #define CPIA_COMMAND_AbortStream (OUTPUT | CPIA_MODULE_DEBUG | 9)
144 #define CPIA_COMMAND_DownloadDRAM (OUTPUT | CPIA_MODULE_DEBUG | 10)
145 #define CPIA_COMMAND_Null (OUTPUT | CPIA_MODULE_DEBUG | 11)
148 FRAME_READY, /* Ready to grab into */
149 FRAME_GRABBING, /* In the process of being grabbed into */
150 FRAME_DONE, /* Finished grabbing, but not been synced yet */
151 FRAME_UNUSED, /* Unused (no MCAPTURE) */
154 #define COMMAND_NONE 0x0000
155 #define COMMAND_SETCOMPRESSION 0x0001
156 #define COMMAND_SETCOMPRESSIONTARGET 0x0002
157 #define COMMAND_SETCOLOURPARAMS 0x0004
158 #define COMMAND_SETFORMAT 0x0008
159 #define COMMAND_PAUSE 0x0010
160 #define COMMAND_RESUME 0x0020
161 #define COMMAND_SETYUVTHRESH 0x0040
162 #define COMMAND_SETECPTIMING 0x0080
163 #define COMMAND_SETCOMPRESSIONPARAMS 0x0100
164 #define COMMAND_SETEXPOSURE 0x0200
165 #define COMMAND_SETCOLOURBALANCE 0x0400
166 #define COMMAND_SETSENSORFPS 0x0800
167 #define COMMAND_SETAPCOR 0x1000
168 #define COMMAND_SETFLICKERCTRL 0x2000
169 #define COMMAND_SETVLOFFSET 0x4000
170 #define COMMAND_SETLIGHTS 0x8000
172 #define ROUND_UP_EXP_FOR_FLICKER 15
174 /* Constants for automatic frame rate adjustment */
176 #define MAX_EXP_102 255
178 #define VERY_LOW_EXP 70
180 #define EXP_ACC_DARK 50
181 #define EXP_ACC_LIGHT 90
182 #define HIGH_COMP_102 160
187 /* Maximum number of 10ms loops to wait for the stream to become ready */
188 #define READY_TIMEOUT 100
190 /* Developer's Guide Table 5 p 3-34
191 * indexed by [mains][sensorFps.baserate][sensorFps.divisor]*/
192 static u8 flicker_jumps[2][2][4] =
193 { { { 76, 38, 19, 9 }, { 92, 46, 23, 11 } },
194 { { 64, 32, 16, 8 }, { 76, 38, 19, 9} }
197 /* forward declaration of local function */
198 static void reset_camera_struct(struct cam_data *cam);
199 static int find_over_exposure(int brightness);
200 static void set_flicker(struct cam_params *params, volatile u32 *command_flags,
204 /**********************************************************************
208 **********************************************************************/
209 static void *rvmalloc(unsigned long size)
214 size = PAGE_ALIGN(size);
215 mem = vmalloc_32(size);
219 memset(mem, 0, size); /* Clear the ram out, no junk to the user */
220 adr = (unsigned long) mem;
222 SetPageReserved(vmalloc_to_page((void *)adr));
230 static void rvfree(void *mem, unsigned long size)
237 adr = (unsigned long) mem;
238 while ((long) size > 0) {
239 ClearPageReserved(vmalloc_to_page((void *)adr));
246 /**********************************************************************
250 **********************************************************************/
251 #ifdef CONFIG_PROC_FS
252 static struct proc_dir_entry *cpia_proc_root=NULL;
254 static int cpia_read_proc(char *page, char **start, off_t off,
255 int count, int *eof, void *data)
259 struct cam_data *cam = data;
262 /* IMPORTANT: This output MUST be kept under PAGE_SIZE
263 * or we need to get more sophisticated. */
265 out += sprintf(out, "read-only\n-----------------------\n");
266 out += sprintf(out, "V4L Driver version: %d.%d.%d\n",
267 CPIA_MAJ_VER, CPIA_MIN_VER, CPIA_PATCH_VER);
268 out += sprintf(out, "CPIA Version: %d.%02d (%d.%d)\n",
269 cam->params.version.firmwareVersion,
270 cam->params.version.firmwareRevision,
271 cam->params.version.vcVersion,
272 cam->params.version.vcRevision);
273 out += sprintf(out, "CPIA PnP-ID: %04x:%04x:%04x\n",
274 cam->params.pnpID.vendor, cam->params.pnpID.product,
275 cam->params.pnpID.deviceRevision);
276 out += sprintf(out, "VP-Version: %d.%d %04x\n",
277 cam->params.vpVersion.vpVersion,
278 cam->params.vpVersion.vpRevision,
279 cam->params.vpVersion.cameraHeadID);
281 out += sprintf(out, "system_state: %#04x\n",
282 cam->params.status.systemState);
283 out += sprintf(out, "grab_state: %#04x\n",
284 cam->params.status.grabState);
285 out += sprintf(out, "stream_state: %#04x\n",
286 cam->params.status.streamState);
287 out += sprintf(out, "fatal_error: %#04x\n",
288 cam->params.status.fatalError);
289 out += sprintf(out, "cmd_error: %#04x\n",
290 cam->params.status.cmdError);
291 out += sprintf(out, "debug_flags: %#04x\n",
292 cam->params.status.debugFlags);
293 out += sprintf(out, "vp_status: %#04x\n",
294 cam->params.status.vpStatus);
295 out += sprintf(out, "error_code: %#04x\n",
296 cam->params.status.errorCode);
297 /* QX3 specific entries */
298 if (cam->params.qx3.qx3_detected) {
299 out += sprintf(out, "button: %4d\n",
300 cam->params.qx3.button);
301 out += sprintf(out, "cradled: %4d\n",
302 cam->params.qx3.cradled);
304 out += sprintf(out, "video_size: %s\n",
305 cam->params.format.videoSize == VIDEOSIZE_CIF ?
307 out += sprintf(out, "roi: (%3d, %3d) to (%3d, %3d)\n",
308 cam->params.roi.colStart*8,
309 cam->params.roi.rowStart*4,
310 cam->params.roi.colEnd*8,
311 cam->params.roi.rowEnd*4);
312 out += sprintf(out, "actual_fps: %3d\n", cam->fps);
313 out += sprintf(out, "transfer_rate: %4dkB/s\n",
316 out += sprintf(out, "\nread-write\n");
317 out += sprintf(out, "----------------------- current min"
318 " max default comment\n");
319 out += sprintf(out, "brightness: %8d %8d %8d %8d\n",
320 cam->params.colourParams.brightness, 0, 100, 50);
321 if (cam->params.version.firmwareVersion == 1 &&
322 cam->params.version.firmwareRevision == 2)
323 /* 1-02 firmware limits contrast to 80 */
328 out += sprintf(out, "contrast: %8d %8d %8d %8d"
330 cam->params.colourParams.contrast, 0, tmp, 48);
331 out += sprintf(out, "saturation: %8d %8d %8d %8d\n",
332 cam->params.colourParams.saturation, 0, 100, 50);
333 tmp = (25000+5000*cam->params.sensorFps.baserate)/
334 (1<<cam->params.sensorFps.divisor);
335 out += sprintf(out, "sensor_fps: %4d.%03d %8d %8d %8d\n",
336 tmp/1000, tmp%1000, 3, 30, 15);
337 out += sprintf(out, "stream_start_line: %8d %8d %8d %8d\n",
338 2*cam->params.streamStartLine, 0,
339 cam->params.format.videoSize == VIDEOSIZE_CIF ? 288:144,
340 cam->params.format.videoSize == VIDEOSIZE_CIF ? 240:120);
341 out += sprintf(out, "sub_sample: %8s %8s %8s %8s\n",
342 cam->params.format.subSample == SUBSAMPLE_420 ?
343 "420" : "422", "420", "422", "422");
344 out += sprintf(out, "yuv_order: %8s %8s %8s %8s\n",
345 cam->params.format.yuvOrder == YUVORDER_YUYV ?
346 "YUYV" : "UYVY", "YUYV" , "UYVY", "YUYV");
347 out += sprintf(out, "ecp_timing: %8s %8s %8s %8s\n",
348 cam->params.ecpTiming ? "slow" : "normal", "slow",
351 if (cam->params.colourBalance.balanceMode == 2) {
352 sprintf(tmpstr, "auto");
354 sprintf(tmpstr, "manual");
356 out += sprintf(out, "color_balance_mode: %8s %8s %8s"
357 " %8s\n", tmpstr, "manual", "auto", "auto");
358 out += sprintf(out, "red_gain: %8d %8d %8d %8d\n",
359 cam->params.colourBalance.redGain, 0, 212, 32);
360 out += sprintf(out, "green_gain: %8d %8d %8d %8d\n",
361 cam->params.colourBalance.greenGain, 0, 212, 6);
362 out += sprintf(out, "blue_gain: %8d %8d %8d %8d\n",
363 cam->params.colourBalance.blueGain, 0, 212, 92);
365 if (cam->params.version.firmwareVersion == 1 &&
366 cam->params.version.firmwareRevision == 2)
367 /* 1-02 firmware limits gain to 2 */
368 sprintf(tmpstr, "%8d %8d %8d", 1, 2, 2);
370 sprintf(tmpstr, "%8d %8d %8d", 1, 8, 2);
372 if (cam->params.exposure.gainMode == 0)
373 out += sprintf(out, "max_gain: unknown %28s"
374 " powers of 2\n", tmpstr);
376 out += sprintf(out, "max_gain: %8d %28s"
378 1<<(cam->params.exposure.gainMode-1), tmpstr);
380 switch(cam->params.exposure.expMode) {
383 sprintf(tmpstr, "manual");
386 sprintf(tmpstr, "auto");
389 sprintf(tmpstr, "unknown");
392 out += sprintf(out, "exposure_mode: %8s %8s %8s"
393 " %8s\n", tmpstr, "manual", "auto", "auto");
394 out += sprintf(out, "centre_weight: %8s %8s %8s %8s\n",
395 (2-cam->params.exposure.centreWeight) ? "on" : "off",
397 out += sprintf(out, "gain: %8d %8d max_gain %8d 1,2,4,8 possible\n",
398 1<<cam->params.exposure.gain, 1, 1);
399 if (cam->params.version.firmwareVersion == 1 &&
400 cam->params.version.firmwareRevision == 2)
401 /* 1-02 firmware limits fineExp/2 to 127 */
406 out += sprintf(out, "fine_exp: %8d %8d %8d %8d\n",
407 cam->params.exposure.fineExp*2, 0, tmp, 0);
408 if (cam->params.version.firmwareVersion == 1 &&
409 cam->params.version.firmwareRevision == 2)
410 /* 1-02 firmware limits coarseExpHi to 0 */
415 out += sprintf(out, "coarse_exp: %8d %8d %8d"
416 " %8d\n", cam->params.exposure.coarseExpLo+
417 256*cam->params.exposure.coarseExpHi, 0, tmp, 185);
418 out += sprintf(out, "red_comp: %8d %8d %8d %8d\n",
419 cam->params.exposure.redComp, COMP_RED, 255, COMP_RED);
420 out += sprintf(out, "green1_comp: %8d %8d %8d %8d\n",
421 cam->params.exposure.green1Comp, COMP_GREEN1, 255,
423 out += sprintf(out, "green2_comp: %8d %8d %8d %8d\n",
424 cam->params.exposure.green2Comp, COMP_GREEN2, 255,
426 out += sprintf(out, "blue_comp: %8d %8d %8d %8d\n",
427 cam->params.exposure.blueComp, COMP_BLUE, 255, COMP_BLUE);
429 out += sprintf(out, "apcor_gain1: %#8x %#8x %#8x %#8x\n",
430 cam->params.apcor.gain1, 0, 0xff, 0x1c);
431 out += sprintf(out, "apcor_gain2: %#8x %#8x %#8x %#8x\n",
432 cam->params.apcor.gain2, 0, 0xff, 0x1a);
433 out += sprintf(out, "apcor_gain4: %#8x %#8x %#8x %#8x\n",
434 cam->params.apcor.gain4, 0, 0xff, 0x2d);
435 out += sprintf(out, "apcor_gain8: %#8x %#8x %#8x %#8x\n",
436 cam->params.apcor.gain8, 0, 0xff, 0x2a);
437 out += sprintf(out, "vl_offset_gain1: %8d %8d %8d %8d\n",
438 cam->params.vlOffset.gain1, 0, 255, 24);
439 out += sprintf(out, "vl_offset_gain2: %8d %8d %8d %8d\n",
440 cam->params.vlOffset.gain2, 0, 255, 28);
441 out += sprintf(out, "vl_offset_gain4: %8d %8d %8d %8d\n",
442 cam->params.vlOffset.gain4, 0, 255, 30);
443 out += sprintf(out, "vl_offset_gain8: %8d %8d %8d %8d\n",
444 cam->params.vlOffset.gain8, 0, 255, 30);
445 out += sprintf(out, "flicker_control: %8s %8s %8s %8s\n",
446 cam->params.flickerControl.flickerMode ? "on" : "off",
448 out += sprintf(out, "mains_frequency: %8d %8d %8d %8d"
450 cam->mainsFreq ? 60 : 50, 50, 60, 50);
451 if(cam->params.flickerControl.allowableOverExposure < 0)
452 out += sprintf(out, "allowable_overexposure: %4dauto auto %8d auto\n",
453 -cam->params.flickerControl.allowableOverExposure,
456 out += sprintf(out, "allowable_overexposure: %8d auto %8d auto\n",
457 cam->params.flickerControl.allowableOverExposure,
459 out += sprintf(out, "compression_mode: ");
460 switch(cam->params.compression.mode) {
461 case CPIA_COMPRESSION_NONE:
462 out += sprintf(out, "%8s", "none");
464 case CPIA_COMPRESSION_AUTO:
465 out += sprintf(out, "%8s", "auto");
467 case CPIA_COMPRESSION_MANUAL:
468 out += sprintf(out, "%8s", "manual");
471 out += sprintf(out, "%8s", "unknown");
474 out += sprintf(out, " none,auto,manual auto\n");
475 out += sprintf(out, "decimation_enable: %8s %8s %8s %8s\n",
476 cam->params.compression.decimation ==
477 DECIMATION_ENAB ? "on":"off", "off", "on",
479 out += sprintf(out, "compression_target: %9s %9s %9s %9s\n",
480 cam->params.compressionTarget.frTargeting ==
481 CPIA_COMPRESSION_TARGET_FRAMERATE ?
482 "framerate":"quality",
483 "framerate", "quality", "quality");
484 out += sprintf(out, "target_framerate: %8d %8d %8d %8d\n",
485 cam->params.compressionTarget.targetFR, 1, 30, 15);
486 out += sprintf(out, "target_quality: %8d %8d %8d %8d\n",
487 cam->params.compressionTarget.targetQ, 1, 64, 5);
488 out += sprintf(out, "y_threshold: %8d %8d %8d %8d\n",
489 cam->params.yuvThreshold.yThreshold, 0, 31, 6);
490 out += sprintf(out, "uv_threshold: %8d %8d %8d %8d\n",
491 cam->params.yuvThreshold.uvThreshold, 0, 31, 6);
492 out += sprintf(out, "hysteresis: %8d %8d %8d %8d\n",
493 cam->params.compressionParams.hysteresis, 0, 255, 3);
494 out += sprintf(out, "threshold_max: %8d %8d %8d %8d\n",
495 cam->params.compressionParams.threshMax, 0, 255, 11);
496 out += sprintf(out, "small_step: %8d %8d %8d %8d\n",
497 cam->params.compressionParams.smallStep, 0, 255, 1);
498 out += sprintf(out, "large_step: %8d %8d %8d %8d\n",
499 cam->params.compressionParams.largeStep, 0, 255, 3);
500 out += sprintf(out, "decimation_hysteresis: %8d %8d %8d %8d\n",
501 cam->params.compressionParams.decimationHysteresis,
503 out += sprintf(out, "fr_diff_step_thresh: %8d %8d %8d %8d\n",
504 cam->params.compressionParams.frDiffStepThresh,
506 out += sprintf(out, "q_diff_step_thresh: %8d %8d %8d %8d\n",
507 cam->params.compressionParams.qDiffStepThresh,
509 out += sprintf(out, "decimation_thresh_mod: %8d %8d %8d %8d\n",
510 cam->params.compressionParams.decimationThreshMod,
512 /* QX3 specific entries */
513 if (cam->params.qx3.qx3_detected) {
514 out += sprintf(out, "toplight: %8s %8s %8s %8s\n",
515 cam->params.qx3.toplight ? "on" : "off",
517 out += sprintf(out, "bottomlight: %8s %8s %8s %8s\n",
518 cam->params.qx3.bottomlight ? "on" : "off",
526 if (len <= 0) return 0;
535 static int match(char *checkstr, char **buffer, unsigned long *count,
536 int *find_colon, int *err)
538 int ret, colon_found = 1;
539 int len = strlen(checkstr);
540 ret = (len <= *count && strncmp(*buffer, checkstr, len) == 0);
546 while (*count && (**buffer == ' ' || **buffer == '\t' ||
547 (!colon_found && **buffer == ':'))) {
553 if (!*count || !colon_found)
561 static unsigned long int value(char **buffer, unsigned long *count, int *err)
564 unsigned long int ret;
565 ret = simple_strtoul(*buffer, &p, 0);
569 *count -= p - *buffer;
575 static int cpia_write_proc(struct file *file, const char __user *buf,
576 unsigned long count, void *data)
578 struct cam_data *cam = data;
579 struct cam_params new_params;
581 int retval, find_colon;
583 unsigned long val = 0;
584 u32 command_flags = 0;
588 * This code to copy from buf to page is shamelessly copied
589 * from the comx driver
591 if (count > PAGE_SIZE) {
592 printk(KERN_ERR "count is %lu > %d!!!\n", count, (int)PAGE_SIZE);
596 if (!(page = (char *)__get_free_page(GFP_KERNEL))) return -ENOMEM;
598 if(copy_from_user(page, buf, count))
604 if (page[count-1] == '\n')
605 page[count-1] = '\0';
606 else if (count < PAGE_SIZE)
608 else if (page[count]) {
615 if (mutex_lock_interruptible(&cam->param_lock))
619 * Skip over leading whitespace
621 while (count && isspace(*buffer)) {
626 memcpy(&new_params, &cam->params, sizeof(struct cam_params));
627 new_mains = cam->mainsFreq;
629 #define MATCH(x) (match(x, &buffer, &count, &find_colon, &retval))
630 #define VALUE (value(&buffer,&count, &retval))
631 #define FIRMWARE_VERSION(x,y) (new_params.version.firmwareVersion == (x) && \
632 new_params.version.firmwareRevision == (y))
635 while (count && !retval) {
637 if (MATCH("brightness")) {
643 new_params.colourParams.brightness = val;
647 command_flags |= COMMAND_SETCOLOURPARAMS;
648 if(new_params.flickerControl.allowableOverExposure < 0)
649 new_params.flickerControl.allowableOverExposure =
650 -find_over_exposure(new_params.colourParams.brightness);
651 if(new_params.flickerControl.flickerMode != 0)
652 command_flags |= COMMAND_SETFLICKERCTRL;
654 } else if (MATCH("contrast")) {
660 /* contrast is in steps of 8, so round*/
661 val = ((val + 3) / 8) * 8;
662 /* 1-02 firmware limits contrast to 80*/
663 if (FIRMWARE_VERSION(1,2) && val > 80)
666 new_params.colourParams.contrast = val;
670 command_flags |= COMMAND_SETCOLOURPARAMS;
671 } else if (MATCH("saturation")) {
677 new_params.colourParams.saturation = val;
681 command_flags |= COMMAND_SETCOLOURPARAMS;
682 } else if (MATCH("sensor_fps")) {
687 /* find values so that sensorFPS is minimized,
692 new_params.sensorFps.divisor = 0;
693 new_params.sensorFps.baserate = 1;
694 } else if (val > 15) {
695 new_params.sensorFps.divisor = 0;
696 new_params.sensorFps.baserate = 0;
697 } else if (val > 12) {
698 new_params.sensorFps.divisor = 1;
699 new_params.sensorFps.baserate = 1;
700 } else if (val > 7) {
701 new_params.sensorFps.divisor = 1;
702 new_params.sensorFps.baserate = 0;
703 } else if (val > 6) {
704 new_params.sensorFps.divisor = 2;
705 new_params.sensorFps.baserate = 1;
706 } else if (val > 3) {
707 new_params.sensorFps.divisor = 2;
708 new_params.sensorFps.baserate = 0;
710 new_params.sensorFps.divisor = 3;
711 /* Either base rate would work here */
712 new_params.sensorFps.baserate = 1;
714 new_params.flickerControl.coarseJump =
715 flicker_jumps[new_mains]
716 [new_params.sensorFps.baserate]
717 [new_params.sensorFps.divisor];
718 if (new_params.flickerControl.flickerMode)
719 command_flags |= COMMAND_SETFLICKERCTRL;
721 command_flags |= COMMAND_SETSENSORFPS;
722 cam->exposure_status = EXPOSURE_NORMAL;
723 } else if (MATCH("stream_start_line")) {
730 if (new_params.format.videoSize == VIDEOSIZE_QCIF)
733 new_params.streamStartLine = val/2;
737 } else if (MATCH("sub_sample")) {
738 if (!retval && MATCH("420"))
739 new_params.format.subSample = SUBSAMPLE_420;
740 else if (!retval && MATCH("422"))
741 new_params.format.subSample = SUBSAMPLE_422;
745 command_flags |= COMMAND_SETFORMAT;
746 } else if (MATCH("yuv_order")) {
747 if (!retval && MATCH("YUYV"))
748 new_params.format.yuvOrder = YUVORDER_YUYV;
749 else if (!retval && MATCH("UYVY"))
750 new_params.format.yuvOrder = YUVORDER_UYVY;
754 command_flags |= COMMAND_SETFORMAT;
755 } else if (MATCH("ecp_timing")) {
756 if (!retval && MATCH("normal"))
757 new_params.ecpTiming = 0;
758 else if (!retval && MATCH("slow"))
759 new_params.ecpTiming = 1;
763 command_flags |= COMMAND_SETECPTIMING;
764 } else if (MATCH("color_balance_mode")) {
765 if (!retval && MATCH("manual"))
766 new_params.colourBalance.balanceMode = 3;
767 else if (!retval && MATCH("auto"))
768 new_params.colourBalance.balanceMode = 2;
772 command_flags |= COMMAND_SETCOLOURBALANCE;
773 } else if (MATCH("red_gain")) {
779 new_params.colourBalance.redGain = val;
780 new_params.colourBalance.balanceMode = 1;
784 command_flags |= COMMAND_SETCOLOURBALANCE;
785 } else if (MATCH("green_gain")) {
791 new_params.colourBalance.greenGain = val;
792 new_params.colourBalance.balanceMode = 1;
796 command_flags |= COMMAND_SETCOLOURBALANCE;
797 } else if (MATCH("blue_gain")) {
803 new_params.colourBalance.blueGain = val;
804 new_params.colourBalance.balanceMode = 1;
808 command_flags |= COMMAND_SETCOLOURBALANCE;
809 } else if (MATCH("max_gain")) {
814 /* 1-02 firmware limits gain to 2 */
815 if (FIRMWARE_VERSION(1,2) && val > 2)
819 new_params.exposure.gainMode = 1;
822 new_params.exposure.gainMode = 2;
825 new_params.exposure.gainMode = 3;
828 new_params.exposure.gainMode = 4;
835 command_flags |= COMMAND_SETEXPOSURE;
836 } else if (MATCH("exposure_mode")) {
837 if (!retval && MATCH("auto"))
838 new_params.exposure.expMode = 2;
839 else if (!retval && MATCH("manual")) {
840 if (new_params.exposure.expMode == 2)
841 new_params.exposure.expMode = 3;
842 if(new_params.flickerControl.flickerMode != 0)
843 command_flags |= COMMAND_SETFLICKERCTRL;
844 new_params.flickerControl.flickerMode = 0;
848 command_flags |= COMMAND_SETEXPOSURE;
849 } else if (MATCH("centre_weight")) {
850 if (!retval && MATCH("on"))
851 new_params.exposure.centreWeight = 1;
852 else if (!retval && MATCH("off"))
853 new_params.exposure.centreWeight = 2;
857 command_flags |= COMMAND_SETEXPOSURE;
858 } else if (MATCH("gain")) {
865 new_params.exposure.gain = 0;
868 new_params.exposure.gain = 1;
871 new_params.exposure.gain = 2;
874 new_params.exposure.gain = 3;
880 new_params.exposure.expMode = 1;
881 if(new_params.flickerControl.flickerMode != 0)
882 command_flags |= COMMAND_SETFLICKERCTRL;
883 new_params.flickerControl.flickerMode = 0;
884 command_flags |= COMMAND_SETEXPOSURE;
885 if (new_params.exposure.gain >
886 new_params.exposure.gainMode-1)
889 } else if (MATCH("fine_exp")) {
895 /* 1-02 firmware limits fineExp/2 to 127*/
896 if (FIRMWARE_VERSION(1,2) && val > 127)
898 new_params.exposure.fineExp = val;
899 new_params.exposure.expMode = 1;
900 command_flags |= COMMAND_SETEXPOSURE;
901 if(new_params.flickerControl.flickerMode != 0)
902 command_flags |= COMMAND_SETFLICKERCTRL;
903 new_params.flickerControl.flickerMode = 0;
904 command_flags |= COMMAND_SETFLICKERCTRL;
908 } else if (MATCH("coarse_exp")) {
913 if (val <= MAX_EXP) {
914 if (FIRMWARE_VERSION(1,2) &&
917 new_params.exposure.coarseExpLo =
919 new_params.exposure.coarseExpHi =
921 new_params.exposure.expMode = 1;
922 command_flags |= COMMAND_SETEXPOSURE;
923 if(new_params.flickerControl.flickerMode != 0)
924 command_flags |= COMMAND_SETFLICKERCTRL;
925 new_params.flickerControl.flickerMode = 0;
926 command_flags |= COMMAND_SETFLICKERCTRL;
930 } else if (MATCH("red_comp")) {
935 if (val >= COMP_RED && val <= 255) {
936 new_params.exposure.redComp = val;
937 new_params.exposure.compMode = 1;
938 command_flags |= COMMAND_SETEXPOSURE;
942 } else if (MATCH("green1_comp")) {
947 if (val >= COMP_GREEN1 && val <= 255) {
948 new_params.exposure.green1Comp = val;
949 new_params.exposure.compMode = 1;
950 command_flags |= COMMAND_SETEXPOSURE;
954 } else if (MATCH("green2_comp")) {
959 if (val >= COMP_GREEN2 && val <= 255) {
960 new_params.exposure.green2Comp = val;
961 new_params.exposure.compMode = 1;
962 command_flags |= COMMAND_SETEXPOSURE;
966 } else if (MATCH("blue_comp")) {
971 if (val >= COMP_BLUE && val <= 255) {
972 new_params.exposure.blueComp = val;
973 new_params.exposure.compMode = 1;
974 command_flags |= COMMAND_SETEXPOSURE;
978 } else if (MATCH("apcor_gain1")) {
983 command_flags |= COMMAND_SETAPCOR;
985 new_params.apcor.gain1 = val;
989 } else if (MATCH("apcor_gain2")) {
994 command_flags |= COMMAND_SETAPCOR;
996 new_params.apcor.gain2 = val;
1000 } else if (MATCH("apcor_gain4")) {
1005 command_flags |= COMMAND_SETAPCOR;
1007 new_params.apcor.gain4 = val;
1011 } else if (MATCH("apcor_gain8")) {
1016 command_flags |= COMMAND_SETAPCOR;
1018 new_params.apcor.gain8 = val;
1022 } else if (MATCH("vl_offset_gain1")) {
1028 new_params.vlOffset.gain1 = val;
1032 command_flags |= COMMAND_SETVLOFFSET;
1033 } else if (MATCH("vl_offset_gain2")) {
1039 new_params.vlOffset.gain2 = val;
1043 command_flags |= COMMAND_SETVLOFFSET;
1044 } else if (MATCH("vl_offset_gain4")) {
1050 new_params.vlOffset.gain4 = val;
1054 command_flags |= COMMAND_SETVLOFFSET;
1055 } else if (MATCH("vl_offset_gain8")) {
1061 new_params.vlOffset.gain8 = val;
1065 command_flags |= COMMAND_SETVLOFFSET;
1066 } else if (MATCH("flicker_control")) {
1067 if (!retval && MATCH("on")) {
1068 set_flicker(&new_params, &command_flags, 1);
1069 } else if (!retval && MATCH("off")) {
1070 set_flicker(&new_params, &command_flags, 0);
1074 command_flags |= COMMAND_SETFLICKERCTRL;
1075 } else if (MATCH("mains_frequency")) {
1076 if (!retval && MATCH("50")) {
1078 new_params.flickerControl.coarseJump =
1079 flicker_jumps[new_mains]
1080 [new_params.sensorFps.baserate]
1081 [new_params.sensorFps.divisor];
1082 if (new_params.flickerControl.flickerMode)
1083 command_flags |= COMMAND_SETFLICKERCTRL;
1084 } else if (!retval && MATCH("60")) {
1086 new_params.flickerControl.coarseJump =
1087 flicker_jumps[new_mains]
1088 [new_params.sensorFps.baserate]
1089 [new_params.sensorFps.divisor];
1090 if (new_params.flickerControl.flickerMode)
1091 command_flags |= COMMAND_SETFLICKERCTRL;
1094 } else if (MATCH("allowable_overexposure")) {
1095 if (!retval && MATCH("auto")) {
1096 new_params.flickerControl.allowableOverExposure =
1097 -find_over_exposure(new_params.colourParams.brightness);
1098 if(new_params.flickerControl.flickerMode != 0)
1099 command_flags |= COMMAND_SETFLICKERCTRL;
1106 new_params.flickerControl.
1107 allowableOverExposure = val;
1108 if(new_params.flickerControl.flickerMode != 0)
1109 command_flags |= COMMAND_SETFLICKERCTRL;
1114 } else if (MATCH("compression_mode")) {
1115 if (!retval && MATCH("none"))
1116 new_params.compression.mode =
1117 CPIA_COMPRESSION_NONE;
1118 else if (!retval && MATCH("auto"))
1119 new_params.compression.mode =
1120 CPIA_COMPRESSION_AUTO;
1121 else if (!retval && MATCH("manual"))
1122 new_params.compression.mode =
1123 CPIA_COMPRESSION_MANUAL;
1127 command_flags |= COMMAND_SETCOMPRESSION;
1128 } else if (MATCH("decimation_enable")) {
1129 if (!retval && MATCH("off"))
1130 new_params.compression.decimation = 0;
1131 else if (!retval && MATCH("on"))
1132 new_params.compression.decimation = 1;
1136 command_flags |= COMMAND_SETCOMPRESSION;
1137 } else if (MATCH("compression_target")) {
1138 if (!retval && MATCH("quality"))
1139 new_params.compressionTarget.frTargeting =
1140 CPIA_COMPRESSION_TARGET_QUALITY;
1141 else if (!retval && MATCH("framerate"))
1142 new_params.compressionTarget.frTargeting =
1143 CPIA_COMPRESSION_TARGET_FRAMERATE;
1147 command_flags |= COMMAND_SETCOMPRESSIONTARGET;
1148 } else if (MATCH("target_framerate")) {
1153 if(val > 0 && val <= 30)
1154 new_params.compressionTarget.targetFR = val;
1158 command_flags |= COMMAND_SETCOMPRESSIONTARGET;
1159 } else if (MATCH("target_quality")) {
1164 if(val > 0 && val <= 64)
1165 new_params.compressionTarget.targetQ = val;
1169 command_flags |= COMMAND_SETCOMPRESSIONTARGET;
1170 } else if (MATCH("y_threshold")) {
1176 new_params.yuvThreshold.yThreshold = val;
1180 command_flags |= COMMAND_SETYUVTHRESH;
1181 } else if (MATCH("uv_threshold")) {
1187 new_params.yuvThreshold.uvThreshold = val;
1191 command_flags |= COMMAND_SETYUVTHRESH;
1192 } else if (MATCH("hysteresis")) {
1198 new_params.compressionParams.hysteresis = val;
1202 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1203 } else if (MATCH("threshold_max")) {
1209 new_params.compressionParams.threshMax = val;
1213 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1214 } else if (MATCH("small_step")) {
1220 new_params.compressionParams.smallStep = val;
1224 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1225 } else if (MATCH("large_step")) {
1231 new_params.compressionParams.largeStep = val;
1235 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1236 } else if (MATCH("decimation_hysteresis")) {
1242 new_params.compressionParams.decimationHysteresis = val;
1246 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1247 } else if (MATCH("fr_diff_step_thresh")) {
1253 new_params.compressionParams.frDiffStepThresh = val;
1257 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1258 } else if (MATCH("q_diff_step_thresh")) {
1264 new_params.compressionParams.qDiffStepThresh = val;
1268 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1269 } else if (MATCH("decimation_thresh_mod")) {
1275 new_params.compressionParams.decimationThreshMod = val;
1279 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1280 } else if (MATCH("toplight")) {
1281 if (!retval && MATCH("on"))
1282 new_params.qx3.toplight = 1;
1283 else if (!retval && MATCH("off"))
1284 new_params.qx3.toplight = 0;
1287 command_flags |= COMMAND_SETLIGHTS;
1288 } else if (MATCH("bottomlight")) {
1289 if (!retval && MATCH("on"))
1290 new_params.qx3.bottomlight = 1;
1291 else if (!retval && MATCH("off"))
1292 new_params.qx3.bottomlight = 0;
1295 command_flags |= COMMAND_SETLIGHTS;
1297 DBG("No match found\n");
1302 while (count && isspace(*buffer) && *buffer != '\n') {
1307 if (*buffer == '\0' && count != 1)
1309 else if (*buffer != '\n' && *buffer != ';' &&
1321 #undef FIRMWARE_VERSION
1323 if (command_flags & COMMAND_SETCOLOURPARAMS) {
1324 /* Adjust cam->vp to reflect these changes */
1325 cam->vp.brightness =
1326 new_params.colourParams.brightness*65535/100;
1328 new_params.colourParams.contrast*65535/100;
1330 new_params.colourParams.saturation*65535/100;
1332 if((command_flags & COMMAND_SETEXPOSURE) &&
1333 new_params.exposure.expMode == 2)
1334 cam->exposure_status = EXPOSURE_NORMAL;
1336 memcpy(&cam->params, &new_params, sizeof(struct cam_params));
1337 cam->mainsFreq = new_mains;
1338 cam->cmd_queue |= command_flags;
1341 DBG("error: %d\n", retval);
1343 mutex_unlock(&cam->param_lock);
1346 free_page((unsigned long)page);
1350 static void create_proc_cpia_cam(struct cam_data *cam)
1352 char name[5 + 1 + 10 + 1];
1353 struct proc_dir_entry *ent;
1355 if (!cpia_proc_root || !cam)
1358 snprintf(name, sizeof(name), "video%d", cam->vdev.minor);
1360 ent = create_proc_entry(name, S_IFREG|S_IRUGO|S_IWUSR, cpia_proc_root);
1365 ent->read_proc = cpia_read_proc;
1366 ent->write_proc = cpia_write_proc;
1368 size of the proc entry is 3736 bytes for the standard webcam;
1369 the extra features of the QX3 microscope add 189 bytes.
1370 (we have not yet probed the camera to see which type it is).
1372 ent->size = 3736 + 189;
1373 cam->proc_entry = ent;
1376 static void destroy_proc_cpia_cam(struct cam_data *cam)
1378 char name[5 + 1 + 10 + 1];
1380 if (!cam || !cam->proc_entry)
1383 snprintf(name, sizeof(name), "video%d", cam->vdev.minor);
1384 remove_proc_entry(name, cpia_proc_root);
1385 cam->proc_entry = NULL;
1388 static void proc_cpia_create(void)
1390 cpia_proc_root = proc_mkdir("cpia", NULL);
1393 cpia_proc_root->owner = THIS_MODULE;
1395 LOG("Unable to initialise /proc/cpia\n");
1398 static void __exit proc_cpia_destroy(void)
1400 remove_proc_entry("cpia", NULL);
1402 #endif /* CONFIG_PROC_FS */
1404 /* ----------------------- debug functions ---------------------- */
1406 #define printstatus(cam) \
1407 DBG("%02x %02x %02x %02x %02x %02x %02x %02x\n",\
1408 cam->params.status.systemState, cam->params.status.grabState, \
1409 cam->params.status.streamState, cam->params.status.fatalError, \
1410 cam->params.status.cmdError, cam->params.status.debugFlags, \
1411 cam->params.status.vpStatus, cam->params.status.errorCode);
1413 /* ----------------------- v4l helpers -------------------------- */
1415 /* supported frame palettes and depths */
1416 static inline int valid_mode(u16 palette, u16 depth)
1418 if ((palette == VIDEO_PALETTE_YUV422 && depth == 16) ||
1419 (palette == VIDEO_PALETTE_YUYV && depth == 16))
1422 if (colorspace_conv)
1423 return (palette == VIDEO_PALETTE_GREY && depth == 8) ||
1424 (palette == VIDEO_PALETTE_RGB555 && depth == 16) ||
1425 (palette == VIDEO_PALETTE_RGB565 && depth == 16) ||
1426 (palette == VIDEO_PALETTE_RGB24 && depth == 24) ||
1427 (palette == VIDEO_PALETTE_RGB32 && depth == 32) ||
1428 (palette == VIDEO_PALETTE_UYVY && depth == 16);
1433 static int match_videosize( int width, int height )
1435 /* return the best match, where 'best' is as always
1436 * the largest that is not bigger than what is requested. */
1437 if (width>=352 && height>=288)
1438 return VIDEOSIZE_352_288; /* CIF */
1440 if (width>=320 && height>=240)
1441 return VIDEOSIZE_320_240; /* SIF */
1443 if (width>=288 && height>=216)
1444 return VIDEOSIZE_288_216;
1446 if (width>=256 && height>=192)
1447 return VIDEOSIZE_256_192;
1449 if (width>=224 && height>=168)
1450 return VIDEOSIZE_224_168;
1452 if (width>=192 && height>=144)
1453 return VIDEOSIZE_192_144;
1455 if (width>=176 && height>=144)
1456 return VIDEOSIZE_176_144; /* QCIF */
1458 if (width>=160 && height>=120)
1459 return VIDEOSIZE_160_120; /* QSIF */
1461 if (width>=128 && height>=96)
1462 return VIDEOSIZE_128_96;
1464 if (width>=88 && height>=72)
1465 return VIDEOSIZE_88_72;
1467 if (width>=64 && height>=48)
1468 return VIDEOSIZE_64_48;
1470 if (width>=48 && height>=48)
1471 return VIDEOSIZE_48_48;
1476 /* these are the capture sizes we support */
1477 static void set_vw_size(struct cam_data *cam)
1479 /* the col/row/start/end values are the result of simple math */
1480 /* study the SetROI-command in cpia developers guide p 2-22 */
1481 /* streamStartLine is set to the recommended value in the cpia */
1482 /* developers guide p 3-37 */
1483 switch(cam->video_size) {
1485 cam->vw.width = 352;
1486 cam->vw.height = 288;
1487 cam->params.format.videoSize=VIDEOSIZE_CIF;
1488 cam->params.roi.colStart=0;
1489 cam->params.roi.rowStart=0;
1490 cam->params.streamStartLine = 120;
1493 cam->vw.width = 320;
1494 cam->vw.height = 240;
1495 cam->params.format.videoSize=VIDEOSIZE_CIF;
1496 cam->params.roi.colStart=2;
1497 cam->params.roi.rowStart=6;
1498 cam->params.streamStartLine = 120;
1500 case VIDEOSIZE_288_216:
1501 cam->vw.width = 288;
1502 cam->vw.height = 216;
1503 cam->params.format.videoSize=VIDEOSIZE_CIF;
1504 cam->params.roi.colStart=4;
1505 cam->params.roi.rowStart=9;
1506 cam->params.streamStartLine = 120;
1508 case VIDEOSIZE_256_192:
1509 cam->vw.width = 256;
1510 cam->vw.height = 192;
1511 cam->params.format.videoSize=VIDEOSIZE_CIF;
1512 cam->params.roi.colStart=6;
1513 cam->params.roi.rowStart=12;
1514 cam->params.streamStartLine = 120;
1516 case VIDEOSIZE_224_168:
1517 cam->vw.width = 224;
1518 cam->vw.height = 168;
1519 cam->params.format.videoSize=VIDEOSIZE_CIF;
1520 cam->params.roi.colStart=8;
1521 cam->params.roi.rowStart=15;
1522 cam->params.streamStartLine = 120;
1524 case VIDEOSIZE_192_144:
1525 cam->vw.width = 192;
1526 cam->vw.height = 144;
1527 cam->params.format.videoSize=VIDEOSIZE_CIF;
1528 cam->params.roi.colStart=10;
1529 cam->params.roi.rowStart=18;
1530 cam->params.streamStartLine = 120;
1532 case VIDEOSIZE_QCIF:
1533 cam->vw.width = 176;
1534 cam->vw.height = 144;
1535 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1536 cam->params.roi.colStart=0;
1537 cam->params.roi.rowStart=0;
1538 cam->params.streamStartLine = 60;
1540 case VIDEOSIZE_QSIF:
1541 cam->vw.width = 160;
1542 cam->vw.height = 120;
1543 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1544 cam->params.roi.colStart=1;
1545 cam->params.roi.rowStart=3;
1546 cam->params.streamStartLine = 60;
1548 case VIDEOSIZE_128_96:
1549 cam->vw.width = 128;
1550 cam->vw.height = 96;
1551 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1552 cam->params.roi.colStart=3;
1553 cam->params.roi.rowStart=6;
1554 cam->params.streamStartLine = 60;
1556 case VIDEOSIZE_88_72:
1558 cam->vw.height = 72;
1559 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1560 cam->params.roi.colStart=5;
1561 cam->params.roi.rowStart=9;
1562 cam->params.streamStartLine = 60;
1564 case VIDEOSIZE_64_48:
1566 cam->vw.height = 48;
1567 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1568 cam->params.roi.colStart=7;
1569 cam->params.roi.rowStart=12;
1570 cam->params.streamStartLine = 60;
1572 case VIDEOSIZE_48_48:
1574 cam->vw.height = 48;
1575 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1576 cam->params.roi.colStart=8;
1577 cam->params.roi.rowStart=6;
1578 cam->params.streamStartLine = 60;
1581 LOG("bad videosize value: %d\n", cam->video_size);
1585 if(cam->vc.width == 0)
1586 cam->vc.width = cam->vw.width;
1587 if(cam->vc.height == 0)
1588 cam->vc.height = cam->vw.height;
1590 cam->params.roi.colStart += cam->vc.x >> 3;
1591 cam->params.roi.colEnd = cam->params.roi.colStart +
1592 (cam->vc.width >> 3);
1593 cam->params.roi.rowStart += cam->vc.y >> 2;
1594 cam->params.roi.rowEnd = cam->params.roi.rowStart +
1595 (cam->vc.height >> 2);
1600 static int allocate_frame_buf(struct cam_data *cam)
1604 cam->frame_buf = rvmalloc(FRAME_NUM * CPIA_MAX_FRAME_SIZE);
1605 if (!cam->frame_buf)
1608 for (i = 0; i < FRAME_NUM; i++)
1609 cam->frame[i].data = cam->frame_buf + i * CPIA_MAX_FRAME_SIZE;
1614 static int free_frame_buf(struct cam_data *cam)
1618 rvfree(cam->frame_buf, FRAME_NUM*CPIA_MAX_FRAME_SIZE);
1619 cam->frame_buf = NULL;
1620 for (i=0; i < FRAME_NUM; i++)
1621 cam->frame[i].data = NULL;
1627 static inline void free_frames(struct cpia_frame frame[FRAME_NUM])
1631 for (i=0; i < FRAME_NUM; i++)
1632 frame[i].state = FRAME_UNUSED;
1636 /**********************************************************************
1640 **********************************************************************/
1641 /* send an arbitrary command to the camera */
1642 static int do_command(struct cam_data *cam, u16 command, u8 a, u8 b, u8 c, u8 d)
1644 int retval, datasize;
1648 case CPIA_COMMAND_GetCPIAVersion:
1649 case CPIA_COMMAND_GetPnPID:
1650 case CPIA_COMMAND_GetCameraStatus:
1651 case CPIA_COMMAND_GetVPVersion:
1654 case CPIA_COMMAND_GetColourParams:
1655 case CPIA_COMMAND_GetColourBalance:
1656 case CPIA_COMMAND_GetExposure:
1657 mutex_lock(&cam->param_lock);
1660 case CPIA_COMMAND_ReadMCPorts:
1661 case CPIA_COMMAND_ReadVCRegs:
1669 cmd[0] = command>>8;
1670 cmd[1] = command&0xff;
1678 retval = cam->ops->transferCmd(cam->lowlevel_data, cmd, data);
1680 DBG("%x - failed, retval=%d\n", command, retval);
1681 if (command == CPIA_COMMAND_GetColourParams ||
1682 command == CPIA_COMMAND_GetColourBalance ||
1683 command == CPIA_COMMAND_GetExposure)
1684 mutex_unlock(&cam->param_lock);
1687 case CPIA_COMMAND_GetCPIAVersion:
1688 cam->params.version.firmwareVersion = data[0];
1689 cam->params.version.firmwareRevision = data[1];
1690 cam->params.version.vcVersion = data[2];
1691 cam->params.version.vcRevision = data[3];
1693 case CPIA_COMMAND_GetPnPID:
1694 cam->params.pnpID.vendor = data[0]+(((u16)data[1])<<8);
1695 cam->params.pnpID.product = data[2]+(((u16)data[3])<<8);
1696 cam->params.pnpID.deviceRevision =
1697 data[4]+(((u16)data[5])<<8);
1699 case CPIA_COMMAND_GetCameraStatus:
1700 cam->params.status.systemState = data[0];
1701 cam->params.status.grabState = data[1];
1702 cam->params.status.streamState = data[2];
1703 cam->params.status.fatalError = data[3];
1704 cam->params.status.cmdError = data[4];
1705 cam->params.status.debugFlags = data[5];
1706 cam->params.status.vpStatus = data[6];
1707 cam->params.status.errorCode = data[7];
1709 case CPIA_COMMAND_GetVPVersion:
1710 cam->params.vpVersion.vpVersion = data[0];
1711 cam->params.vpVersion.vpRevision = data[1];
1712 cam->params.vpVersion.cameraHeadID =
1713 data[2]+(((u16)data[3])<<8);
1715 case CPIA_COMMAND_GetColourParams:
1716 cam->params.colourParams.brightness = data[0];
1717 cam->params.colourParams.contrast = data[1];
1718 cam->params.colourParams.saturation = data[2];
1719 mutex_unlock(&cam->param_lock);
1721 case CPIA_COMMAND_GetColourBalance:
1722 cam->params.colourBalance.redGain = data[0];
1723 cam->params.colourBalance.greenGain = data[1];
1724 cam->params.colourBalance.blueGain = data[2];
1725 mutex_unlock(&cam->param_lock);
1727 case CPIA_COMMAND_GetExposure:
1728 cam->params.exposure.gain = data[0];
1729 cam->params.exposure.fineExp = data[1];
1730 cam->params.exposure.coarseExpLo = data[2];
1731 cam->params.exposure.coarseExpHi = data[3];
1732 cam->params.exposure.redComp = data[4];
1733 cam->params.exposure.green1Comp = data[5];
1734 cam->params.exposure.green2Comp = data[6];
1735 cam->params.exposure.blueComp = data[7];
1736 mutex_unlock(&cam->param_lock);
1739 case CPIA_COMMAND_ReadMCPorts:
1740 if (!cam->params.qx3.qx3_detected)
1742 /* test button press */
1743 cam->params.qx3.button = ((data[1] & 0x02) == 0);
1744 if (cam->params.qx3.button) {
1745 /* button pressed - unlock the latch */
1746 do_command(cam,CPIA_COMMAND_WriteMCPort,3,0xDF,0xDF,0);
1747 do_command(cam,CPIA_COMMAND_WriteMCPort,3,0xFF,0xFF,0);
1750 /* test whether microscope is cradled */
1751 cam->params.qx3.cradled = ((data[2] & 0x40) == 0);
1761 /* send a command to the camera with an additional data transaction */
1762 static int do_command_extended(struct cam_data *cam, u16 command,
1763 u8 a, u8 b, u8 c, u8 d,
1764 u8 e, u8 f, u8 g, u8 h,
1765 u8 i, u8 j, u8 k, u8 l)
1770 cmd[0] = command>>8;
1771 cmd[1] = command&0xff;
1787 retval = cam->ops->transferCmd(cam->lowlevel_data, cmd, data);
1789 DBG("%x - failed\n", command);
1794 /**********************************************************************
1796 * Colorspace conversion
1798 **********************************************************************/
1799 #define LIMIT(x) ((((x)>0xffffff)?0xff0000:(((x)<=0xffff)?0:(x)&0xff0000))>>16)
1801 static int convert420(unsigned char *yuv, unsigned char *rgb, int out_fmt,
1802 int linesize, int mmap_kludge)
1804 int y, u, v, r, g, b, y1;
1806 /* Odd lines use the same u and v as the previous line.
1807 * Because of compression, it is necessary to get this
1808 * information from the decoded image. */
1810 case VIDEO_PALETTE_RGB555:
1811 y = (*yuv++ - 16) * 76310;
1812 y1 = (*yuv - 16) * 76310;
1813 r = ((*(rgb+1-linesize)) & 0x7c) << 1;
1814 g = ((*(rgb-linesize)) & 0xe0) >> 4 |
1815 ((*(rgb+1-linesize)) & 0x03) << 6;
1816 b = ((*(rgb-linesize)) & 0x1f) << 3;
1817 u = (-53294 * r - 104635 * g + 157929 * b) / 5756495;
1818 v = (157968 * r - 132278 * g - 25690 * b) / 5366159;
1820 g = -25690 * u - 53294 * v;
1822 *rgb++ = ((LIMIT(g+y) & 0xf8) << 2) | (LIMIT(b+y) >> 3);
1823 *rgb++ = ((LIMIT(r+y) & 0xf8) >> 1) | (LIMIT(g+y) >> 6);
1824 *rgb++ = ((LIMIT(g+y1) & 0xf8) << 2) | (LIMIT(b+y1) >> 3);
1825 *rgb = ((LIMIT(r+y1) & 0xf8) >> 1) | (LIMIT(g+y1) >> 6);
1827 case VIDEO_PALETTE_RGB565:
1828 y = (*yuv++ - 16) * 76310;
1829 y1 = (*yuv - 16) * 76310;
1830 r = (*(rgb+1-linesize)) & 0xf8;
1831 g = ((*(rgb-linesize)) & 0xe0) >> 3 |
1832 ((*(rgb+1-linesize)) & 0x07) << 5;
1833 b = ((*(rgb-linesize)) & 0x1f) << 3;
1834 u = (-53294 * r - 104635 * g + 157929 * b) / 5756495;
1835 v = (157968 * r - 132278 * g - 25690 * b) / 5366159;
1837 g = -25690 * u - 53294 * v;
1839 *rgb++ = ((LIMIT(g+y) & 0xfc) << 3) | (LIMIT(b+y) >> 3);
1840 *rgb++ = (LIMIT(r+y) & 0xf8) | (LIMIT(g+y) >> 5);
1841 *rgb++ = ((LIMIT(g+y1) & 0xfc) << 3) | (LIMIT(b+y1) >> 3);
1842 *rgb = (LIMIT(r+y1) & 0xf8) | (LIMIT(g+y1) >> 5);
1845 case VIDEO_PALETTE_RGB24:
1846 case VIDEO_PALETTE_RGB32:
1847 y = (*yuv++ - 16) * 76310;
1848 y1 = (*yuv - 16) * 76310;
1850 r = *(rgb+2-linesize);
1851 g = *(rgb+1-linesize);
1852 b = *(rgb-linesize);
1854 r = *(rgb-linesize);
1855 g = *(rgb+1-linesize);
1856 b = *(rgb+2-linesize);
1858 u = (-53294 * r - 104635 * g + 157929 * b) / 5756495;
1859 v = (157968 * r - 132278 * g - 25690 * b) / 5366159;
1861 g = -25690 * u + -53294 * v;
1864 *rgb++ = LIMIT(b+y);
1865 *rgb++ = LIMIT(g+y);
1866 *rgb++ = LIMIT(r+y);
1867 if(out_fmt == VIDEO_PALETTE_RGB32)
1869 *rgb++ = LIMIT(b+y1);
1870 *rgb++ = LIMIT(g+y1);
1873 *rgb++ = LIMIT(r+y);
1874 *rgb++ = LIMIT(g+y);
1875 *rgb++ = LIMIT(b+y);
1876 if(out_fmt == VIDEO_PALETTE_RGB32)
1878 *rgb++ = LIMIT(r+y1);
1879 *rgb++ = LIMIT(g+y1);
1882 if(out_fmt == VIDEO_PALETTE_RGB32)
1885 case VIDEO_PALETTE_YUV422:
1886 case VIDEO_PALETTE_YUYV:
1888 u = *(rgb+1-linesize);
1890 v = *(rgb+3-linesize);
1896 case VIDEO_PALETTE_UYVY:
1897 u = *(rgb-linesize);
1899 v = *(rgb+2-linesize);
1906 case VIDEO_PALETTE_GREY:
1911 DBG("Empty: %d\n", out_fmt);
1917 static int yuvconvert(unsigned char *yuv, unsigned char *rgb, int out_fmt,
1918 int in_uyvy, int mmap_kludge)
1920 int y, u, v, r, g, b, y1;
1923 case VIDEO_PALETTE_RGB555:
1924 case VIDEO_PALETTE_RGB565:
1925 case VIDEO_PALETTE_RGB24:
1926 case VIDEO_PALETTE_RGB32:
1929 y = (*yuv++ - 16) * 76310;
1931 y1 = (*yuv - 16) * 76310;
1933 y = (*yuv++ - 16) * 76310;
1935 y1 = (*yuv++ - 16) * 76310;
1939 g = -25690 * u + -53294 * v;
1947 /* Just to avoid compiler warnings */
1954 case VIDEO_PALETTE_RGB555:
1955 *rgb++ = ((LIMIT(g+y) & 0xf8) << 2) | (LIMIT(b+y) >> 3);
1956 *rgb++ = ((LIMIT(r+y) & 0xf8) >> 1) | (LIMIT(g+y) >> 6);
1957 *rgb++ = ((LIMIT(g+y1) & 0xf8) << 2) | (LIMIT(b+y1) >> 3);
1958 *rgb = ((LIMIT(r+y1) & 0xf8) >> 1) | (LIMIT(g+y1) >> 6);
1960 case VIDEO_PALETTE_RGB565:
1961 *rgb++ = ((LIMIT(g+y) & 0xfc) << 3) | (LIMIT(b+y) >> 3);
1962 *rgb++ = (LIMIT(r+y) & 0xf8) | (LIMIT(g+y) >> 5);
1963 *rgb++ = ((LIMIT(g+y1) & 0xfc) << 3) | (LIMIT(b+y1) >> 3);
1964 *rgb = (LIMIT(r+y1) & 0xf8) | (LIMIT(g+y1) >> 5);
1966 case VIDEO_PALETTE_RGB24:
1968 *rgb++ = LIMIT(b+y);
1969 *rgb++ = LIMIT(g+y);
1970 *rgb++ = LIMIT(r+y);
1971 *rgb++ = LIMIT(b+y1);
1972 *rgb++ = LIMIT(g+y1);
1975 *rgb++ = LIMIT(r+y);
1976 *rgb++ = LIMIT(g+y);
1977 *rgb++ = LIMIT(b+y);
1978 *rgb++ = LIMIT(r+y1);
1979 *rgb++ = LIMIT(g+y1);
1983 case VIDEO_PALETTE_RGB32:
1985 *rgb++ = LIMIT(b+y);
1986 *rgb++ = LIMIT(g+y);
1987 *rgb++ = LIMIT(r+y);
1989 *rgb++ = LIMIT(b+y1);
1990 *rgb++ = LIMIT(g+y1);
1993 *rgb++ = LIMIT(r+y);
1994 *rgb++ = LIMIT(g+y);
1995 *rgb++ = LIMIT(b+y);
1997 *rgb++ = LIMIT(r+y1);
1998 *rgb++ = LIMIT(g+y1);
2002 case VIDEO_PALETTE_GREY:
2006 case VIDEO_PALETTE_YUV422:
2007 case VIDEO_PALETTE_YUYV:
2013 case VIDEO_PALETTE_UYVY:
2020 DBG("Empty: %d\n", out_fmt);
2025 static int skipcount(int count, int fmt)
2028 case VIDEO_PALETTE_GREY:
2030 case VIDEO_PALETTE_RGB555:
2031 case VIDEO_PALETTE_RGB565:
2032 case VIDEO_PALETTE_YUV422:
2033 case VIDEO_PALETTE_YUYV:
2034 case VIDEO_PALETTE_UYVY:
2036 case VIDEO_PALETTE_RGB24:
2038 case VIDEO_PALETTE_RGB32:
2045 static int parse_picture(struct cam_data *cam, int size)
2047 u8 *obuf, *ibuf, *end_obuf;
2048 int ll, in_uyvy, compressed, decimation, even_line, origsize, out_fmt;
2049 int rows, cols, linesize, subsample_422;
2051 /* make sure params don't change while we are decoding */
2052 mutex_lock(&cam->param_lock);
2054 obuf = cam->decompressed_frame.data;
2055 end_obuf = obuf+CPIA_MAX_FRAME_SIZE;
2056 ibuf = cam->raw_image;
2058 out_fmt = cam->vp.palette;
2060 if ((ibuf[0] != MAGIC_0) || (ibuf[1] != MAGIC_1)) {
2061 LOG("header not found\n");
2062 mutex_unlock(&cam->param_lock);
2066 if ((ibuf[16] != VIDEOSIZE_QCIF) && (ibuf[16] != VIDEOSIZE_CIF)) {
2067 LOG("wrong video size\n");
2068 mutex_unlock(&cam->param_lock);
2072 if (ibuf[17] != SUBSAMPLE_420 && ibuf[17] != SUBSAMPLE_422) {
2073 LOG("illegal subtype %d\n",ibuf[17]);
2074 mutex_unlock(&cam->param_lock);
2077 subsample_422 = ibuf[17] == SUBSAMPLE_422;
2079 if (ibuf[18] != YUVORDER_YUYV && ibuf[18] != YUVORDER_UYVY) {
2080 LOG("illegal yuvorder %d\n",ibuf[18]);
2081 mutex_unlock(&cam->param_lock);
2084 in_uyvy = ibuf[18] == YUVORDER_UYVY;
2086 if ((ibuf[24] != cam->params.roi.colStart) ||
2087 (ibuf[25] != cam->params.roi.colEnd) ||
2088 (ibuf[26] != cam->params.roi.rowStart) ||
2089 (ibuf[27] != cam->params.roi.rowEnd)) {
2090 LOG("ROI mismatch\n");
2091 mutex_unlock(&cam->param_lock);
2094 cols = 8*(ibuf[25] - ibuf[24]);
2095 rows = 4*(ibuf[27] - ibuf[26]);
2098 if ((ibuf[28] != NOT_COMPRESSED) && (ibuf[28] != COMPRESSED)) {
2099 LOG("illegal compression %d\n",ibuf[28]);
2100 mutex_unlock(&cam->param_lock);
2103 compressed = (ibuf[28] == COMPRESSED);
2105 if (ibuf[29] != NO_DECIMATION && ibuf[29] != DECIMATION_ENAB) {
2106 LOG("illegal decimation %d\n",ibuf[29]);
2107 mutex_unlock(&cam->param_lock);
2110 decimation = (ibuf[29] == DECIMATION_ENAB);
2112 cam->params.yuvThreshold.yThreshold = ibuf[30];
2113 cam->params.yuvThreshold.uvThreshold = ibuf[31];
2114 cam->params.status.systemState = ibuf[32];
2115 cam->params.status.grabState = ibuf[33];
2116 cam->params.status.streamState = ibuf[34];
2117 cam->params.status.fatalError = ibuf[35];
2118 cam->params.status.cmdError = ibuf[36];
2119 cam->params.status.debugFlags = ibuf[37];
2120 cam->params.status.vpStatus = ibuf[38];
2121 cam->params.status.errorCode = ibuf[39];
2122 cam->fps = ibuf[41];
2123 mutex_unlock(&cam->param_lock);
2125 linesize = skipcount(cols, out_fmt);
2126 ibuf += FRAME_HEADER_SIZE;
2127 size -= FRAME_HEADER_SIZE;
2128 ll = ibuf[0] | (ibuf[1] << 8);
2135 LOG("Insufficient data in buffer\n");
2140 if (!compressed || (compressed && !(*ibuf & 1))) {
2141 if(subsample_422 || even_line) {
2142 obuf += yuvconvert(ibuf, obuf, out_fmt,
2143 in_uyvy, cam->mmap_kludge);
2147 /* SUBSAMPLE_420 on an odd line */
2148 obuf += convert420(ibuf, obuf,
2155 /*skip compressed interval from previous frame*/
2156 obuf += skipcount(*ibuf >> 1, out_fmt);
2157 if (obuf > end_obuf) {
2158 LOG("Insufficient buffer size\n");
2167 DBG("EOL not found giving up after %d/%d"
2168 " bytes\n", origsize-size, origsize);
2172 ++ibuf; /* skip over EOL */
2174 if ((size > 3) && (ibuf[0] == EOI) && (ibuf[1] == EOI) &&
2175 (ibuf[2] == EOI) && (ibuf[3] == EOI)) {
2181 /* skip the odd lines for now */
2186 ll = ibuf[0] | (ibuf[1] << 8);
2187 ibuf += 2; /* skip over line length */
2190 even_line = !even_line;
2192 LOG("line length was not 1 but %d after %d/%d bytes\n",
2193 ll, origsize-size, origsize);
2199 /* interpolate odd rows */
2202 prev = cam->decompressed_frame.data;
2203 obuf = prev+linesize;
2204 next = obuf+linesize;
2205 for(i=1; i<rows-1; i+=2) {
2206 for(j=0; j<linesize; ++j) {
2207 *obuf++ = ((int)*prev++ + *next++) / 2;
2213 /* last row is odd, just copy previous row */
2214 memcpy(obuf, prev, linesize);
2217 cam->decompressed_frame.count = obuf-cam->decompressed_frame.data;
2219 return cam->decompressed_frame.count;
2222 /* InitStreamCap wrapper to select correct start line */
2223 static inline int init_stream_cap(struct cam_data *cam)
2225 return do_command(cam, CPIA_COMMAND_InitStreamCap,
2226 0, cam->params.streamStartLine, 0, 0);
2230 /* find_over_exposure
2231 * Finds a suitable value of OverExposure for use with SetFlickerCtrl
2232 * Some calculation is required because this value changes with the brightness
2233 * set with SetColourParameters
2235 * Parameters: Brightness - last brightness value set with SetColourParameters
2237 * Returns: OverExposure value to use with SetFlickerCtrl
2239 #define FLICKER_MAX_EXPOSURE 250
2240 #define FLICKER_ALLOWABLE_OVER_EXPOSURE 146
2241 #define FLICKER_BRIGHTNESS_CONSTANT 59
2242 static int find_over_exposure(int brightness)
2244 int MaxAllowableOverExposure, OverExposure;
2246 MaxAllowableOverExposure = FLICKER_MAX_EXPOSURE - brightness -
2247 FLICKER_BRIGHTNESS_CONSTANT;
2249 if (MaxAllowableOverExposure < FLICKER_ALLOWABLE_OVER_EXPOSURE) {
2250 OverExposure = MaxAllowableOverExposure;
2252 OverExposure = FLICKER_ALLOWABLE_OVER_EXPOSURE;
2255 return OverExposure;
2257 #undef FLICKER_MAX_EXPOSURE
2258 #undef FLICKER_ALLOWABLE_OVER_EXPOSURE
2259 #undef FLICKER_BRIGHTNESS_CONSTANT
2261 /* update various camera modes and settings */
2262 static void dispatch_commands(struct cam_data *cam)
2264 mutex_lock(&cam->param_lock);
2265 if (cam->cmd_queue==COMMAND_NONE) {
2266 mutex_unlock(&cam->param_lock);
2269 DEB_BYTE(cam->cmd_queue);
2270 DEB_BYTE(cam->cmd_queue>>8);
2271 if (cam->cmd_queue & COMMAND_SETFORMAT) {
2272 do_command(cam, CPIA_COMMAND_SetFormat,
2273 cam->params.format.videoSize,
2274 cam->params.format.subSample,
2275 cam->params.format.yuvOrder, 0);
2276 do_command(cam, CPIA_COMMAND_SetROI,
2277 cam->params.roi.colStart, cam->params.roi.colEnd,
2278 cam->params.roi.rowStart, cam->params.roi.rowEnd);
2279 cam->first_frame = 1;
2282 if (cam->cmd_queue & COMMAND_SETCOLOURPARAMS)
2283 do_command(cam, CPIA_COMMAND_SetColourParams,
2284 cam->params.colourParams.brightness,
2285 cam->params.colourParams.contrast,
2286 cam->params.colourParams.saturation, 0);
2288 if (cam->cmd_queue & COMMAND_SETAPCOR)
2289 do_command(cam, CPIA_COMMAND_SetApcor,
2290 cam->params.apcor.gain1,
2291 cam->params.apcor.gain2,
2292 cam->params.apcor.gain4,
2293 cam->params.apcor.gain8);
2295 if (cam->cmd_queue & COMMAND_SETVLOFFSET)
2296 do_command(cam, CPIA_COMMAND_SetVLOffset,
2297 cam->params.vlOffset.gain1,
2298 cam->params.vlOffset.gain2,
2299 cam->params.vlOffset.gain4,
2300 cam->params.vlOffset.gain8);
2302 if (cam->cmd_queue & COMMAND_SETEXPOSURE) {
2303 do_command_extended(cam, CPIA_COMMAND_SetExposure,
2304 cam->params.exposure.gainMode,
2306 cam->params.exposure.compMode,
2307 cam->params.exposure.centreWeight,
2308 cam->params.exposure.gain,
2309 cam->params.exposure.fineExp,
2310 cam->params.exposure.coarseExpLo,
2311 cam->params.exposure.coarseExpHi,
2312 cam->params.exposure.redComp,
2313 cam->params.exposure.green1Comp,
2314 cam->params.exposure.green2Comp,
2315 cam->params.exposure.blueComp);
2316 if(cam->params.exposure.expMode != 1) {
2317 do_command_extended(cam, CPIA_COMMAND_SetExposure,
2319 cam->params.exposure.expMode,
2321 cam->params.exposure.gain,
2322 cam->params.exposure.fineExp,
2323 cam->params.exposure.coarseExpLo,
2324 cam->params.exposure.coarseExpHi,
2329 if (cam->cmd_queue & COMMAND_SETCOLOURBALANCE) {
2330 if (cam->params.colourBalance.balanceMode == 1) {
2331 do_command(cam, CPIA_COMMAND_SetColourBalance,
2333 cam->params.colourBalance.redGain,
2334 cam->params.colourBalance.greenGain,
2335 cam->params.colourBalance.blueGain);
2336 do_command(cam, CPIA_COMMAND_SetColourBalance,
2339 if (cam->params.colourBalance.balanceMode == 2) {
2340 do_command(cam, CPIA_COMMAND_SetColourBalance,
2343 if (cam->params.colourBalance.balanceMode == 3) {
2344 do_command(cam, CPIA_COMMAND_SetColourBalance,
2349 if (cam->cmd_queue & COMMAND_SETCOMPRESSIONTARGET)
2350 do_command(cam, CPIA_COMMAND_SetCompressionTarget,
2351 cam->params.compressionTarget.frTargeting,
2352 cam->params.compressionTarget.targetFR,
2353 cam->params.compressionTarget.targetQ, 0);
2355 if (cam->cmd_queue & COMMAND_SETYUVTHRESH)
2356 do_command(cam, CPIA_COMMAND_SetYUVThresh,
2357 cam->params.yuvThreshold.yThreshold,
2358 cam->params.yuvThreshold.uvThreshold, 0, 0);
2360 if (cam->cmd_queue & COMMAND_SETCOMPRESSIONPARAMS)
2361 do_command_extended(cam, CPIA_COMMAND_SetCompressionParams,
2363 cam->params.compressionParams.hysteresis,
2364 cam->params.compressionParams.threshMax,
2365 cam->params.compressionParams.smallStep,
2366 cam->params.compressionParams.largeStep,
2367 cam->params.compressionParams.decimationHysteresis,
2368 cam->params.compressionParams.frDiffStepThresh,
2369 cam->params.compressionParams.qDiffStepThresh,
2370 cam->params.compressionParams.decimationThreshMod);
2372 if (cam->cmd_queue & COMMAND_SETCOMPRESSION)
2373 do_command(cam, CPIA_COMMAND_SetCompression,
2374 cam->params.compression.mode,
2375 cam->params.compression.decimation, 0, 0);
2377 if (cam->cmd_queue & COMMAND_SETSENSORFPS)
2378 do_command(cam, CPIA_COMMAND_SetSensorFPS,
2379 cam->params.sensorFps.divisor,
2380 cam->params.sensorFps.baserate, 0, 0);
2382 if (cam->cmd_queue & COMMAND_SETFLICKERCTRL)
2383 do_command(cam, CPIA_COMMAND_SetFlickerCtrl,
2384 cam->params.flickerControl.flickerMode,
2385 cam->params.flickerControl.coarseJump,
2386 abs(cam->params.flickerControl.allowableOverExposure),
2389 if (cam->cmd_queue & COMMAND_SETECPTIMING)
2390 do_command(cam, CPIA_COMMAND_SetECPTiming,
2391 cam->params.ecpTiming, 0, 0, 0);
2393 if (cam->cmd_queue & COMMAND_PAUSE)
2394 do_command(cam, CPIA_COMMAND_EndStreamCap, 0, 0, 0, 0);
2396 if (cam->cmd_queue & COMMAND_RESUME)
2397 init_stream_cap(cam);
2399 if (cam->cmd_queue & COMMAND_SETLIGHTS && cam->params.qx3.qx3_detected)
2401 int p1 = (cam->params.qx3.bottomlight == 0) << 1;
2402 int p2 = (cam->params.qx3.toplight == 0) << 3;
2403 do_command(cam, CPIA_COMMAND_WriteVCReg, 0x90, 0x8F, 0x50, 0);
2404 do_command(cam, CPIA_COMMAND_WriteMCPort, 2, 0, (p1|p2|0xE0), 0);
2407 cam->cmd_queue = COMMAND_NONE;
2408 mutex_unlock(&cam->param_lock);
2414 static void set_flicker(struct cam_params *params, volatile u32 *command_flags,
2417 /* Everything in here is from the Windows driver */
2418 #define FIRMWARE_VERSION(x,y) (params->version.firmwareVersion == (x) && \
2419 params->version.firmwareRevision == (y))
2420 /* define for compgain calculation */
2422 #define COMPGAIN(base, curexp, newexp) \
2423 (u8) ((((float) base - 128.0) * ((float) curexp / (float) newexp)) + 128.5)
2424 #define EXP_FROM_COMP(basecomp, curcomp, curexp) \
2425 (u16)((float)curexp * (float)(u8)(curcomp + 128) / (float)(u8)(basecomp - 128))
2427 /* equivalent functions without floating point math */
2428 #define COMPGAIN(base, curexp, newexp) \
2429 (u8)(128 + (((u32)(2*(base-128)*curexp + newexp)) / (2* newexp)) )
2430 #define EXP_FROM_COMP(basecomp, curcomp, curexp) \
2431 (u16)(((u32)(curexp * (u8)(curcomp + 128)) / (u8)(basecomp - 128)))
2435 int currentexp = params->exposure.coarseExpLo +
2436 params->exposure.coarseExpHi*256;
2439 int cj = params->flickerControl.coarseJump;
2440 params->flickerControl.flickerMode = 1;
2441 params->flickerControl.disabled = 0;
2442 if(params->exposure.expMode != 2)
2443 *command_flags |= COMMAND_SETEXPOSURE;
2444 params->exposure.expMode = 2;
2445 currentexp = currentexp << params->exposure.gain;
2446 params->exposure.gain = 0;
2447 /* round down current exposure to nearest value */
2448 startexp = (currentexp + ROUND_UP_EXP_FOR_FLICKER) / cj;
2451 startexp = (startexp * cj) - 1;
2452 if(FIRMWARE_VERSION(1,2))
2453 while(startexp > MAX_EXP_102)
2456 while(startexp > MAX_EXP)
2458 params->exposure.coarseExpLo = startexp & 0xff;
2459 params->exposure.coarseExpHi = startexp >> 8;
2460 if (currentexp > startexp) {
2461 if (currentexp > (2 * startexp))
2462 currentexp = 2 * startexp;
2463 params->exposure.redComp = COMPGAIN (COMP_RED, currentexp, startexp);
2464 params->exposure.green1Comp = COMPGAIN (COMP_GREEN1, currentexp, startexp);
2465 params->exposure.green2Comp = COMPGAIN (COMP_GREEN2, currentexp, startexp);
2466 params->exposure.blueComp = COMPGAIN (COMP_BLUE, currentexp, startexp);
2468 params->exposure.redComp = COMP_RED;
2469 params->exposure.green1Comp = COMP_GREEN1;
2470 params->exposure.green2Comp = COMP_GREEN2;
2471 params->exposure.blueComp = COMP_BLUE;
2473 if(FIRMWARE_VERSION(1,2))
2474 params->exposure.compMode = 0;
2476 params->exposure.compMode = 1;
2478 params->apcor.gain1 = 0x18;
2479 params->apcor.gain2 = 0x18;
2480 params->apcor.gain4 = 0x16;
2481 params->apcor.gain8 = 0x14;
2482 *command_flags |= COMMAND_SETAPCOR;
2484 params->flickerControl.flickerMode = 0;
2485 params->flickerControl.disabled = 1;
2486 /* Coarse = average of equivalent coarse for each comp channel */
2487 startexp = EXP_FROM_COMP(COMP_RED, params->exposure.redComp, currentexp);
2488 startexp += EXP_FROM_COMP(COMP_GREEN1, params->exposure.green1Comp, currentexp);
2489 startexp += EXP_FROM_COMP(COMP_GREEN2, params->exposure.green2Comp, currentexp);
2490 startexp += EXP_FROM_COMP(COMP_BLUE, params->exposure.blueComp, currentexp);
2491 startexp = startexp >> 2;
2492 while(startexp > MAX_EXP &&
2493 params->exposure.gain < params->exposure.gainMode-1) {
2494 startexp = startexp >> 1;
2495 ++params->exposure.gain;
2497 if(FIRMWARE_VERSION(1,2) && startexp > MAX_EXP_102)
2498 startexp = MAX_EXP_102;
2499 if(startexp > MAX_EXP)
2501 params->exposure.coarseExpLo = startexp&0xff;
2502 params->exposure.coarseExpHi = startexp >> 8;
2503 params->exposure.redComp = COMP_RED;
2504 params->exposure.green1Comp = COMP_GREEN1;
2505 params->exposure.green2Comp = COMP_GREEN2;
2506 params->exposure.blueComp = COMP_BLUE;
2507 params->exposure.compMode = 1;
2508 *command_flags |= COMMAND_SETEXPOSURE;
2509 params->apcor.gain1 = 0x18;
2510 params->apcor.gain2 = 0x16;
2511 params->apcor.gain4 = 0x24;
2512 params->apcor.gain8 = 0x34;
2513 *command_flags |= COMMAND_SETAPCOR;
2515 params->vlOffset.gain1 = 20;
2516 params->vlOffset.gain2 = 24;
2517 params->vlOffset.gain4 = 26;
2518 params->vlOffset.gain8 = 26;
2519 *command_flags |= COMMAND_SETVLOFFSET;
2520 #undef FIRMWARE_VERSION
2521 #undef EXP_FROM_COMP
2525 #define FIRMWARE_VERSION(x,y) (cam->params.version.firmwareVersion == (x) && \
2526 cam->params.version.firmwareRevision == (y))
2527 /* monitor the exposure and adjust the sensor frame rate if needed */
2528 static void monitor_exposure(struct cam_data *cam)
2530 u8 exp_acc, bcomp, gain, coarseL, cmd[8], data[8];
2531 int retval, light_exp, dark_exp, very_dark_exp;
2532 int old_exposure, new_exposure, framerate;
2534 /* get necessary stats and register settings from camera */
2535 /* do_command can't handle this, so do it ourselves */
2536 cmd[0] = CPIA_COMMAND_ReadVPRegs>>8;
2537 cmd[1] = CPIA_COMMAND_ReadVPRegs&0xff;
2544 retval = cam->ops->transferCmd(cam->lowlevel_data, cmd, data);
2546 LOG("ReadVPRegs(30,4,9,8) - failed, retval=%d\n",
2555 mutex_lock(&cam->param_lock);
2556 light_exp = cam->params.colourParams.brightness +
2557 TC - 50 + EXP_ACC_LIGHT;
2560 dark_exp = cam->params.colourParams.brightness +
2561 TC - 50 - EXP_ACC_DARK;
2564 very_dark_exp = dark_exp/2;
2566 old_exposure = cam->params.exposure.coarseExpHi * 256 +
2567 cam->params.exposure.coarseExpLo;
2569 if(!cam->params.flickerControl.disabled) {
2570 /* Flicker control on */
2571 int max_comp = FIRMWARE_VERSION(1,2) ? MAX_COMP : HIGH_COMP_102;
2572 bcomp += 128; /* decode */
2573 if(bcomp >= max_comp && exp_acc < dark_exp) {
2575 if(exp_acc < very_dark_exp) {
2577 if(cam->exposure_status == EXPOSURE_VERY_DARK)
2578 ++cam->exposure_count;
2580 cam->exposure_status = EXPOSURE_VERY_DARK;
2581 cam->exposure_count = 1;
2585 if(cam->exposure_status == EXPOSURE_DARK)
2586 ++cam->exposure_count;
2588 cam->exposure_status = EXPOSURE_DARK;
2589 cam->exposure_count = 1;
2592 } else if(old_exposure <= LOW_EXP || exp_acc > light_exp) {
2594 if(old_exposure <= VERY_LOW_EXP) {
2596 if(cam->exposure_status == EXPOSURE_VERY_LIGHT)
2597 ++cam->exposure_count;
2599 cam->exposure_status = EXPOSURE_VERY_LIGHT;
2600 cam->exposure_count = 1;
2604 if(cam->exposure_status == EXPOSURE_LIGHT)
2605 ++cam->exposure_count;
2607 cam->exposure_status = EXPOSURE_LIGHT;
2608 cam->exposure_count = 1;
2612 /* not dark or light */
2613 cam->exposure_status = EXPOSURE_NORMAL;
2616 /* Flicker control off */
2617 if(old_exposure >= MAX_EXP && exp_acc < dark_exp) {
2619 if(exp_acc < very_dark_exp) {
2621 if(cam->exposure_status == EXPOSURE_VERY_DARK)
2622 ++cam->exposure_count;
2624 cam->exposure_status = EXPOSURE_VERY_DARK;
2625 cam->exposure_count = 1;
2629 if(cam->exposure_status == EXPOSURE_DARK)
2630 ++cam->exposure_count;
2632 cam->exposure_status = EXPOSURE_DARK;
2633 cam->exposure_count = 1;
2636 } else if(old_exposure <= LOW_EXP || exp_acc > light_exp) {
2638 if(old_exposure <= VERY_LOW_EXP) {
2640 if(cam->exposure_status == EXPOSURE_VERY_LIGHT)
2641 ++cam->exposure_count;
2643 cam->exposure_status = EXPOSURE_VERY_LIGHT;
2644 cam->exposure_count = 1;
2648 if(cam->exposure_status == EXPOSURE_LIGHT)
2649 ++cam->exposure_count;
2651 cam->exposure_status = EXPOSURE_LIGHT;
2652 cam->exposure_count = 1;
2656 /* not dark or light */
2657 cam->exposure_status = EXPOSURE_NORMAL;
2661 framerate = cam->fps;
2662 if(framerate > 30 || framerate < 1)
2665 if(!cam->params.flickerControl.disabled) {
2666 /* Flicker control on */
2667 if((cam->exposure_status == EXPOSURE_VERY_DARK ||
2668 cam->exposure_status == EXPOSURE_DARK) &&
2669 cam->exposure_count >= DARK_TIME*framerate &&
2670 cam->params.sensorFps.divisor < 3) {
2672 /* dark for too long */
2673 ++cam->params.sensorFps.divisor;
2674 cam->cmd_queue |= COMMAND_SETSENSORFPS;
2676 cam->params.flickerControl.coarseJump =
2677 flicker_jumps[cam->mainsFreq]
2678 [cam->params.sensorFps.baserate]
2679 [cam->params.sensorFps.divisor];
2680 cam->cmd_queue |= COMMAND_SETFLICKERCTRL;
2682 new_exposure = cam->params.flickerControl.coarseJump-1;
2683 while(new_exposure < old_exposure/2)
2684 new_exposure += cam->params.flickerControl.coarseJump;
2685 cam->params.exposure.coarseExpLo = new_exposure & 0xff;
2686 cam->params.exposure.coarseExpHi = new_exposure >> 8;
2687 cam->cmd_queue |= COMMAND_SETEXPOSURE;
2688 cam->exposure_status = EXPOSURE_NORMAL;
2689 LOG("Automatically decreasing sensor_fps\n");
2691 } else if((cam->exposure_status == EXPOSURE_VERY_LIGHT ||
2692 cam->exposure_status == EXPOSURE_LIGHT) &&
2693 cam->exposure_count >= LIGHT_TIME*framerate &&
2694 cam->params.sensorFps.divisor > 0) {
2696 /* light for too long */
2697 int max_exp = FIRMWARE_VERSION(1,2) ? MAX_EXP_102 : MAX_EXP ;
2699 --cam->params.sensorFps.divisor;
2700 cam->cmd_queue |= COMMAND_SETSENSORFPS;
2702 cam->params.flickerControl.coarseJump =
2703 flicker_jumps[cam->mainsFreq]
2704 [cam->params.sensorFps.baserate]
2705 [cam->params.sensorFps.divisor];
2706 cam->cmd_queue |= COMMAND_SETFLICKERCTRL;
2708 new_exposure = cam->params.flickerControl.coarseJump-1;
2709 while(new_exposure < 2*old_exposure &&
2711 cam->params.flickerControl.coarseJump < max_exp)
2712 new_exposure += cam->params.flickerControl.coarseJump;
2713 cam->params.exposure.coarseExpLo = new_exposure & 0xff;
2714 cam->params.exposure.coarseExpHi = new_exposure >> 8;
2715 cam->cmd_queue |= COMMAND_SETEXPOSURE;
2716 cam->exposure_status = EXPOSURE_NORMAL;
2717 LOG("Automatically increasing sensor_fps\n");
2720 /* Flicker control off */
2721 if((cam->exposure_status == EXPOSURE_VERY_DARK ||
2722 cam->exposure_status == EXPOSURE_DARK) &&
2723 cam->exposure_count >= DARK_TIME*framerate &&
2724 cam->params.sensorFps.divisor < 3) {
2726 /* dark for too long */
2727 ++cam->params.sensorFps.divisor;
2728 cam->cmd_queue |= COMMAND_SETSENSORFPS;
2730 if(cam->params.exposure.gain > 0) {
2731 --cam->params.exposure.gain;
2732 cam->cmd_queue |= COMMAND_SETEXPOSURE;
2734 cam->exposure_status = EXPOSURE_NORMAL;
2735 LOG("Automatically decreasing sensor_fps\n");
2737 } else if((cam->exposure_status == EXPOSURE_VERY_LIGHT ||
2738 cam->exposure_status == EXPOSURE_LIGHT) &&
2739 cam->exposure_count >= LIGHT_TIME*framerate &&
2740 cam->params.sensorFps.divisor > 0) {
2742 /* light for too long */
2743 --cam->params.sensorFps.divisor;
2744 cam->cmd_queue |= COMMAND_SETSENSORFPS;
2746 if(cam->params.exposure.gain <
2747 cam->params.exposure.gainMode-1) {
2748 ++cam->params.exposure.gain;
2749 cam->cmd_queue |= COMMAND_SETEXPOSURE;
2751 cam->exposure_status = EXPOSURE_NORMAL;
2752 LOG("Automatically increasing sensor_fps\n");
2755 mutex_unlock(&cam->param_lock);
2758 /*-----------------------------------------------------------------*/
2759 /* if flicker is switched off, this function switches it back on.It checks,
2760 however, that conditions are suitable before restarting it.
2761 This should only be called for firmware version 1.2.
2763 It also adjust the colour balance when an exposure step is detected - as
2764 long as flicker is running
2766 static void restart_flicker(struct cam_data *cam)
2768 int cam_exposure, old_exp;
2769 if(!FIRMWARE_VERSION(1,2))
2771 mutex_lock(&cam->param_lock);
2772 if(cam->params.flickerControl.flickerMode == 0 ||
2773 cam->raw_image[39] == 0) {
2774 mutex_unlock(&cam->param_lock);
2777 cam_exposure = cam->raw_image[39]*2;
2778 old_exp = cam->params.exposure.coarseExpLo +
2779 cam->params.exposure.coarseExpHi*256;
2781 see how far away camera exposure is from a valid
2782 flicker exposure value
2784 cam_exposure %= cam->params.flickerControl.coarseJump;
2785 if(!cam->params.flickerControl.disabled &&
2786 cam_exposure <= cam->params.flickerControl.coarseJump - 3) {
2787 /* Flicker control auto-disabled */
2788 cam->params.flickerControl.disabled = 1;
2791 if(cam->params.flickerControl.disabled &&
2792 cam->params.flickerControl.flickerMode &&
2793 old_exp > cam->params.flickerControl.coarseJump +
2794 ROUND_UP_EXP_FOR_FLICKER) {
2795 /* exposure is now high enough to switch
2796 flicker control back on */
2797 set_flicker(&cam->params, &cam->cmd_queue, 1);
2798 if((cam->cmd_queue & COMMAND_SETEXPOSURE) &&
2799 cam->params.exposure.expMode == 2)
2800 cam->exposure_status = EXPOSURE_NORMAL;
2803 mutex_unlock(&cam->param_lock);
2805 #undef FIRMWARE_VERSION
2807 static int clear_stall(struct cam_data *cam)
2809 /* FIXME: Does this actually work? */
2810 LOG("Clearing stall\n");
2812 cam->ops->streamRead(cam->lowlevel_data, cam->raw_image, 0);
2813 do_command(cam, CPIA_COMMAND_GetCameraStatus,0,0,0,0);
2814 return cam->params.status.streamState != STREAM_PAUSED;
2817 /* kernel thread function to read image from camera */
2818 static int fetch_frame(void *data)
2820 int image_size, retry;
2821 struct cam_data *cam = (struct cam_data *)data;
2822 unsigned long oldjif, rate, diff;
2824 /* Allow up to two bad images in a row to be read and
2825 * ignored before an error is reported */
2826 for (retry = 0; retry < 3; ++retry) {
2828 DBG("retry=%d\n", retry);
2833 /* load first frame always uncompressed */
2834 if (cam->first_frame &&
2835 cam->params.compression.mode != CPIA_COMPRESSION_NONE) {
2836 do_command(cam, CPIA_COMMAND_SetCompression,
2837 CPIA_COMPRESSION_NONE,
2838 NO_DECIMATION, 0, 0);
2839 /* Trial & error - Discarding a frame prevents the
2840 first frame from having an error in the data. */
2841 do_command(cam, CPIA_COMMAND_DiscardFrame, 0, 0, 0, 0);
2844 /* init camera upload */
2845 if (do_command(cam, CPIA_COMMAND_GrabFrame, 0,
2846 cam->params.streamStartLine, 0, 0))
2849 if (cam->ops->wait_for_stream_ready) {
2850 /* loop until image ready */
2852 do_command(cam, CPIA_COMMAND_GetCameraStatus,0,0,0,0);
2853 while (cam->params.status.streamState != STREAM_READY) {
2854 if(++count > READY_TIMEOUT)
2856 if(cam->params.status.streamState ==
2859 if(!clear_stall(cam))
2865 /* sleep for 10 ms, hopefully ;) */
2866 msleep_interruptible(10);
2867 if (signal_pending(current))
2870 do_command(cam, CPIA_COMMAND_GetCameraStatus,
2873 if(cam->params.status.streamState != STREAM_READY) {
2880 /* grab image from camera */
2882 image_size = cam->ops->streamRead(cam->lowlevel_data,
2884 if (image_size <= 0) {
2885 DBG("streamRead failed: %d\n", image_size);
2889 rate = image_size * HZ / 1024;
2890 diff = jiffies-oldjif;
2891 cam->transfer_rate = diff==0 ? rate : rate/diff;
2892 /* diff==0 ? unlikely but possible */
2894 /* Switch flicker control back on if it got turned off */
2895 restart_flicker(cam);
2897 /* If AEC is enabled, monitor the exposure and
2898 adjust the sensor frame rate if needed */
2899 if(cam->params.exposure.expMode == 2)
2900 monitor_exposure(cam);
2902 /* camera idle now so dispatch queued commands */
2903 dispatch_commands(cam);
2905 /* Update our knowledge of the camera state */
2906 do_command(cam, CPIA_COMMAND_GetColourBalance, 0, 0, 0, 0);
2907 do_command(cam, CPIA_COMMAND_GetExposure, 0, 0, 0, 0);
2908 do_command(cam, CPIA_COMMAND_ReadMCPorts, 0, 0, 0, 0);
2910 /* decompress and convert image to by copying it from
2911 * raw_image to decompressed_frame
2916 cam->image_size = parse_picture(cam, image_size);
2917 if (cam->image_size <= 0) {
2918 DBG("parse_picture failed %d\n", cam->image_size);
2919 if(cam->params.compression.mode !=
2920 CPIA_COMPRESSION_NONE) {
2921 /* Compression may not work right if we
2922 had a bad frame, get the next one
2924 cam->first_frame = 1;
2925 do_command(cam, CPIA_COMMAND_SetGrabMode,
2926 CPIA_GRAB_SINGLE, 0, 0, 0);
2927 /* FIXME: Trial & error - need up to 70ms for
2928 the grab mode change to complete ? */
2929 msleep_interruptible(70);
2930 if (signal_pending(current))
2938 /* FIXME: this only works for double buffering */
2939 if (cam->frame[cam->curframe].state == FRAME_READY) {
2940 memcpy(cam->frame[cam->curframe].data,
2941 cam->decompressed_frame.data,
2942 cam->decompressed_frame.count);
2943 cam->frame[cam->curframe].state = FRAME_DONE;
2945 cam->decompressed_frame.state = FRAME_DONE;
2947 if (cam->first_frame) {
2948 cam->first_frame = 0;
2949 do_command(cam, CPIA_COMMAND_SetCompression,
2950 cam->params.compression.mode,
2951 cam->params.compression.decimation, 0, 0);
2953 /* Switch from single-grab to continuous grab */
2954 do_command(cam, CPIA_COMMAND_SetGrabMode,
2955 CPIA_GRAB_CONTINUOUS, 0, 0, 0);
2962 static int capture_frame(struct cam_data *cam, struct video_mmap *vm)
2964 if (!cam->frame_buf) {
2965 /* we do lazy allocation */
2967 if ((err = allocate_frame_buf(cam)))
2971 cam->curframe = vm->frame;
2972 cam->frame[cam->curframe].state = FRAME_READY;
2973 return fetch_frame(cam);
2976 static int goto_high_power(struct cam_data *cam)
2978 if (do_command(cam, CPIA_COMMAND_GotoHiPower, 0, 0, 0, 0))
2980 msleep_interruptible(40); /* windows driver does it too */
2981 if(signal_pending(current))
2983 if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0))
2985 if (cam->params.status.systemState == HI_POWER_STATE) {
2986 DBG("camera now in HIGH power state\n");
2993 static int goto_low_power(struct cam_data *cam)
2995 if (do_command(cam, CPIA_COMMAND_GotoLoPower, 0, 0, 0, 0))
2997 if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0))
2999 if (cam->params.status.systemState == LO_POWER_STATE) {
3000 DBG("camera now in LOW power state\n");
3007 static void save_camera_state(struct cam_data *cam)
3009 if(!(cam->cmd_queue & COMMAND_SETCOLOURBALANCE))
3010 do_command(cam, CPIA_COMMAND_GetColourBalance, 0, 0, 0, 0);
3011 if(!(cam->cmd_queue & COMMAND_SETEXPOSURE))
3012 do_command(cam, CPIA_COMMAND_GetExposure, 0, 0, 0, 0);
3014 DBG("%d/%d/%d/%d/%d/%d/%d/%d\n",
3015 cam->params.exposure.gain,
3016 cam->params.exposure.fineExp,
3017 cam->params.exposure.coarseExpLo,
3018 cam->params.exposure.coarseExpHi,
3019 cam->params.exposure.redComp,
3020 cam->params.exposure.green1Comp,
3021 cam->params.exposure.green2Comp,
3022 cam->params.exposure.blueComp);
3024 cam->params.colourBalance.redGain,
3025 cam->params.colourBalance.greenGain,
3026 cam->params.colourBalance.blueGain);
3029 static int set_camera_state(struct cam_data *cam)
3031 cam->cmd_queue = COMMAND_SETCOMPRESSION |
3032 COMMAND_SETCOMPRESSIONTARGET |
3033 COMMAND_SETCOLOURPARAMS |
3035 COMMAND_SETYUVTHRESH |
3036 COMMAND_SETECPTIMING |
3037 COMMAND_SETCOMPRESSIONPARAMS |
3038 COMMAND_SETEXPOSURE |
3039 COMMAND_SETCOLOURBALANCE |
3040 COMMAND_SETSENSORFPS |
3042 COMMAND_SETFLICKERCTRL |
3043 COMMAND_SETVLOFFSET;
3045 do_command(cam, CPIA_COMMAND_SetGrabMode, CPIA_GRAB_SINGLE,0,0,0);
3046 dispatch_commands(cam);
3048 /* Wait 6 frames for the sensor to get all settings and
3049 AEC/ACB to settle */
3050 msleep_interruptible(6*(cam->params.sensorFps.baserate ? 33 : 40) *
3051 (1 << cam->params.sensorFps.divisor) + 10);
3053 if(signal_pending(current))
3056 save_camera_state(cam);
3061 static void get_version_information(struct cam_data *cam)
3063 /* GetCPIAVersion */
3064 do_command(cam, CPIA_COMMAND_GetCPIAVersion, 0, 0, 0, 0);
3067 do_command(cam, CPIA_COMMAND_GetPnPID, 0, 0, 0, 0);
3070 /* initialize camera */
3071 static int reset_camera(struct cam_data *cam)
3074 /* Start the camera in low power mode */
3075 if (goto_low_power(cam)) {
3076 if (cam->params.status.systemState != WARM_BOOT_STATE)
3079 /* FIXME: this is just dirty trial and error */
3080 err = goto_high_power(cam);
3083 do_command(cam, CPIA_COMMAND_DiscardFrame, 0, 0, 0, 0);
3084 if (goto_low_power(cam))
3088 /* procedure described in developer's guide p3-28 */
3090 /* Check the firmware version. */
3091 cam->params.version.firmwareVersion = 0;
3092 get_version_information(cam);
3093 if (cam->params.version.firmwareVersion != 1)
3096 /* A bug in firmware 1-02 limits gainMode to 2 */
3097 if(cam->params.version.firmwareRevision <= 2 &&
3098 cam->params.exposure.gainMode > 2) {
3099 cam->params.exposure.gainMode = 2;
3102 /* set QX3 detected flag */
3103 cam->params.qx3.qx3_detected = (cam->params.pnpID.vendor == 0x0813 &&
3104 cam->params.pnpID.product == 0x0001);
3106 /* The fatal error checking should be done after
3107 * the camera powers up (developer's guide p 3-38) */
3109 /* Set streamState before transition to high power to avoid bug
3110 * in firmware 1-02 */
3111 do_command(cam, CPIA_COMMAND_ModifyCameraStatus, STREAMSTATE, 0,
3112 STREAM_NOT_READY, 0);
3115 err = goto_high_power(cam);
3119 /* Check the camera status */
3120 if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0))
3123 if (cam->params.status.fatalError) {
3124 DBG("fatal_error: %#04x\n",
3125 cam->params.status.fatalError);
3126 DBG("vp_status: %#04x\n",
3127 cam->params.status.vpStatus);
3128 if (cam->params.status.fatalError & ~(COM_FLAG|CPIA_FLAG)) {
3129 /* Fatal error in camera */
3131 } else if (cam->params.status.fatalError & (COM_FLAG|CPIA_FLAG)) {
3132 /* Firmware 1-02 may do this for parallel port cameras,
3133 * just clear the flags (developer's guide p 3-38) */
3134 do_command(cam, CPIA_COMMAND_ModifyCameraStatus,
3135 FATALERROR, ~(COM_FLAG|CPIA_FLAG), 0, 0);
3139 /* Check the camera status again */
3140 if (cam->params.status.fatalError) {
3141 if (cam->params.status.fatalError)
3145 /* VPVersion can't be retrieved before the camera is in HiPower,
3146 * so get it here instead of in get_version_information. */
3147 do_command(cam, CPIA_COMMAND_GetVPVersion, 0, 0, 0, 0);
3149 /* set camera to a known state */
3150 return set_camera_state(cam);
3153 static void put_cam(struct cpia_camera_ops* ops)
3155 module_put(ops->owner);
3158 /* ------------------------- V4L interface --------------------- */
3159 static int cpia_open(struct inode *inode, struct file *file)
3161 struct video_device *dev = video_devdata(file);
3162 struct cam_data *cam = dev->priv;
3166 DBG("Internal error, cam_data not found!\n");
3170 if (cam->open_count > 0) {
3171 DBG("Camera already open\n");
3175 if (!try_module_get(cam->ops->owner))
3178 mutex_lock(&cam->busy_lock);
3180 if (!cam->raw_image) {
3181 cam->raw_image = rvmalloc(CPIA_MAX_IMAGE_SIZE);
3182 if (!cam->raw_image)
3186 if (!cam->decompressed_frame.data) {
3187 cam->decompressed_frame.data = rvmalloc(CPIA_MAX_FRAME_SIZE);
3188 if (!cam->decompressed_frame.data)
3194 if (cam->ops->open(cam->lowlevel_data))
3197 /* reset the camera */
3198 if ((err = reset_camera(cam)) != 0) {
3199 cam->ops->close(cam->lowlevel_data);
3204 if(signal_pending(current))
3207 /* Set ownership of /proc/cpia/videoX to current user */
3209 cam->proc_entry->uid = current->uid;
3211 /* set mark for loading first frame uncompressed */
3212 cam->first_frame = 1;
3214 /* init it to something */
3215 cam->mmap_kludge = 0;
3218 file->private_data = dev;
3219 mutex_unlock(&cam->busy_lock);
3223 if (cam->decompressed_frame.data) {
3224 rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE);
3225 cam->decompressed_frame.data = NULL;
3227 if (cam->raw_image) {
3228 rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
3229 cam->raw_image = NULL;
3231 mutex_unlock(&cam->busy_lock);
3236 static int cpia_close(struct inode *inode, struct file *file)
3238 struct video_device *dev = file->private_data;
3239 struct cam_data *cam = dev->priv;
3242 /* Return ownership of /proc/cpia/videoX to root */
3244 cam->proc_entry->uid = 0;
3246 /* save camera state for later open (developers guide ch 3.5.3) */
3247 save_camera_state(cam);
3250 goto_low_power(cam);
3252 /* Update the camera status */
3253 do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0);
3255 /* cleanup internal state stuff */
3256 free_frames(cam->frame);
3259 cam->ops->close(cam->lowlevel_data);
3264 if (--cam->open_count == 0) {
3265 /* clean up capture-buffers */
3266 if (cam->raw_image) {
3267 rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
3268 cam->raw_image = NULL;
3271 if (cam->decompressed_frame.data) {
3272 rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE);
3273 cam->decompressed_frame.data = NULL;
3277 free_frame_buf(cam);
3282 file->private_data = NULL;
3287 static ssize_t cpia_read(struct file *file, char __user *buf,
3288 size_t count, loff_t *ppos)
3290 struct video_device *dev = file->private_data;
3291 struct cam_data *cam = dev->priv;
3294 /* make this _really_ smp and multithread-safe */
3295 if (mutex_lock_interruptible(&cam->busy_lock))
3300 mutex_unlock(&cam->busy_lock);
3306 mutex_unlock(&cam->busy_lock);
3312 mutex_unlock(&cam->busy_lock);
3317 cam->decompressed_frame.state = FRAME_READY;
3319 if((err = fetch_frame(cam)) != 0) {
3320 DBG("ERROR from fetch_frame: %d\n", err);
3321 mutex_unlock(&cam->busy_lock);
3324 cam->decompressed_frame.state = FRAME_UNUSED;
3326 /* copy data to user space */
3327 if (cam->decompressed_frame.count > count) {
3328 DBG("count wrong: %d, %lu\n", cam->decompressed_frame.count,
3329 (unsigned long) count);
3330 mutex_unlock(&cam->busy_lock);
3333 if (copy_to_user(buf, cam->decompressed_frame.data,
3334 cam->decompressed_frame.count)) {
3335 DBG("copy_to_user failed\n");
3336 mutex_unlock(&cam->busy_lock);
3340 mutex_unlock(&cam->busy_lock);
3341 return cam->decompressed_frame.count;
3344 static int cpia_do_ioctl(struct inode *inode, struct file *file,
3345 unsigned int ioctlnr, void *arg)
3347 struct video_device *dev = file->private_data;
3348 struct cam_data *cam = dev->priv;
3351 if (!cam || !cam->ops)
3354 /* make this _really_ smp-safe */
3355 if (mutex_lock_interruptible(&cam->busy_lock))
3358 //DBG("cpia_ioctl: %u\n", ioctlnr);
3361 /* query capabilities */
3364 struct video_capability *b = arg;
3366 DBG("VIDIOCGCAP\n");
3367 strcpy(b->name, "CPiA Camera");
3368 b->type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE;
3371 b->maxwidth = 352; /* VIDEOSIZE_CIF */
3373 b->minwidth = 48; /* VIDEOSIZE_48_48 */
3378 /* get/set video source - we are a camera and nothing else */
3381 struct video_channel *v = arg;
3383 DBG("VIDIOCGCHAN\n");
3384 if (v->channel != 0) {
3390 strcpy(v->name, "Camera");
3393 v->type = VIDEO_TYPE_CAMERA;
3400 struct video_channel *v = arg;
3402 DBG("VIDIOCSCHAN\n");
3403 if (v->channel != 0)
3408 /* image properties */
3411 struct video_picture *pic = arg;
3412 DBG("VIDIOCGPICT\n");
3419 struct video_picture *vp = arg;
3421 DBG("VIDIOCSPICT\n");
3423 /* check validity */
3424 DBG("palette: %d\n", vp->palette);
3425 DBG("depth: %d\n", vp->depth);
3426 if (!valid_mode(vp->palette, vp->depth)) {
3431 mutex_lock(&cam->param_lock);
3432 /* brightness, colour, contrast need no check 0-65535 */
3434 /* update cam->params.colourParams */
3435 cam->params.colourParams.brightness = vp->brightness*100/65535;
3436 cam->params.colourParams.contrast = vp->contrast*100/65535;
3437 cam->params.colourParams.saturation = vp->colour*100/65535;
3438 /* contrast is in steps of 8, so round */
3439 cam->params.colourParams.contrast =
3440 ((cam->params.colourParams.contrast + 3) / 8) * 8;
3441 if (cam->params.version.firmwareVersion == 1 &&
3442 cam->params.version.firmwareRevision == 2 &&
3443 cam->params.colourParams.contrast > 80) {
3444 /* 1-02 firmware limits contrast to 80 */
3445 cam->params.colourParams.contrast = 80;
3448 /* Adjust flicker control if necessary */
3449 if(cam->params.flickerControl.allowableOverExposure < 0)
3450 cam->params.flickerControl.allowableOverExposure =
3451 -find_over_exposure(cam->params.colourParams.brightness);
3452 if(cam->params.flickerControl.flickerMode != 0)
3453 cam->cmd_queue |= COMMAND_SETFLICKERCTRL;
3456 /* queue command to update camera */
3457 cam->cmd_queue |= COMMAND_SETCOLOURPARAMS;
3458 mutex_unlock(&cam->param_lock);
3459 DBG("VIDIOCSPICT: %d / %d // %d / %d / %d / %d\n",
3460 vp->depth, vp->palette, vp->brightness, vp->hue, vp->colour,
3465 /* get/set capture window */
3468 struct video_window *vw = arg;
3469 DBG("VIDIOCGWIN\n");
3477 /* copy_from_user, check validity, copy to internal structure */
3478 struct video_window *vw = arg;
3479 DBG("VIDIOCSWIN\n");
3481 if (vw->clipcount != 0) { /* clipping not supported */
3485 if (vw->clips != NULL) { /* clipping not supported */
3490 /* we set the video window to something smaller or equal to what
3491 * is requested by the user???
3493 mutex_lock(&cam->param_lock);
3494 if (vw->width != cam->vw.width || vw->height != cam->vw.height) {
3495 int video_size = match_videosize(vw->width, vw->height);
3497 if (video_size < 0) {
3499 mutex_unlock(&cam->param_lock);
3502 cam->video_size = video_size;
3504 /* video size is changing, reset the subcapture area */
3505 memset(&cam->vc, 0, sizeof(cam->vc));
3508 DBG("%d / %d\n", cam->vw.width, cam->vw.height);
3509 cam->cmd_queue |= COMMAND_SETFORMAT;
3512 mutex_unlock(&cam->param_lock);
3514 /* setformat ignored by camera during streaming,
3515 * so stop/dispatch/start */
3516 if (cam->cmd_queue & COMMAND_SETFORMAT) {
3518 dispatch_commands(cam);
3520 DBG("%d/%d:%d\n", cam->video_size,
3521 cam->vw.width, cam->vw.height);
3525 /* mmap interface */
3528 struct video_mbuf *vm = arg;
3531 DBG("VIDIOCGMBUF\n");
3532 memset(vm, 0, sizeof(*vm));
3533 vm->size = CPIA_MAX_FRAME_SIZE*FRAME_NUM;
3534 vm->frames = FRAME_NUM;
3535 for (i = 0; i < FRAME_NUM; i++)
3536 vm->offsets[i] = CPIA_MAX_FRAME_SIZE * i;
3540 case VIDIOCMCAPTURE:
3542 struct video_mmap *vm = arg;
3545 DBG("VIDIOCMCAPTURE: %d / %d / %dx%d\n", vm->format, vm->frame,
3546 vm->width, vm->height);
3547 if (vm->frame<0||vm->frame>=FRAME_NUM) {
3552 /* set video format */
3553 cam->vp.palette = vm->format;
3554 switch(vm->format) {
3555 case VIDEO_PALETTE_GREY:
3558 case VIDEO_PALETTE_RGB555:
3559 case VIDEO_PALETTE_RGB565:
3560 case VIDEO_PALETTE_YUV422:
3561 case VIDEO_PALETTE_YUYV:
3562 case VIDEO_PALETTE_UYVY:
3565 case VIDEO_PALETTE_RGB24:
3568 case VIDEO_PALETTE_RGB32:
3578 /* set video size */
3579 video_size = match_videosize(vm->width, vm->height);
3580 if (video_size < 0) {
3584 if (video_size != cam->video_size) {
3585 cam->video_size = video_size;
3587 /* video size is changing, reset the subcapture area */
3588 memset(&cam->vc, 0, sizeof(cam->vc));
3591 cam->cmd_queue |= COMMAND_SETFORMAT;
3592 dispatch_commands(cam);
3594 /* according to v4l-spec we must start streaming here */
3595 cam->mmap_kludge = 1;
3596 retval = capture_frame(cam, vm);
3605 //DBG("VIDIOCSYNC: %d\n", *frame);
3607 if (*frame<0 || *frame >= FRAME_NUM) {
3612 switch (cam->frame[*frame].state) {
3615 case FRAME_GRABBING:
3616 DBG("sync to unused frame %d\n", *frame);
3621 cam->frame[*frame].state = FRAME_UNUSED;
3622 //DBG("VIDIOCSYNC: %d synced\n", *frame);
3625 if (retval == -EINTR) {
3626 /* FIXME - xawtv does not handle this nice */
3632 case VIDIOCGCAPTURE:
3634 struct video_capture *vc = arg;
3636 DBG("VIDIOCGCAPTURE\n");
3643 case VIDIOCSCAPTURE:
3645 struct video_capture *vc = arg;
3647 DBG("VIDIOCSCAPTURE\n");
3649 if (vc->decimation != 0) { /* How should this be used? */
3653 if (vc->flags != 0) { /* Even/odd grab not supported */
3658 /* Clip to the resolution we can set for the ROI
3659 (every 8 columns and 4 rows) */
3660 vc->x = vc->x & ~(__u32)7;
3661 vc->y = vc->y & ~(__u32)3;
3662 vc->width = vc->width & ~(__u32)7;
3663 vc->height = vc->height & ~(__u32)3;
3665 if(vc->width == 0 || vc->height == 0 ||
3666 vc->x + vc->width > cam->vw.width ||
3667 vc->y + vc->height > cam->vw.height) {
3672 DBG("%d,%d/%dx%d\n", vc->x,vc->y,vc->width, vc->height);
3674 mutex_lock(&cam->param_lock);
3678 cam->vc.width = vc->width;
3679 cam->vc.height = vc->height;
3682 cam->cmd_queue |= COMMAND_SETFORMAT;
3684 mutex_unlock(&cam->param_lock);
3686 /* setformat ignored by camera during streaming,
3687 * so stop/dispatch/start */
3688 dispatch_commands(cam);
3694 struct video_unit *vu = arg;
3696 DBG("VIDIOCGUNIT\n");
3698 vu->video = cam->vdev.minor;
3699 vu->vbi = VIDEO_NO_UNIT;
3700 vu->radio = VIDEO_NO_UNIT;
3701 vu->audio = VIDEO_NO_UNIT;
3702 vu->teletext = VIDEO_NO_UNIT;
3708 /* pointless to implement overlay with this camera */
3713 /* tuner interface - we have none */
3718 /* audio interface - we have none */
3724 retval = -ENOIOCTLCMD;
3728 mutex_unlock(&cam->busy_lock);
3732 static int cpia_ioctl(struct inode *inode, struct file *file,
3733 unsigned int cmd, unsigned long arg)
3735 return video_usercopy(inode, file, cmd, arg, cpia_do_ioctl);
3740 static int cpia_mmap(struct file *file, struct vm_area_struct *vma)
3742 struct video_device *dev = file->private_data;
3743 unsigned long start = vma->vm_start;
3744 unsigned long size = vma->vm_end - vma->vm_start;
3745 unsigned long page, pos;
3746 struct cam_data *cam = dev->priv;
3749 if (!cam || !cam->ops)
3752 DBG("cpia_mmap: %ld\n", size);
3754 if (size > FRAME_NUM*CPIA_MAX_FRAME_SIZE)
3757 if (!cam || !cam->ops)
3760 /* make this _really_ smp-safe */
3761 if (mutex_lock_interruptible(&cam->busy_lock))
3764 if (!cam->frame_buf) { /* we do lazy allocation */
3765 if ((retval = allocate_frame_buf(cam))) {
3766 mutex_unlock(&cam->busy_lock);
3771 pos = (unsigned long)(cam->frame_buf);
3773 page = vmalloc_to_pfn((void *)pos);
3774 if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
3775 mutex_unlock(&cam->busy_lock);
3780 if (size > PAGE_SIZE)
3786 DBG("cpia_mmap: %ld\n", size);
3787 mutex_unlock(&cam->busy_lock);
3792 static const struct file_operations cpia_fops = {
3793 .owner = THIS_MODULE,
3795 .release = cpia_close,
3798 .ioctl = cpia_ioctl,
3799 .compat_ioctl = v4l_compat_ioctl32,
3800 .llseek = no_llseek,
3803 static struct video_device cpia_template = {
3804 .owner = THIS_MODULE,
3805 .name = "CPiA Camera",
3806 .type = VID_TYPE_CAPTURE,
3807 .hardware = VID_HARDWARE_CPIA,
3811 /* initialise cam_data structure */
3812 static void reset_camera_struct(struct cam_data *cam)
3814 /* The following parameter values are the defaults from
3815 * "Software Developer's Guide for CPiA Cameras". Any changes
3816 * to the defaults are noted in comments. */
3817 cam->params.colourParams.brightness = 50;
3818 cam->params.colourParams.contrast = 48;
3819 cam->params.colourParams.saturation = 50;
3820 cam->params.exposure.gainMode = 4;
3821 cam->params.exposure.expMode = 2; /* AEC */
3822 cam->params.exposure.compMode = 1;
3823 cam->params.exposure.centreWeight = 1;
3824 cam->params.exposure.gain = 0;
3825 cam->params.exposure.fineExp = 0;
3826 cam->params.exposure.coarseExpLo = 185;
3827 cam->params.exposure.coarseExpHi = 0;
3828 cam->params.exposure.redComp = COMP_RED;
3829 cam->params.exposure.green1Comp = COMP_GREEN1;
3830 cam->params.exposure.green2Comp = COMP_GREEN2;
3831 cam->params.exposure.blueComp = COMP_BLUE;
3832 cam->params.colourBalance.balanceMode = 2; /* ACB */
3833 cam->params.colourBalance.redGain = 32;
3834 cam->params.colourBalance.greenGain = 6;
3835 cam->params.colourBalance.blueGain = 92;
3836 cam->params.apcor.gain1 = 0x18;
3837 cam->params.apcor.gain2 = 0x16;
3838 cam->params.apcor.gain4 = 0x24;
3839 cam->params.apcor.gain8 = 0x34;
3840 cam->params.flickerControl.flickerMode = 0;
3841 cam->params.flickerControl.disabled = 1;
3843 cam->params.flickerControl.coarseJump =
3844 flicker_jumps[cam->mainsFreq]
3845 [cam->params.sensorFps.baserate]
3846 [cam->params.sensorFps.divisor];
3847 cam->params.flickerControl.allowableOverExposure =
3848 -find_over_exposure(cam->params.colourParams.brightness);
3849 cam->params.vlOffset.gain1 = 20;
3850 cam->params.vlOffset.gain2 = 24;
3851 cam->params.vlOffset.gain4 = 26;
3852 cam->params.vlOffset.gain8 = 26;
3853 cam->params.compressionParams.hysteresis = 3;
3854 cam->params.compressionParams.threshMax = 11;
3855 cam->params.compressionParams.smallStep = 1;
3856 cam->params.compressionParams.largeStep = 3;
3857 cam->params.compressionParams.decimationHysteresis = 2;
3858 cam->params.compressionParams.frDiffStepThresh = 5;
3859 cam->params.compressionParams.qDiffStepThresh = 3;
3860 cam->params.compressionParams.decimationThreshMod = 2;
3861 /* End of default values from Software Developer's Guide */
3863 cam->transfer_rate = 0;
3864 cam->exposure_status = EXPOSURE_NORMAL;
3866 /* Set Sensor FPS to 15fps. This seems better than 30fps
3867 * for indoor lighting. */
3868 cam->params.sensorFps.divisor = 1;
3869 cam->params.sensorFps.baserate = 1;
3871 cam->params.yuvThreshold.yThreshold = 6; /* From windows driver */
3872 cam->params.yuvThreshold.uvThreshold = 6; /* From windows driver */
3874 cam->params.format.subSample = SUBSAMPLE_422;
3875 cam->params.format.yuvOrder = YUVORDER_YUYV;
3877 cam->params.compression.mode = CPIA_COMPRESSION_AUTO;
3878 cam->params.compressionTarget.frTargeting =
3879 CPIA_COMPRESSION_TARGET_QUALITY;
3880 cam->params.compressionTarget.targetFR = 15; /* From windows driver */
3881 cam->params.compressionTarget.targetQ = 5; /* From windows driver */
3883 cam->params.qx3.qx3_detected = 0;
3884 cam->params.qx3.toplight = 0;
3885 cam->params.qx3.bottomlight = 0;
3886 cam->params.qx3.button = 0;
3887 cam->params.qx3.cradled = 0;
3889 cam->video_size = VIDEOSIZE_CIF;
3891 cam->vp.colour = 32768; /* 50% */
3892 cam->vp.hue = 32768; /* 50% */
3893 cam->vp.brightness = 32768; /* 50% */
3894 cam->vp.contrast = 32768; /* 50% */
3895 cam->vp.whiteness = 0; /* not used -> grayscale only */
3896 cam->vp.depth = 24; /* to be set by user */
3897 cam->vp.palette = VIDEO_PALETTE_RGB24; /* to be set by user */
3907 cam->vw.chromakey = 0;
3909 cam->vw.clipcount = 0;
3910 cam->vw.clips = NULL;
3912 cam->cmd_queue = COMMAND_NONE;
3913 cam->first_frame = 1;
3918 /* initialize cam_data structure */
3919 static void init_camera_struct(struct cam_data *cam,
3920 struct cpia_camera_ops *ops )
3924 /* Default everything to 0 */
3925 memset(cam, 0, sizeof(struct cam_data));
3928 mutex_init(&cam->param_lock);
3929 mutex_init(&cam->busy_lock);
3931 reset_camera_struct(cam);
3933 cam->proc_entry = NULL;
3935 memcpy(&cam->vdev, &cpia_template, sizeof(cpia_template));
3936 cam->vdev.priv = cam;
3939 for (i = 0; i < FRAME_NUM; i++) {
3940 cam->frame[i].width = 0;
3941 cam->frame[i].height = 0;
3942 cam->frame[i].state = FRAME_UNUSED;
3943 cam->frame[i].data = NULL;
3945 cam->decompressed_frame.width = 0;
3946 cam->decompressed_frame.height = 0;
3947 cam->decompressed_frame.state = FRAME_UNUSED;
3948 cam->decompressed_frame.data = NULL;
3951 struct cam_data *cpia_register_camera(struct cpia_camera_ops *ops, void *lowlevel)
3953 struct cam_data *camera;
3955 if ((camera = kmalloc(sizeof(struct cam_data), GFP_KERNEL)) == NULL)
3959 init_camera_struct( camera, ops );
3960 camera->lowlevel_data = lowlevel;
3962 /* register v4l device */
3963 if (video_register_device(&camera->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
3965 printk(KERN_DEBUG "video_register_device failed\n");
3969 /* get version information from camera: open/reset/close */
3972 if (camera->ops->open(camera->lowlevel_data))
3975 /* reset the camera */
3976 if (reset_camera(camera) != 0) {
3977 camera->ops->close(camera->lowlevel_data);
3982 camera->ops->close(camera->lowlevel_data);
3984 #ifdef CONFIG_PROC_FS
3985 create_proc_cpia_cam(camera);
3988 printk(KERN_INFO " CPiA Version: %d.%02d (%d.%d)\n",
3989 camera->params.version.firmwareVersion,
3990 camera->params.version.firmwareRevision,
3991 camera->params.version.vcVersion,
3992 camera->params.version.vcRevision);
3993 printk(KERN_INFO " CPiA PnP-ID: %04x:%04x:%04x\n",
3994 camera->params.pnpID.vendor,
3995 camera->params.pnpID.product,
3996 camera->params.pnpID.deviceRevision);
3997 printk(KERN_INFO " VP-Version: %d.%d %04x\n",
3998 camera->params.vpVersion.vpVersion,
3999 camera->params.vpVersion.vpRevision,
4000 camera->params.vpVersion.cameraHeadID);
4005 void cpia_unregister_camera(struct cam_data *cam)
4007 DBG("unregistering video\n");
4008 video_unregister_device(&cam->vdev);
4009 if (cam->open_count) {
4011 DBG("camera open -- setting ops to NULL\n");
4015 #ifdef CONFIG_PROC_FS
4016 DBG("destroying /proc/cpia/video%d\n", cam->vdev.minor);
4017 destroy_proc_cpia_cam(cam);
4019 if (!cam->open_count) {
4020 DBG("freeing camera\n");
4025 static int __init cpia_init(void)
4027 printk(KERN_INFO "%s v%d.%d.%d\n", ABOUT,
4028 CPIA_MAJ_VER, CPIA_MIN_VER, CPIA_PATCH_VER);
4030 printk(KERN_WARNING "Since in-kernel colorspace conversion is not "
4031 "allowed, it is disabled by default now. Users should fix the "
4032 "applications in case they don't work without conversion "
4033 "reenabled by setting the 'colorspace_conv' module "
4034 "parameter to 1\n");
4036 #ifdef CONFIG_PROC_FS
4043 static void __exit cpia_exit(void)
4045 #ifdef CONFIG_PROC_FS
4046 proc_cpia_destroy();
4050 module_init(cpia_init);
4051 module_exit(cpia_exit);
4053 /* Exported symbols for modules. */
4055 EXPORT_SYMBOL(cpia_register_camera);
4056 EXPORT_SYMBOL(cpia_unregister_camera);