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/moduleparam.h>
32 #include <linux/init.h>
34 #include <linux/vmalloc.h>
35 #include <linux/slab.h>
36 #include <linux/proc_fs.h>
37 #include <linux/ctype.h>
38 #include <linux/pagemap.h>
39 #include <linux/delay.h>
41 #include <linux/mutex.h>
44 #include <linux/kmod.h>
49 static int video_nr = -1;
52 module_param(video_nr, int, 0);
53 MODULE_AUTHOR("Scott J. Bertin <sbertin@securenym.net> & Peter Pregler <Peter_Pregler@email.com> & Johannes Erdfelt <johannes@erdfelt.com>");
54 MODULE_DESCRIPTION("V4L-driver for Vision CPiA based cameras");
55 MODULE_LICENSE("GPL");
56 MODULE_SUPPORTED_DEVICE("video");
59 static unsigned short colorspace_conv;
60 module_param(colorspace_conv, ushort, 0444);
61 MODULE_PARM_DESC(colorspace_conv,
62 " Colorspace conversion:"
63 "\n 0 = disable, 1 = enable"
64 "\n Default value is 0"
67 #define ABOUT "V4L-Driver for Vision CPiA based cameras"
69 #ifndef VID_HARDWARE_CPIA
70 #define VID_HARDWARE_CPIA 24 /* FIXME -> from linux/videodev.h */
73 #define CPIA_MODULE_CPIA (0<<5)
74 #define CPIA_MODULE_SYSTEM (1<<5)
75 #define CPIA_MODULE_VP_CTRL (5<<5)
76 #define CPIA_MODULE_CAPTURE (6<<5)
77 #define CPIA_MODULE_DEBUG (7<<5)
79 #define INPUT (DATA_IN << 8)
80 #define OUTPUT (DATA_OUT << 8)
82 #define CPIA_COMMAND_GetCPIAVersion (INPUT | CPIA_MODULE_CPIA | 1)
83 #define CPIA_COMMAND_GetPnPID (INPUT | CPIA_MODULE_CPIA | 2)
84 #define CPIA_COMMAND_GetCameraStatus (INPUT | CPIA_MODULE_CPIA | 3)
85 #define CPIA_COMMAND_GotoHiPower (OUTPUT | CPIA_MODULE_CPIA | 4)
86 #define CPIA_COMMAND_GotoLoPower (OUTPUT | CPIA_MODULE_CPIA | 5)
87 #define CPIA_COMMAND_GotoSuspend (OUTPUT | CPIA_MODULE_CPIA | 7)
88 #define CPIA_COMMAND_GotoPassThrough (OUTPUT | CPIA_MODULE_CPIA | 8)
89 #define CPIA_COMMAND_ModifyCameraStatus (OUTPUT | CPIA_MODULE_CPIA | 10)
91 #define CPIA_COMMAND_ReadVCRegs (INPUT | CPIA_MODULE_SYSTEM | 1)
92 #define CPIA_COMMAND_WriteVCReg (OUTPUT | CPIA_MODULE_SYSTEM | 2)
93 #define CPIA_COMMAND_ReadMCPorts (INPUT | CPIA_MODULE_SYSTEM | 3)
94 #define CPIA_COMMAND_WriteMCPort (OUTPUT | CPIA_MODULE_SYSTEM | 4)
95 #define CPIA_COMMAND_SetBaudRate (OUTPUT | CPIA_MODULE_SYSTEM | 5)
96 #define CPIA_COMMAND_SetECPTiming (OUTPUT | CPIA_MODULE_SYSTEM | 6)
97 #define CPIA_COMMAND_ReadIDATA (INPUT | CPIA_MODULE_SYSTEM | 7)
98 #define CPIA_COMMAND_WriteIDATA (OUTPUT | CPIA_MODULE_SYSTEM | 8)
99 #define CPIA_COMMAND_GenericCall (OUTPUT | CPIA_MODULE_SYSTEM | 9)
100 #define CPIA_COMMAND_I2CStart (OUTPUT | CPIA_MODULE_SYSTEM | 10)
101 #define CPIA_COMMAND_I2CStop (OUTPUT | CPIA_MODULE_SYSTEM | 11)
102 #define CPIA_COMMAND_I2CWrite (OUTPUT | CPIA_MODULE_SYSTEM | 12)
103 #define CPIA_COMMAND_I2CRead (INPUT | CPIA_MODULE_SYSTEM | 13)
105 #define CPIA_COMMAND_GetVPVersion (INPUT | CPIA_MODULE_VP_CTRL | 1)
106 #define CPIA_COMMAND_ResetFrameCounter (INPUT | CPIA_MODULE_VP_CTRL | 2)
107 #define CPIA_COMMAND_SetColourParams (OUTPUT | CPIA_MODULE_VP_CTRL | 3)
108 #define CPIA_COMMAND_SetExposure (OUTPUT | CPIA_MODULE_VP_CTRL | 4)
109 #define CPIA_COMMAND_SetColourBalance (OUTPUT | CPIA_MODULE_VP_CTRL | 6)
110 #define CPIA_COMMAND_SetSensorFPS (OUTPUT | CPIA_MODULE_VP_CTRL | 7)
111 #define CPIA_COMMAND_SetVPDefaults (OUTPUT | CPIA_MODULE_VP_CTRL | 8)
112 #define CPIA_COMMAND_SetApcor (OUTPUT | CPIA_MODULE_VP_CTRL | 9)
113 #define CPIA_COMMAND_SetFlickerCtrl (OUTPUT | CPIA_MODULE_VP_CTRL | 10)
114 #define CPIA_COMMAND_SetVLOffset (OUTPUT | CPIA_MODULE_VP_CTRL | 11)
115 #define CPIA_COMMAND_GetColourParams (INPUT | CPIA_MODULE_VP_CTRL | 16)
116 #define CPIA_COMMAND_GetColourBalance (INPUT | CPIA_MODULE_VP_CTRL | 17)
117 #define CPIA_COMMAND_GetExposure (INPUT | CPIA_MODULE_VP_CTRL | 18)
118 #define CPIA_COMMAND_SetSensorMatrix (OUTPUT | CPIA_MODULE_VP_CTRL | 19)
119 #define CPIA_COMMAND_ColourBars (OUTPUT | CPIA_MODULE_VP_CTRL | 25)
120 #define CPIA_COMMAND_ReadVPRegs (INPUT | CPIA_MODULE_VP_CTRL | 30)
121 #define CPIA_COMMAND_WriteVPReg (OUTPUT | CPIA_MODULE_VP_CTRL | 31)
123 #define CPIA_COMMAND_GrabFrame (OUTPUT | CPIA_MODULE_CAPTURE | 1)
124 #define CPIA_COMMAND_UploadFrame (OUTPUT | CPIA_MODULE_CAPTURE | 2)
125 #define CPIA_COMMAND_SetGrabMode (OUTPUT | CPIA_MODULE_CAPTURE | 3)
126 #define CPIA_COMMAND_InitStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 4)
127 #define CPIA_COMMAND_FiniStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 5)
128 #define CPIA_COMMAND_StartStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 6)
129 #define CPIA_COMMAND_EndStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 7)
130 #define CPIA_COMMAND_SetFormat (OUTPUT | CPIA_MODULE_CAPTURE | 8)
131 #define CPIA_COMMAND_SetROI (OUTPUT | CPIA_MODULE_CAPTURE | 9)
132 #define CPIA_COMMAND_SetCompression (OUTPUT | CPIA_MODULE_CAPTURE | 10)
133 #define CPIA_COMMAND_SetCompressionTarget (OUTPUT | CPIA_MODULE_CAPTURE | 11)
134 #define CPIA_COMMAND_SetYUVThresh (OUTPUT | CPIA_MODULE_CAPTURE | 12)
135 #define CPIA_COMMAND_SetCompressionParams (OUTPUT | CPIA_MODULE_CAPTURE | 13)
136 #define CPIA_COMMAND_DiscardFrame (OUTPUT | CPIA_MODULE_CAPTURE | 14)
137 #define CPIA_COMMAND_GrabReset (OUTPUT | CPIA_MODULE_CAPTURE | 15)
139 #define CPIA_COMMAND_OutputRS232 (OUTPUT | CPIA_MODULE_DEBUG | 1)
140 #define CPIA_COMMAND_AbortProcess (OUTPUT | CPIA_MODULE_DEBUG | 4)
141 #define CPIA_COMMAND_SetDramPage (OUTPUT | CPIA_MODULE_DEBUG | 5)
142 #define CPIA_COMMAND_StartDramUpload (OUTPUT | CPIA_MODULE_DEBUG | 6)
143 #define CPIA_COMMAND_StartDummyDtream (OUTPUT | CPIA_MODULE_DEBUG | 8)
144 #define CPIA_COMMAND_AbortStream (OUTPUT | CPIA_MODULE_DEBUG | 9)
145 #define CPIA_COMMAND_DownloadDRAM (OUTPUT | CPIA_MODULE_DEBUG | 10)
146 #define CPIA_COMMAND_Null (OUTPUT | CPIA_MODULE_DEBUG | 11)
149 FRAME_READY, /* Ready to grab into */
150 FRAME_GRABBING, /* In the process of being grabbed into */
151 FRAME_DONE, /* Finished grabbing, but not been synced yet */
152 FRAME_UNUSED, /* Unused (no MCAPTURE) */
155 #define COMMAND_NONE 0x0000
156 #define COMMAND_SETCOMPRESSION 0x0001
157 #define COMMAND_SETCOMPRESSIONTARGET 0x0002
158 #define COMMAND_SETCOLOURPARAMS 0x0004
159 #define COMMAND_SETFORMAT 0x0008
160 #define COMMAND_PAUSE 0x0010
161 #define COMMAND_RESUME 0x0020
162 #define COMMAND_SETYUVTHRESH 0x0040
163 #define COMMAND_SETECPTIMING 0x0080
164 #define COMMAND_SETCOMPRESSIONPARAMS 0x0100
165 #define COMMAND_SETEXPOSURE 0x0200
166 #define COMMAND_SETCOLOURBALANCE 0x0400
167 #define COMMAND_SETSENSORFPS 0x0800
168 #define COMMAND_SETAPCOR 0x1000
169 #define COMMAND_SETFLICKERCTRL 0x2000
170 #define COMMAND_SETVLOFFSET 0x4000
171 #define COMMAND_SETLIGHTS 0x8000
173 #define ROUND_UP_EXP_FOR_FLICKER 15
175 /* Constants for automatic frame rate adjustment */
177 #define MAX_EXP_102 255
179 #define VERY_LOW_EXP 70
181 #define EXP_ACC_DARK 50
182 #define EXP_ACC_LIGHT 90
183 #define HIGH_COMP_102 160
188 /* Maximum number of 10ms loops to wait for the stream to become ready */
189 #define READY_TIMEOUT 100
191 /* Developer's Guide Table 5 p 3-34
192 * indexed by [mains][sensorFps.baserate][sensorFps.divisor]*/
193 static u8 flicker_jumps[2][2][4] =
194 { { { 76, 38, 19, 9 }, { 92, 46, 23, 11 } },
195 { { 64, 32, 16, 8 }, { 76, 38, 19, 9} }
198 /* forward declaration of local function */
199 static void reset_camera_struct(struct cam_data *cam);
200 static int find_over_exposure(int brightness);
201 static void set_flicker(struct cam_params *params, volatile u32 *command_flags,
205 /**********************************************************************
209 **********************************************************************/
210 static void *rvmalloc(unsigned long size)
215 size = PAGE_ALIGN(size);
216 mem = vmalloc_32(size);
220 memset(mem, 0, size); /* Clear the ram out, no junk to the user */
221 adr = (unsigned long) mem;
223 SetPageReserved(vmalloc_to_page((void *)adr));
231 static void rvfree(void *mem, unsigned long size)
238 adr = (unsigned long) mem;
239 while ((long) size > 0) {
240 ClearPageReserved(vmalloc_to_page((void *)adr));
247 /**********************************************************************
251 **********************************************************************/
252 #ifdef CONFIG_PROC_FS
253 static struct proc_dir_entry *cpia_proc_root=NULL;
255 static int cpia_read_proc(char *page, char **start, off_t off,
256 int count, int *eof, void *data)
260 struct cam_data *cam = data;
263 /* IMPORTANT: This output MUST be kept under PAGE_SIZE
264 * or we need to get more sophisticated. */
266 out += sprintf(out, "read-only\n-----------------------\n");
267 out += sprintf(out, "V4L Driver version: %d.%d.%d\n",
268 CPIA_MAJ_VER, CPIA_MIN_VER, CPIA_PATCH_VER);
269 out += sprintf(out, "CPIA Version: %d.%02d (%d.%d)\n",
270 cam->params.version.firmwareVersion,
271 cam->params.version.firmwareRevision,
272 cam->params.version.vcVersion,
273 cam->params.version.vcRevision);
274 out += sprintf(out, "CPIA PnP-ID: %04x:%04x:%04x\n",
275 cam->params.pnpID.vendor, cam->params.pnpID.product,
276 cam->params.pnpID.deviceRevision);
277 out += sprintf(out, "VP-Version: %d.%d %04x\n",
278 cam->params.vpVersion.vpVersion,
279 cam->params.vpVersion.vpRevision,
280 cam->params.vpVersion.cameraHeadID);
282 out += sprintf(out, "system_state: %#04x\n",
283 cam->params.status.systemState);
284 out += sprintf(out, "grab_state: %#04x\n",
285 cam->params.status.grabState);
286 out += sprintf(out, "stream_state: %#04x\n",
287 cam->params.status.streamState);
288 out += sprintf(out, "fatal_error: %#04x\n",
289 cam->params.status.fatalError);
290 out += sprintf(out, "cmd_error: %#04x\n",
291 cam->params.status.cmdError);
292 out += sprintf(out, "debug_flags: %#04x\n",
293 cam->params.status.debugFlags);
294 out += sprintf(out, "vp_status: %#04x\n",
295 cam->params.status.vpStatus);
296 out += sprintf(out, "error_code: %#04x\n",
297 cam->params.status.errorCode);
298 /* QX3 specific entries */
299 if (cam->params.qx3.qx3_detected) {
300 out += sprintf(out, "button: %4d\n",
301 cam->params.qx3.button);
302 out += sprintf(out, "cradled: %4d\n",
303 cam->params.qx3.cradled);
305 out += sprintf(out, "video_size: %s\n",
306 cam->params.format.videoSize == VIDEOSIZE_CIF ?
308 out += sprintf(out, "roi: (%3d, %3d) to (%3d, %3d)\n",
309 cam->params.roi.colStart*8,
310 cam->params.roi.rowStart*4,
311 cam->params.roi.colEnd*8,
312 cam->params.roi.rowEnd*4);
313 out += sprintf(out, "actual_fps: %3d\n", cam->fps);
314 out += sprintf(out, "transfer_rate: %4dkB/s\n",
317 out += sprintf(out, "\nread-write\n");
318 out += sprintf(out, "----------------------- current min"
319 " max default comment\n");
320 out += sprintf(out, "brightness: %8d %8d %8d %8d\n",
321 cam->params.colourParams.brightness, 0, 100, 50);
322 if (cam->params.version.firmwareVersion == 1 &&
323 cam->params.version.firmwareRevision == 2)
324 /* 1-02 firmware limits contrast to 80 */
329 out += sprintf(out, "contrast: %8d %8d %8d %8d"
331 cam->params.colourParams.contrast, 0, tmp, 48);
332 out += sprintf(out, "saturation: %8d %8d %8d %8d\n",
333 cam->params.colourParams.saturation, 0, 100, 50);
334 tmp = (25000+5000*cam->params.sensorFps.baserate)/
335 (1<<cam->params.sensorFps.divisor);
336 out += sprintf(out, "sensor_fps: %4d.%03d %8d %8d %8d\n",
337 tmp/1000, tmp%1000, 3, 30, 15);
338 out += sprintf(out, "stream_start_line: %8d %8d %8d %8d\n",
339 2*cam->params.streamStartLine, 0,
340 cam->params.format.videoSize == VIDEOSIZE_CIF ? 288:144,
341 cam->params.format.videoSize == VIDEOSIZE_CIF ? 240:120);
342 out += sprintf(out, "sub_sample: %8s %8s %8s %8s\n",
343 cam->params.format.subSample == SUBSAMPLE_420 ?
344 "420" : "422", "420", "422", "422");
345 out += sprintf(out, "yuv_order: %8s %8s %8s %8s\n",
346 cam->params.format.yuvOrder == YUVORDER_YUYV ?
347 "YUYV" : "UYVY", "YUYV" , "UYVY", "YUYV");
348 out += sprintf(out, "ecp_timing: %8s %8s %8s %8s\n",
349 cam->params.ecpTiming ? "slow" : "normal", "slow",
352 if (cam->params.colourBalance.balanceMode == 2) {
353 sprintf(tmpstr, "auto");
355 sprintf(tmpstr, "manual");
357 out += sprintf(out, "color_balance_mode: %8s %8s %8s"
358 " %8s\n", tmpstr, "manual", "auto", "auto");
359 out += sprintf(out, "red_gain: %8d %8d %8d %8d\n",
360 cam->params.colourBalance.redGain, 0, 212, 32);
361 out += sprintf(out, "green_gain: %8d %8d %8d %8d\n",
362 cam->params.colourBalance.greenGain, 0, 212, 6);
363 out += sprintf(out, "blue_gain: %8d %8d %8d %8d\n",
364 cam->params.colourBalance.blueGain, 0, 212, 92);
366 if (cam->params.version.firmwareVersion == 1 &&
367 cam->params.version.firmwareRevision == 2)
368 /* 1-02 firmware limits gain to 2 */
369 sprintf(tmpstr, "%8d %8d %8d", 1, 2, 2);
371 sprintf(tmpstr, "%8d %8d %8d", 1, 8, 2);
373 if (cam->params.exposure.gainMode == 0)
374 out += sprintf(out, "max_gain: unknown %28s"
375 " powers of 2\n", tmpstr);
377 out += sprintf(out, "max_gain: %8d %28s"
379 1<<(cam->params.exposure.gainMode-1), tmpstr);
381 switch(cam->params.exposure.expMode) {
384 sprintf(tmpstr, "manual");
387 sprintf(tmpstr, "auto");
390 sprintf(tmpstr, "unknown");
393 out += sprintf(out, "exposure_mode: %8s %8s %8s"
394 " %8s\n", tmpstr, "manual", "auto", "auto");
395 out += sprintf(out, "centre_weight: %8s %8s %8s %8s\n",
396 (2-cam->params.exposure.centreWeight) ? "on" : "off",
398 out += sprintf(out, "gain: %8d %8d max_gain %8d 1,2,4,8 possible\n",
399 1<<cam->params.exposure.gain, 1, 1);
400 if (cam->params.version.firmwareVersion == 1 &&
401 cam->params.version.firmwareRevision == 2)
402 /* 1-02 firmware limits fineExp/2 to 127 */
407 out += sprintf(out, "fine_exp: %8d %8d %8d %8d\n",
408 cam->params.exposure.fineExp*2, 0, tmp, 0);
409 if (cam->params.version.firmwareVersion == 1 &&
410 cam->params.version.firmwareRevision == 2)
411 /* 1-02 firmware limits coarseExpHi to 0 */
416 out += sprintf(out, "coarse_exp: %8d %8d %8d"
417 " %8d\n", cam->params.exposure.coarseExpLo+
418 256*cam->params.exposure.coarseExpHi, 0, tmp, 185);
419 out += sprintf(out, "red_comp: %8d %8d %8d %8d\n",
420 cam->params.exposure.redComp, COMP_RED, 255, COMP_RED);
421 out += sprintf(out, "green1_comp: %8d %8d %8d %8d\n",
422 cam->params.exposure.green1Comp, COMP_GREEN1, 255,
424 out += sprintf(out, "green2_comp: %8d %8d %8d %8d\n",
425 cam->params.exposure.green2Comp, COMP_GREEN2, 255,
427 out += sprintf(out, "blue_comp: %8d %8d %8d %8d\n",
428 cam->params.exposure.blueComp, COMP_BLUE, 255, COMP_BLUE);
430 out += sprintf(out, "apcor_gain1: %#8x %#8x %#8x %#8x\n",
431 cam->params.apcor.gain1, 0, 0xff, 0x1c);
432 out += sprintf(out, "apcor_gain2: %#8x %#8x %#8x %#8x\n",
433 cam->params.apcor.gain2, 0, 0xff, 0x1a);
434 out += sprintf(out, "apcor_gain4: %#8x %#8x %#8x %#8x\n",
435 cam->params.apcor.gain4, 0, 0xff, 0x2d);
436 out += sprintf(out, "apcor_gain8: %#8x %#8x %#8x %#8x\n",
437 cam->params.apcor.gain8, 0, 0xff, 0x2a);
438 out += sprintf(out, "vl_offset_gain1: %8d %8d %8d %8d\n",
439 cam->params.vlOffset.gain1, 0, 255, 24);
440 out += sprintf(out, "vl_offset_gain2: %8d %8d %8d %8d\n",
441 cam->params.vlOffset.gain2, 0, 255, 28);
442 out += sprintf(out, "vl_offset_gain4: %8d %8d %8d %8d\n",
443 cam->params.vlOffset.gain4, 0, 255, 30);
444 out += sprintf(out, "vl_offset_gain8: %8d %8d %8d %8d\n",
445 cam->params.vlOffset.gain8, 0, 255, 30);
446 out += sprintf(out, "flicker_control: %8s %8s %8s %8s\n",
447 cam->params.flickerControl.flickerMode ? "on" : "off",
449 out += sprintf(out, "mains_frequency: %8d %8d %8d %8d"
451 cam->mainsFreq ? 60 : 50, 50, 60, 50);
452 if(cam->params.flickerControl.allowableOverExposure < 0)
453 out += sprintf(out, "allowable_overexposure: %4dauto auto %8d auto\n",
454 -cam->params.flickerControl.allowableOverExposure,
457 out += sprintf(out, "allowable_overexposure: %8d auto %8d auto\n",
458 cam->params.flickerControl.allowableOverExposure,
460 out += sprintf(out, "compression_mode: ");
461 switch(cam->params.compression.mode) {
462 case CPIA_COMPRESSION_NONE:
463 out += sprintf(out, "%8s", "none");
465 case CPIA_COMPRESSION_AUTO:
466 out += sprintf(out, "%8s", "auto");
468 case CPIA_COMPRESSION_MANUAL:
469 out += sprintf(out, "%8s", "manual");
472 out += sprintf(out, "%8s", "unknown");
475 out += sprintf(out, " none,auto,manual auto\n");
476 out += sprintf(out, "decimation_enable: %8s %8s %8s %8s\n",
477 cam->params.compression.decimation ==
478 DECIMATION_ENAB ? "on":"off", "off", "on",
480 out += sprintf(out, "compression_target: %9s %9s %9s %9s\n",
481 cam->params.compressionTarget.frTargeting ==
482 CPIA_COMPRESSION_TARGET_FRAMERATE ?
483 "framerate":"quality",
484 "framerate", "quality", "quality");
485 out += sprintf(out, "target_framerate: %8d %8d %8d %8d\n",
486 cam->params.compressionTarget.targetFR, 1, 30, 15);
487 out += sprintf(out, "target_quality: %8d %8d %8d %8d\n",
488 cam->params.compressionTarget.targetQ, 1, 64, 5);
489 out += sprintf(out, "y_threshold: %8d %8d %8d %8d\n",
490 cam->params.yuvThreshold.yThreshold, 0, 31, 6);
491 out += sprintf(out, "uv_threshold: %8d %8d %8d %8d\n",
492 cam->params.yuvThreshold.uvThreshold, 0, 31, 6);
493 out += sprintf(out, "hysteresis: %8d %8d %8d %8d\n",
494 cam->params.compressionParams.hysteresis, 0, 255, 3);
495 out += sprintf(out, "threshold_max: %8d %8d %8d %8d\n",
496 cam->params.compressionParams.threshMax, 0, 255, 11);
497 out += sprintf(out, "small_step: %8d %8d %8d %8d\n",
498 cam->params.compressionParams.smallStep, 0, 255, 1);
499 out += sprintf(out, "large_step: %8d %8d %8d %8d\n",
500 cam->params.compressionParams.largeStep, 0, 255, 3);
501 out += sprintf(out, "decimation_hysteresis: %8d %8d %8d %8d\n",
502 cam->params.compressionParams.decimationHysteresis,
504 out += sprintf(out, "fr_diff_step_thresh: %8d %8d %8d %8d\n",
505 cam->params.compressionParams.frDiffStepThresh,
507 out += sprintf(out, "q_diff_step_thresh: %8d %8d %8d %8d\n",
508 cam->params.compressionParams.qDiffStepThresh,
510 out += sprintf(out, "decimation_thresh_mod: %8d %8d %8d %8d\n",
511 cam->params.compressionParams.decimationThreshMod,
513 /* QX3 specific entries */
514 if (cam->params.qx3.qx3_detected) {
515 out += sprintf(out, "toplight: %8s %8s %8s %8s\n",
516 cam->params.qx3.toplight ? "on" : "off",
518 out += sprintf(out, "bottomlight: %8s %8s %8s %8s\n",
519 cam->params.qx3.bottomlight ? "on" : "off",
527 if (len <= 0) return 0;
536 static int match(char *checkstr, char **buffer, unsigned long *count,
537 int *find_colon, int *err)
539 int ret, colon_found = 1;
540 int len = strlen(checkstr);
541 ret = (len <= *count && strncmp(*buffer, checkstr, len) == 0);
547 while (*count && (**buffer == ' ' || **buffer == '\t' ||
548 (!colon_found && **buffer == ':'))) {
554 if (!*count || !colon_found)
562 static unsigned long int value(char **buffer, unsigned long *count, int *err)
565 unsigned long int ret;
566 ret = simple_strtoul(*buffer, &p, 0);
570 *count -= p - *buffer;
576 static int cpia_write_proc(struct file *file, const char __user *buf,
577 unsigned long count, void *data)
579 struct cam_data *cam = data;
580 struct cam_params new_params;
582 int retval, find_colon;
584 unsigned long val = 0;
585 u32 command_flags = 0;
589 * This code to copy from buf to page is shamelessly copied
590 * from the comx driver
592 if (count > PAGE_SIZE) {
593 printk(KERN_ERR "count is %lu > %d!!!\n", count, (int)PAGE_SIZE);
597 if (!(page = (char *)__get_free_page(GFP_KERNEL))) return -ENOMEM;
599 if(copy_from_user(page, buf, count))
605 if (page[count-1] == '\n')
606 page[count-1] = '\0';
607 else if (count < PAGE_SIZE)
609 else if (page[count]) {
616 if (mutex_lock_interruptible(&cam->param_lock))
620 * Skip over leading whitespace
622 while (count && isspace(*buffer)) {
627 memcpy(&new_params, &cam->params, sizeof(struct cam_params));
628 new_mains = cam->mainsFreq;
630 #define MATCH(x) (match(x, &buffer, &count, &find_colon, &retval))
631 #define VALUE (value(&buffer,&count, &retval))
632 #define FIRMWARE_VERSION(x,y) (new_params.version.firmwareVersion == (x) && \
633 new_params.version.firmwareRevision == (y))
636 while (count && !retval) {
638 if (MATCH("brightness")) {
644 new_params.colourParams.brightness = val;
648 command_flags |= COMMAND_SETCOLOURPARAMS;
649 if(new_params.flickerControl.allowableOverExposure < 0)
650 new_params.flickerControl.allowableOverExposure =
651 -find_over_exposure(new_params.colourParams.brightness);
652 if(new_params.flickerControl.flickerMode != 0)
653 command_flags |= COMMAND_SETFLICKERCTRL;
655 } else if (MATCH("contrast")) {
661 /* contrast is in steps of 8, so round*/
662 val = ((val + 3) / 8) * 8;
663 /* 1-02 firmware limits contrast to 80*/
664 if (FIRMWARE_VERSION(1,2) && val > 80)
667 new_params.colourParams.contrast = val;
671 command_flags |= COMMAND_SETCOLOURPARAMS;
672 } else if (MATCH("saturation")) {
678 new_params.colourParams.saturation = val;
682 command_flags |= COMMAND_SETCOLOURPARAMS;
683 } else if (MATCH("sensor_fps")) {
688 /* find values so that sensorFPS is minimized,
693 new_params.sensorFps.divisor = 0;
694 new_params.sensorFps.baserate = 1;
695 } else if (val > 15) {
696 new_params.sensorFps.divisor = 0;
697 new_params.sensorFps.baserate = 0;
698 } else if (val > 12) {
699 new_params.sensorFps.divisor = 1;
700 new_params.sensorFps.baserate = 1;
701 } else if (val > 7) {
702 new_params.sensorFps.divisor = 1;
703 new_params.sensorFps.baserate = 0;
704 } else if (val > 6) {
705 new_params.sensorFps.divisor = 2;
706 new_params.sensorFps.baserate = 1;
707 } else if (val > 3) {
708 new_params.sensorFps.divisor = 2;
709 new_params.sensorFps.baserate = 0;
711 new_params.sensorFps.divisor = 3;
712 /* Either base rate would work here */
713 new_params.sensorFps.baserate = 1;
715 new_params.flickerControl.coarseJump =
716 flicker_jumps[new_mains]
717 [new_params.sensorFps.baserate]
718 [new_params.sensorFps.divisor];
719 if (new_params.flickerControl.flickerMode)
720 command_flags |= COMMAND_SETFLICKERCTRL;
722 command_flags |= COMMAND_SETSENSORFPS;
723 cam->exposure_status = EXPOSURE_NORMAL;
724 } else if (MATCH("stream_start_line")) {
731 if (new_params.format.videoSize == VIDEOSIZE_QCIF)
734 new_params.streamStartLine = val/2;
738 } else if (MATCH("sub_sample")) {
739 if (!retval && MATCH("420"))
740 new_params.format.subSample = SUBSAMPLE_420;
741 else if (!retval && MATCH("422"))
742 new_params.format.subSample = SUBSAMPLE_422;
746 command_flags |= COMMAND_SETFORMAT;
747 } else if (MATCH("yuv_order")) {
748 if (!retval && MATCH("YUYV"))
749 new_params.format.yuvOrder = YUVORDER_YUYV;
750 else if (!retval && MATCH("UYVY"))
751 new_params.format.yuvOrder = YUVORDER_UYVY;
755 command_flags |= COMMAND_SETFORMAT;
756 } else if (MATCH("ecp_timing")) {
757 if (!retval && MATCH("normal"))
758 new_params.ecpTiming = 0;
759 else if (!retval && MATCH("slow"))
760 new_params.ecpTiming = 1;
764 command_flags |= COMMAND_SETECPTIMING;
765 } else if (MATCH("color_balance_mode")) {
766 if (!retval && MATCH("manual"))
767 new_params.colourBalance.balanceMode = 3;
768 else if (!retval && MATCH("auto"))
769 new_params.colourBalance.balanceMode = 2;
773 command_flags |= COMMAND_SETCOLOURBALANCE;
774 } else if (MATCH("red_gain")) {
780 new_params.colourBalance.redGain = val;
781 new_params.colourBalance.balanceMode = 1;
785 command_flags |= COMMAND_SETCOLOURBALANCE;
786 } else if (MATCH("green_gain")) {
792 new_params.colourBalance.greenGain = val;
793 new_params.colourBalance.balanceMode = 1;
797 command_flags |= COMMAND_SETCOLOURBALANCE;
798 } else if (MATCH("blue_gain")) {
804 new_params.colourBalance.blueGain = val;
805 new_params.colourBalance.balanceMode = 1;
809 command_flags |= COMMAND_SETCOLOURBALANCE;
810 } else if (MATCH("max_gain")) {
815 /* 1-02 firmware limits gain to 2 */
816 if (FIRMWARE_VERSION(1,2) && val > 2)
820 new_params.exposure.gainMode = 1;
823 new_params.exposure.gainMode = 2;
826 new_params.exposure.gainMode = 3;
829 new_params.exposure.gainMode = 4;
836 command_flags |= COMMAND_SETEXPOSURE;
837 } else if (MATCH("exposure_mode")) {
838 if (!retval && MATCH("auto"))
839 new_params.exposure.expMode = 2;
840 else if (!retval && MATCH("manual")) {
841 if (new_params.exposure.expMode == 2)
842 new_params.exposure.expMode = 3;
843 if(new_params.flickerControl.flickerMode != 0)
844 command_flags |= COMMAND_SETFLICKERCTRL;
845 new_params.flickerControl.flickerMode = 0;
849 command_flags |= COMMAND_SETEXPOSURE;
850 } else if (MATCH("centre_weight")) {
851 if (!retval && MATCH("on"))
852 new_params.exposure.centreWeight = 1;
853 else if (!retval && MATCH("off"))
854 new_params.exposure.centreWeight = 2;
858 command_flags |= COMMAND_SETEXPOSURE;
859 } else if (MATCH("gain")) {
866 new_params.exposure.gain = 0;
869 new_params.exposure.gain = 1;
872 new_params.exposure.gain = 2;
875 new_params.exposure.gain = 3;
881 new_params.exposure.expMode = 1;
882 if(new_params.flickerControl.flickerMode != 0)
883 command_flags |= COMMAND_SETFLICKERCTRL;
884 new_params.flickerControl.flickerMode = 0;
885 command_flags |= COMMAND_SETEXPOSURE;
886 if (new_params.exposure.gain >
887 new_params.exposure.gainMode-1)
890 } else if (MATCH("fine_exp")) {
896 /* 1-02 firmware limits fineExp/2 to 127*/
897 if (FIRMWARE_VERSION(1,2) && val > 127)
899 new_params.exposure.fineExp = val;
900 new_params.exposure.expMode = 1;
901 command_flags |= COMMAND_SETEXPOSURE;
902 if(new_params.flickerControl.flickerMode != 0)
903 command_flags |= COMMAND_SETFLICKERCTRL;
904 new_params.flickerControl.flickerMode = 0;
905 command_flags |= COMMAND_SETFLICKERCTRL;
909 } else if (MATCH("coarse_exp")) {
914 if (val <= MAX_EXP) {
915 if (FIRMWARE_VERSION(1,2) &&
918 new_params.exposure.coarseExpLo =
920 new_params.exposure.coarseExpHi =
922 new_params.exposure.expMode = 1;
923 command_flags |= COMMAND_SETEXPOSURE;
924 if(new_params.flickerControl.flickerMode != 0)
925 command_flags |= COMMAND_SETFLICKERCTRL;
926 new_params.flickerControl.flickerMode = 0;
927 command_flags |= COMMAND_SETFLICKERCTRL;
931 } else if (MATCH("red_comp")) {
936 if (val >= COMP_RED && val <= 255) {
937 new_params.exposure.redComp = val;
938 new_params.exposure.compMode = 1;
939 command_flags |= COMMAND_SETEXPOSURE;
943 } else if (MATCH("green1_comp")) {
948 if (val >= COMP_GREEN1 && val <= 255) {
949 new_params.exposure.green1Comp = val;
950 new_params.exposure.compMode = 1;
951 command_flags |= COMMAND_SETEXPOSURE;
955 } else if (MATCH("green2_comp")) {
960 if (val >= COMP_GREEN2 && val <= 255) {
961 new_params.exposure.green2Comp = val;
962 new_params.exposure.compMode = 1;
963 command_flags |= COMMAND_SETEXPOSURE;
967 } else if (MATCH("blue_comp")) {
972 if (val >= COMP_BLUE && val <= 255) {
973 new_params.exposure.blueComp = val;
974 new_params.exposure.compMode = 1;
975 command_flags |= COMMAND_SETEXPOSURE;
979 } else if (MATCH("apcor_gain1")) {
984 command_flags |= COMMAND_SETAPCOR;
986 new_params.apcor.gain1 = val;
990 } else if (MATCH("apcor_gain2")) {
995 command_flags |= COMMAND_SETAPCOR;
997 new_params.apcor.gain2 = val;
1001 } else if (MATCH("apcor_gain4")) {
1006 command_flags |= COMMAND_SETAPCOR;
1008 new_params.apcor.gain4 = val;
1012 } else if (MATCH("apcor_gain8")) {
1017 command_flags |= COMMAND_SETAPCOR;
1019 new_params.apcor.gain8 = val;
1023 } else if (MATCH("vl_offset_gain1")) {
1029 new_params.vlOffset.gain1 = val;
1033 command_flags |= COMMAND_SETVLOFFSET;
1034 } else if (MATCH("vl_offset_gain2")) {
1040 new_params.vlOffset.gain2 = val;
1044 command_flags |= COMMAND_SETVLOFFSET;
1045 } else if (MATCH("vl_offset_gain4")) {
1051 new_params.vlOffset.gain4 = val;
1055 command_flags |= COMMAND_SETVLOFFSET;
1056 } else if (MATCH("vl_offset_gain8")) {
1062 new_params.vlOffset.gain8 = val;
1066 command_flags |= COMMAND_SETVLOFFSET;
1067 } else if (MATCH("flicker_control")) {
1068 if (!retval && MATCH("on")) {
1069 set_flicker(&new_params, &command_flags, 1);
1070 } else if (!retval && MATCH("off")) {
1071 set_flicker(&new_params, &command_flags, 0);
1075 command_flags |= COMMAND_SETFLICKERCTRL;
1076 } else if (MATCH("mains_frequency")) {
1077 if (!retval && MATCH("50")) {
1079 new_params.flickerControl.coarseJump =
1080 flicker_jumps[new_mains]
1081 [new_params.sensorFps.baserate]
1082 [new_params.sensorFps.divisor];
1083 if (new_params.flickerControl.flickerMode)
1084 command_flags |= COMMAND_SETFLICKERCTRL;
1085 } else if (!retval && MATCH("60")) {
1087 new_params.flickerControl.coarseJump =
1088 flicker_jumps[new_mains]
1089 [new_params.sensorFps.baserate]
1090 [new_params.sensorFps.divisor];
1091 if (new_params.flickerControl.flickerMode)
1092 command_flags |= COMMAND_SETFLICKERCTRL;
1095 } else if (MATCH("allowable_overexposure")) {
1096 if (!retval && MATCH("auto")) {
1097 new_params.flickerControl.allowableOverExposure =
1098 -find_over_exposure(new_params.colourParams.brightness);
1099 if(new_params.flickerControl.flickerMode != 0)
1100 command_flags |= COMMAND_SETFLICKERCTRL;
1107 new_params.flickerControl.
1108 allowableOverExposure = val;
1109 if(new_params.flickerControl.flickerMode != 0)
1110 command_flags |= COMMAND_SETFLICKERCTRL;
1115 } else if (MATCH("compression_mode")) {
1116 if (!retval && MATCH("none"))
1117 new_params.compression.mode =
1118 CPIA_COMPRESSION_NONE;
1119 else if (!retval && MATCH("auto"))
1120 new_params.compression.mode =
1121 CPIA_COMPRESSION_AUTO;
1122 else if (!retval && MATCH("manual"))
1123 new_params.compression.mode =
1124 CPIA_COMPRESSION_MANUAL;
1128 command_flags |= COMMAND_SETCOMPRESSION;
1129 } else if (MATCH("decimation_enable")) {
1130 if (!retval && MATCH("off"))
1131 new_params.compression.decimation = 0;
1132 else if (!retval && MATCH("on"))
1133 new_params.compression.decimation = 1;
1137 command_flags |= COMMAND_SETCOMPRESSION;
1138 } else if (MATCH("compression_target")) {
1139 if (!retval && MATCH("quality"))
1140 new_params.compressionTarget.frTargeting =
1141 CPIA_COMPRESSION_TARGET_QUALITY;
1142 else if (!retval && MATCH("framerate"))
1143 new_params.compressionTarget.frTargeting =
1144 CPIA_COMPRESSION_TARGET_FRAMERATE;
1148 command_flags |= COMMAND_SETCOMPRESSIONTARGET;
1149 } else if (MATCH("target_framerate")) {
1154 if(val > 0 && val <= 30)
1155 new_params.compressionTarget.targetFR = val;
1159 command_flags |= COMMAND_SETCOMPRESSIONTARGET;
1160 } else if (MATCH("target_quality")) {
1165 if(val > 0 && val <= 64)
1166 new_params.compressionTarget.targetQ = val;
1170 command_flags |= COMMAND_SETCOMPRESSIONTARGET;
1171 } else if (MATCH("y_threshold")) {
1177 new_params.yuvThreshold.yThreshold = val;
1181 command_flags |= COMMAND_SETYUVTHRESH;
1182 } else if (MATCH("uv_threshold")) {
1188 new_params.yuvThreshold.uvThreshold = val;
1192 command_flags |= COMMAND_SETYUVTHRESH;
1193 } else if (MATCH("hysteresis")) {
1199 new_params.compressionParams.hysteresis = val;
1203 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1204 } else if (MATCH("threshold_max")) {
1210 new_params.compressionParams.threshMax = val;
1214 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1215 } else if (MATCH("small_step")) {
1221 new_params.compressionParams.smallStep = val;
1225 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1226 } else if (MATCH("large_step")) {
1232 new_params.compressionParams.largeStep = val;
1236 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1237 } else if (MATCH("decimation_hysteresis")) {
1243 new_params.compressionParams.decimationHysteresis = val;
1247 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1248 } else if (MATCH("fr_diff_step_thresh")) {
1254 new_params.compressionParams.frDiffStepThresh = val;
1258 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1259 } else if (MATCH("q_diff_step_thresh")) {
1265 new_params.compressionParams.qDiffStepThresh = val;
1269 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1270 } else if (MATCH("decimation_thresh_mod")) {
1276 new_params.compressionParams.decimationThreshMod = val;
1280 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1281 } else if (MATCH("toplight")) {
1282 if (!retval && MATCH("on"))
1283 new_params.qx3.toplight = 1;
1284 else if (!retval && MATCH("off"))
1285 new_params.qx3.toplight = 0;
1288 command_flags |= COMMAND_SETLIGHTS;
1289 } else if (MATCH("bottomlight")) {
1290 if (!retval && MATCH("on"))
1291 new_params.qx3.bottomlight = 1;
1292 else if (!retval && MATCH("off"))
1293 new_params.qx3.bottomlight = 0;
1296 command_flags |= COMMAND_SETLIGHTS;
1298 DBG("No match found\n");
1303 while (count && isspace(*buffer) && *buffer != '\n') {
1308 if (*buffer == '\0' && count != 1)
1310 else if (*buffer != '\n' && *buffer != ';' &&
1322 #undef FIRMWARE_VERSION
1324 if (command_flags & COMMAND_SETCOLOURPARAMS) {
1325 /* Adjust cam->vp to reflect these changes */
1326 cam->vp.brightness =
1327 new_params.colourParams.brightness*65535/100;
1329 new_params.colourParams.contrast*65535/100;
1331 new_params.colourParams.saturation*65535/100;
1333 if((command_flags & COMMAND_SETEXPOSURE) &&
1334 new_params.exposure.expMode == 2)
1335 cam->exposure_status = EXPOSURE_NORMAL;
1337 memcpy(&cam->params, &new_params, sizeof(struct cam_params));
1338 cam->mainsFreq = new_mains;
1339 cam->cmd_queue |= command_flags;
1342 DBG("error: %d\n", retval);
1344 mutex_unlock(&cam->param_lock);
1347 free_page((unsigned long)page);
1351 static void create_proc_cpia_cam(struct cam_data *cam)
1353 char name[5 + 1 + 10 + 1];
1354 struct proc_dir_entry *ent;
1356 if (!cpia_proc_root || !cam)
1359 snprintf(name, sizeof(name), "video%d", cam->vdev.minor);
1361 ent = create_proc_entry(name, S_IFREG|S_IRUGO|S_IWUSR, cpia_proc_root);
1366 ent->read_proc = cpia_read_proc;
1367 ent->write_proc = cpia_write_proc;
1369 size of the proc entry is 3736 bytes for the standard webcam;
1370 the extra features of the QX3 microscope add 189 bytes.
1371 (we have not yet probed the camera to see which type it is).
1373 ent->size = 3736 + 189;
1374 cam->proc_entry = ent;
1377 static void destroy_proc_cpia_cam(struct cam_data *cam)
1379 char name[5 + 1 + 10 + 1];
1381 if (!cam || !cam->proc_entry)
1384 snprintf(name, sizeof(name), "video%d", cam->vdev.minor);
1385 remove_proc_entry(name, cpia_proc_root);
1386 cam->proc_entry = NULL;
1389 static void proc_cpia_create(void)
1391 cpia_proc_root = proc_mkdir("cpia", NULL);
1394 cpia_proc_root->owner = THIS_MODULE;
1396 LOG("Unable to initialise /proc/cpia\n");
1399 static void __exit proc_cpia_destroy(void)
1401 remove_proc_entry("cpia", NULL);
1403 #endif /* CONFIG_PROC_FS */
1405 /* ----------------------- debug functions ---------------------- */
1407 #define printstatus(cam) \
1408 DBG("%02x %02x %02x %02x %02x %02x %02x %02x\n",\
1409 cam->params.status.systemState, cam->params.status.grabState, \
1410 cam->params.status.streamState, cam->params.status.fatalError, \
1411 cam->params.status.cmdError, cam->params.status.debugFlags, \
1412 cam->params.status.vpStatus, cam->params.status.errorCode);
1414 /* ----------------------- v4l helpers -------------------------- */
1416 /* supported frame palettes and depths */
1417 static inline int valid_mode(u16 palette, u16 depth)
1419 if ((palette == VIDEO_PALETTE_YUV422 && depth == 16) ||
1420 (palette == VIDEO_PALETTE_YUYV && depth == 16))
1423 if (colorspace_conv)
1424 return (palette == VIDEO_PALETTE_GREY && depth == 8) ||
1425 (palette == VIDEO_PALETTE_RGB555 && depth == 16) ||
1426 (palette == VIDEO_PALETTE_RGB565 && depth == 16) ||
1427 (palette == VIDEO_PALETTE_RGB24 && depth == 24) ||
1428 (palette == VIDEO_PALETTE_RGB32 && depth == 32) ||
1429 (palette == VIDEO_PALETTE_UYVY && depth == 16);
1434 static int match_videosize( int width, int height )
1436 /* return the best match, where 'best' is as always
1437 * the largest that is not bigger than what is requested. */
1438 if (width>=352 && height>=288)
1439 return VIDEOSIZE_352_288; /* CIF */
1441 if (width>=320 && height>=240)
1442 return VIDEOSIZE_320_240; /* SIF */
1444 if (width>=288 && height>=216)
1445 return VIDEOSIZE_288_216;
1447 if (width>=256 && height>=192)
1448 return VIDEOSIZE_256_192;
1450 if (width>=224 && height>=168)
1451 return VIDEOSIZE_224_168;
1453 if (width>=192 && height>=144)
1454 return VIDEOSIZE_192_144;
1456 if (width>=176 && height>=144)
1457 return VIDEOSIZE_176_144; /* QCIF */
1459 if (width>=160 && height>=120)
1460 return VIDEOSIZE_160_120; /* QSIF */
1462 if (width>=128 && height>=96)
1463 return VIDEOSIZE_128_96;
1465 if (width>=88 && height>=72)
1466 return VIDEOSIZE_88_72;
1468 if (width>=64 && height>=48)
1469 return VIDEOSIZE_64_48;
1471 if (width>=48 && height>=48)
1472 return VIDEOSIZE_48_48;
1477 /* these are the capture sizes we support */
1478 static void set_vw_size(struct cam_data *cam)
1480 /* the col/row/start/end values are the result of simple math */
1481 /* study the SetROI-command in cpia developers guide p 2-22 */
1482 /* streamStartLine is set to the recommended value in the cpia */
1483 /* developers guide p 3-37 */
1484 switch(cam->video_size) {
1486 cam->vw.width = 352;
1487 cam->vw.height = 288;
1488 cam->params.format.videoSize=VIDEOSIZE_CIF;
1489 cam->params.roi.colStart=0;
1490 cam->params.roi.rowStart=0;
1491 cam->params.streamStartLine = 120;
1494 cam->vw.width = 320;
1495 cam->vw.height = 240;
1496 cam->params.format.videoSize=VIDEOSIZE_CIF;
1497 cam->params.roi.colStart=2;
1498 cam->params.roi.rowStart=6;
1499 cam->params.streamStartLine = 120;
1501 case VIDEOSIZE_288_216:
1502 cam->vw.width = 288;
1503 cam->vw.height = 216;
1504 cam->params.format.videoSize=VIDEOSIZE_CIF;
1505 cam->params.roi.colStart=4;
1506 cam->params.roi.rowStart=9;
1507 cam->params.streamStartLine = 120;
1509 case VIDEOSIZE_256_192:
1510 cam->vw.width = 256;
1511 cam->vw.height = 192;
1512 cam->params.format.videoSize=VIDEOSIZE_CIF;
1513 cam->params.roi.colStart=6;
1514 cam->params.roi.rowStart=12;
1515 cam->params.streamStartLine = 120;
1517 case VIDEOSIZE_224_168:
1518 cam->vw.width = 224;
1519 cam->vw.height = 168;
1520 cam->params.format.videoSize=VIDEOSIZE_CIF;
1521 cam->params.roi.colStart=8;
1522 cam->params.roi.rowStart=15;
1523 cam->params.streamStartLine = 120;
1525 case VIDEOSIZE_192_144:
1526 cam->vw.width = 192;
1527 cam->vw.height = 144;
1528 cam->params.format.videoSize=VIDEOSIZE_CIF;
1529 cam->params.roi.colStart=10;
1530 cam->params.roi.rowStart=18;
1531 cam->params.streamStartLine = 120;
1533 case VIDEOSIZE_QCIF:
1534 cam->vw.width = 176;
1535 cam->vw.height = 144;
1536 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1537 cam->params.roi.colStart=0;
1538 cam->params.roi.rowStart=0;
1539 cam->params.streamStartLine = 60;
1541 case VIDEOSIZE_QSIF:
1542 cam->vw.width = 160;
1543 cam->vw.height = 120;
1544 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1545 cam->params.roi.colStart=1;
1546 cam->params.roi.rowStart=3;
1547 cam->params.streamStartLine = 60;
1549 case VIDEOSIZE_128_96:
1550 cam->vw.width = 128;
1551 cam->vw.height = 96;
1552 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1553 cam->params.roi.colStart=3;
1554 cam->params.roi.rowStart=6;
1555 cam->params.streamStartLine = 60;
1557 case VIDEOSIZE_88_72:
1559 cam->vw.height = 72;
1560 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1561 cam->params.roi.colStart=5;
1562 cam->params.roi.rowStart=9;
1563 cam->params.streamStartLine = 60;
1565 case VIDEOSIZE_64_48:
1567 cam->vw.height = 48;
1568 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1569 cam->params.roi.colStart=7;
1570 cam->params.roi.rowStart=12;
1571 cam->params.streamStartLine = 60;
1573 case VIDEOSIZE_48_48:
1575 cam->vw.height = 48;
1576 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1577 cam->params.roi.colStart=8;
1578 cam->params.roi.rowStart=6;
1579 cam->params.streamStartLine = 60;
1582 LOG("bad videosize value: %d\n", cam->video_size);
1586 if(cam->vc.width == 0)
1587 cam->vc.width = cam->vw.width;
1588 if(cam->vc.height == 0)
1589 cam->vc.height = cam->vw.height;
1591 cam->params.roi.colStart += cam->vc.x >> 3;
1592 cam->params.roi.colEnd = cam->params.roi.colStart +
1593 (cam->vc.width >> 3);
1594 cam->params.roi.rowStart += cam->vc.y >> 2;
1595 cam->params.roi.rowEnd = cam->params.roi.rowStart +
1596 (cam->vc.height >> 2);
1601 static int allocate_frame_buf(struct cam_data *cam)
1605 cam->frame_buf = rvmalloc(FRAME_NUM * CPIA_MAX_FRAME_SIZE);
1606 if (!cam->frame_buf)
1609 for (i = 0; i < FRAME_NUM; i++)
1610 cam->frame[i].data = cam->frame_buf + i * CPIA_MAX_FRAME_SIZE;
1615 static int free_frame_buf(struct cam_data *cam)
1619 rvfree(cam->frame_buf, FRAME_NUM*CPIA_MAX_FRAME_SIZE);
1620 cam->frame_buf = NULL;
1621 for (i=0; i < FRAME_NUM; i++)
1622 cam->frame[i].data = NULL;
1628 static inline void free_frames(struct cpia_frame frame[FRAME_NUM])
1632 for (i=0; i < FRAME_NUM; i++)
1633 frame[i].state = FRAME_UNUSED;
1637 /**********************************************************************
1641 **********************************************************************/
1642 /* send an arbitrary command to the camera */
1643 static int do_command(struct cam_data *cam, u16 command, u8 a, u8 b, u8 c, u8 d)
1645 int retval, datasize;
1649 case CPIA_COMMAND_GetCPIAVersion:
1650 case CPIA_COMMAND_GetPnPID:
1651 case CPIA_COMMAND_GetCameraStatus:
1652 case CPIA_COMMAND_GetVPVersion:
1655 case CPIA_COMMAND_GetColourParams:
1656 case CPIA_COMMAND_GetColourBalance:
1657 case CPIA_COMMAND_GetExposure:
1658 mutex_lock(&cam->param_lock);
1661 case CPIA_COMMAND_ReadMCPorts:
1662 case CPIA_COMMAND_ReadVCRegs:
1670 cmd[0] = command>>8;
1671 cmd[1] = command&0xff;
1679 retval = cam->ops->transferCmd(cam->lowlevel_data, cmd, data);
1681 DBG("%x - failed, retval=%d\n", command, retval);
1682 if (command == CPIA_COMMAND_GetColourParams ||
1683 command == CPIA_COMMAND_GetColourBalance ||
1684 command == CPIA_COMMAND_GetExposure)
1685 mutex_unlock(&cam->param_lock);
1688 case CPIA_COMMAND_GetCPIAVersion:
1689 cam->params.version.firmwareVersion = data[0];
1690 cam->params.version.firmwareRevision = data[1];
1691 cam->params.version.vcVersion = data[2];
1692 cam->params.version.vcRevision = data[3];
1694 case CPIA_COMMAND_GetPnPID:
1695 cam->params.pnpID.vendor = data[0]+(((u16)data[1])<<8);
1696 cam->params.pnpID.product = data[2]+(((u16)data[3])<<8);
1697 cam->params.pnpID.deviceRevision =
1698 data[4]+(((u16)data[5])<<8);
1700 case CPIA_COMMAND_GetCameraStatus:
1701 cam->params.status.systemState = data[0];
1702 cam->params.status.grabState = data[1];
1703 cam->params.status.streamState = data[2];
1704 cam->params.status.fatalError = data[3];
1705 cam->params.status.cmdError = data[4];
1706 cam->params.status.debugFlags = data[5];
1707 cam->params.status.vpStatus = data[6];
1708 cam->params.status.errorCode = data[7];
1710 case CPIA_COMMAND_GetVPVersion:
1711 cam->params.vpVersion.vpVersion = data[0];
1712 cam->params.vpVersion.vpRevision = data[1];
1713 cam->params.vpVersion.cameraHeadID =
1714 data[2]+(((u16)data[3])<<8);
1716 case CPIA_COMMAND_GetColourParams:
1717 cam->params.colourParams.brightness = data[0];
1718 cam->params.colourParams.contrast = data[1];
1719 cam->params.colourParams.saturation = data[2];
1720 mutex_unlock(&cam->param_lock);
1722 case CPIA_COMMAND_GetColourBalance:
1723 cam->params.colourBalance.redGain = data[0];
1724 cam->params.colourBalance.greenGain = data[1];
1725 cam->params.colourBalance.blueGain = data[2];
1726 mutex_unlock(&cam->param_lock);
1728 case CPIA_COMMAND_GetExposure:
1729 cam->params.exposure.gain = data[0];
1730 cam->params.exposure.fineExp = data[1];
1731 cam->params.exposure.coarseExpLo = data[2];
1732 cam->params.exposure.coarseExpHi = data[3];
1733 cam->params.exposure.redComp = data[4];
1734 cam->params.exposure.green1Comp = data[5];
1735 cam->params.exposure.green2Comp = data[6];
1736 cam->params.exposure.blueComp = data[7];
1737 mutex_unlock(&cam->param_lock);
1740 case CPIA_COMMAND_ReadMCPorts:
1741 if (!cam->params.qx3.qx3_detected)
1743 /* test button press */
1744 cam->params.qx3.button = ((data[1] & 0x02) == 0);
1745 if (cam->params.qx3.button) {
1746 /* button pressed - unlock the latch */
1747 do_command(cam,CPIA_COMMAND_WriteMCPort,3,0xDF,0xDF,0);
1748 do_command(cam,CPIA_COMMAND_WriteMCPort,3,0xFF,0xFF,0);
1751 /* test whether microscope is cradled */
1752 cam->params.qx3.cradled = ((data[2] & 0x40) == 0);
1762 /* send a command to the camera with an additional data transaction */
1763 static int do_command_extended(struct cam_data *cam, u16 command,
1764 u8 a, u8 b, u8 c, u8 d,
1765 u8 e, u8 f, u8 g, u8 h,
1766 u8 i, u8 j, u8 k, u8 l)
1771 cmd[0] = command>>8;
1772 cmd[1] = command&0xff;
1788 retval = cam->ops->transferCmd(cam->lowlevel_data, cmd, data);
1790 DBG("%x - failed\n", command);
1795 /**********************************************************************
1797 * Colorspace conversion
1799 **********************************************************************/
1800 #define LIMIT(x) ((((x)>0xffffff)?0xff0000:(((x)<=0xffff)?0:(x)&0xff0000))>>16)
1802 static int convert420(unsigned char *yuv, unsigned char *rgb, int out_fmt,
1803 int linesize, int mmap_kludge)
1805 int y, u, v, r, g, b, y1;
1807 /* Odd lines use the same u and v as the previous line.
1808 * Because of compression, it is necessary to get this
1809 * information from the decoded image. */
1811 case VIDEO_PALETTE_RGB555:
1812 y = (*yuv++ - 16) * 76310;
1813 y1 = (*yuv - 16) * 76310;
1814 r = ((*(rgb+1-linesize)) & 0x7c) << 1;
1815 g = ((*(rgb-linesize)) & 0xe0) >> 4 |
1816 ((*(rgb+1-linesize)) & 0x03) << 6;
1817 b = ((*(rgb-linesize)) & 0x1f) << 3;
1818 u = (-53294 * r - 104635 * g + 157929 * b) / 5756495;
1819 v = (157968 * r - 132278 * g - 25690 * b) / 5366159;
1821 g = -25690 * u - 53294 * v;
1823 *rgb++ = ((LIMIT(g+y) & 0xf8) << 2) | (LIMIT(b+y) >> 3);
1824 *rgb++ = ((LIMIT(r+y) & 0xf8) >> 1) | (LIMIT(g+y) >> 6);
1825 *rgb++ = ((LIMIT(g+y1) & 0xf8) << 2) | (LIMIT(b+y1) >> 3);
1826 *rgb = ((LIMIT(r+y1) & 0xf8) >> 1) | (LIMIT(g+y1) >> 6);
1828 case VIDEO_PALETTE_RGB565:
1829 y = (*yuv++ - 16) * 76310;
1830 y1 = (*yuv - 16) * 76310;
1831 r = (*(rgb+1-linesize)) & 0xf8;
1832 g = ((*(rgb-linesize)) & 0xe0) >> 3 |
1833 ((*(rgb+1-linesize)) & 0x07) << 5;
1834 b = ((*(rgb-linesize)) & 0x1f) << 3;
1835 u = (-53294 * r - 104635 * g + 157929 * b) / 5756495;
1836 v = (157968 * r - 132278 * g - 25690 * b) / 5366159;
1838 g = -25690 * u - 53294 * v;
1840 *rgb++ = ((LIMIT(g+y) & 0xfc) << 3) | (LIMIT(b+y) >> 3);
1841 *rgb++ = (LIMIT(r+y) & 0xf8) | (LIMIT(g+y) >> 5);
1842 *rgb++ = ((LIMIT(g+y1) & 0xfc) << 3) | (LIMIT(b+y1) >> 3);
1843 *rgb = (LIMIT(r+y1) & 0xf8) | (LIMIT(g+y1) >> 5);
1846 case VIDEO_PALETTE_RGB24:
1847 case VIDEO_PALETTE_RGB32:
1848 y = (*yuv++ - 16) * 76310;
1849 y1 = (*yuv - 16) * 76310;
1851 r = *(rgb+2-linesize);
1852 g = *(rgb+1-linesize);
1853 b = *(rgb-linesize);
1855 r = *(rgb-linesize);
1856 g = *(rgb+1-linesize);
1857 b = *(rgb+2-linesize);
1859 u = (-53294 * r - 104635 * g + 157929 * b) / 5756495;
1860 v = (157968 * r - 132278 * g - 25690 * b) / 5366159;
1862 g = -25690 * u + -53294 * v;
1865 *rgb++ = LIMIT(b+y);
1866 *rgb++ = LIMIT(g+y);
1867 *rgb++ = LIMIT(r+y);
1868 if(out_fmt == VIDEO_PALETTE_RGB32)
1870 *rgb++ = LIMIT(b+y1);
1871 *rgb++ = LIMIT(g+y1);
1874 *rgb++ = LIMIT(r+y);
1875 *rgb++ = LIMIT(g+y);
1876 *rgb++ = LIMIT(b+y);
1877 if(out_fmt == VIDEO_PALETTE_RGB32)
1879 *rgb++ = LIMIT(r+y1);
1880 *rgb++ = LIMIT(g+y1);
1883 if(out_fmt == VIDEO_PALETTE_RGB32)
1886 case VIDEO_PALETTE_YUV422:
1887 case VIDEO_PALETTE_YUYV:
1889 u = *(rgb+1-linesize);
1891 v = *(rgb+3-linesize);
1897 case VIDEO_PALETTE_UYVY:
1898 u = *(rgb-linesize);
1900 v = *(rgb+2-linesize);
1907 case VIDEO_PALETTE_GREY:
1912 DBG("Empty: %d\n", out_fmt);
1918 static int yuvconvert(unsigned char *yuv, unsigned char *rgb, int out_fmt,
1919 int in_uyvy, int mmap_kludge)
1921 int y, u, v, r, g, b, y1;
1924 case VIDEO_PALETTE_RGB555:
1925 case VIDEO_PALETTE_RGB565:
1926 case VIDEO_PALETTE_RGB24:
1927 case VIDEO_PALETTE_RGB32:
1930 y = (*yuv++ - 16) * 76310;
1932 y1 = (*yuv - 16) * 76310;
1934 y = (*yuv++ - 16) * 76310;
1936 y1 = (*yuv++ - 16) * 76310;
1940 g = -25690 * u + -53294 * v;
1948 /* Just to avoid compiler warnings */
1955 case VIDEO_PALETTE_RGB555:
1956 *rgb++ = ((LIMIT(g+y) & 0xf8) << 2) | (LIMIT(b+y) >> 3);
1957 *rgb++ = ((LIMIT(r+y) & 0xf8) >> 1) | (LIMIT(g+y) >> 6);
1958 *rgb++ = ((LIMIT(g+y1) & 0xf8) << 2) | (LIMIT(b+y1) >> 3);
1959 *rgb = ((LIMIT(r+y1) & 0xf8) >> 1) | (LIMIT(g+y1) >> 6);
1961 case VIDEO_PALETTE_RGB565:
1962 *rgb++ = ((LIMIT(g+y) & 0xfc) << 3) | (LIMIT(b+y) >> 3);
1963 *rgb++ = (LIMIT(r+y) & 0xf8) | (LIMIT(g+y) >> 5);
1964 *rgb++ = ((LIMIT(g+y1) & 0xfc) << 3) | (LIMIT(b+y1) >> 3);
1965 *rgb = (LIMIT(r+y1) & 0xf8) | (LIMIT(g+y1) >> 5);
1967 case VIDEO_PALETTE_RGB24:
1969 *rgb++ = LIMIT(b+y);
1970 *rgb++ = LIMIT(g+y);
1971 *rgb++ = LIMIT(r+y);
1972 *rgb++ = LIMIT(b+y1);
1973 *rgb++ = LIMIT(g+y1);
1976 *rgb++ = LIMIT(r+y);
1977 *rgb++ = LIMIT(g+y);
1978 *rgb++ = LIMIT(b+y);
1979 *rgb++ = LIMIT(r+y1);
1980 *rgb++ = LIMIT(g+y1);
1984 case VIDEO_PALETTE_RGB32:
1986 *rgb++ = LIMIT(b+y);
1987 *rgb++ = LIMIT(g+y);
1988 *rgb++ = LIMIT(r+y);
1990 *rgb++ = LIMIT(b+y1);
1991 *rgb++ = LIMIT(g+y1);
1994 *rgb++ = LIMIT(r+y);
1995 *rgb++ = LIMIT(g+y);
1996 *rgb++ = LIMIT(b+y);
1998 *rgb++ = LIMIT(r+y1);
1999 *rgb++ = LIMIT(g+y1);
2003 case VIDEO_PALETTE_GREY:
2007 case VIDEO_PALETTE_YUV422:
2008 case VIDEO_PALETTE_YUYV:
2014 case VIDEO_PALETTE_UYVY:
2021 DBG("Empty: %d\n", out_fmt);
2026 static int skipcount(int count, int fmt)
2029 case VIDEO_PALETTE_GREY:
2031 case VIDEO_PALETTE_RGB555:
2032 case VIDEO_PALETTE_RGB565:
2033 case VIDEO_PALETTE_YUV422:
2034 case VIDEO_PALETTE_YUYV:
2035 case VIDEO_PALETTE_UYVY:
2037 case VIDEO_PALETTE_RGB24:
2039 case VIDEO_PALETTE_RGB32:
2046 static int parse_picture(struct cam_data *cam, int size)
2048 u8 *obuf, *ibuf, *end_obuf;
2049 int ll, in_uyvy, compressed, decimation, even_line, origsize, out_fmt;
2050 int rows, cols, linesize, subsample_422;
2052 /* make sure params don't change while we are decoding */
2053 mutex_lock(&cam->param_lock);
2055 obuf = cam->decompressed_frame.data;
2056 end_obuf = obuf+CPIA_MAX_FRAME_SIZE;
2057 ibuf = cam->raw_image;
2059 out_fmt = cam->vp.palette;
2061 if ((ibuf[0] != MAGIC_0) || (ibuf[1] != MAGIC_1)) {
2062 LOG("header not found\n");
2063 mutex_unlock(&cam->param_lock);
2067 if ((ibuf[16] != VIDEOSIZE_QCIF) && (ibuf[16] != VIDEOSIZE_CIF)) {
2068 LOG("wrong video size\n");
2069 mutex_unlock(&cam->param_lock);
2073 if (ibuf[17] != SUBSAMPLE_420 && ibuf[17] != SUBSAMPLE_422) {
2074 LOG("illegal subtype %d\n",ibuf[17]);
2075 mutex_unlock(&cam->param_lock);
2078 subsample_422 = ibuf[17] == SUBSAMPLE_422;
2080 if (ibuf[18] != YUVORDER_YUYV && ibuf[18] != YUVORDER_UYVY) {
2081 LOG("illegal yuvorder %d\n",ibuf[18]);
2082 mutex_unlock(&cam->param_lock);
2085 in_uyvy = ibuf[18] == YUVORDER_UYVY;
2087 if ((ibuf[24] != cam->params.roi.colStart) ||
2088 (ibuf[25] != cam->params.roi.colEnd) ||
2089 (ibuf[26] != cam->params.roi.rowStart) ||
2090 (ibuf[27] != cam->params.roi.rowEnd)) {
2091 LOG("ROI mismatch\n");
2092 mutex_unlock(&cam->param_lock);
2095 cols = 8*(ibuf[25] - ibuf[24]);
2096 rows = 4*(ibuf[27] - ibuf[26]);
2099 if ((ibuf[28] != NOT_COMPRESSED) && (ibuf[28] != COMPRESSED)) {
2100 LOG("illegal compression %d\n",ibuf[28]);
2101 mutex_unlock(&cam->param_lock);
2104 compressed = (ibuf[28] == COMPRESSED);
2106 if (ibuf[29] != NO_DECIMATION && ibuf[29] != DECIMATION_ENAB) {
2107 LOG("illegal decimation %d\n",ibuf[29]);
2108 mutex_unlock(&cam->param_lock);
2111 decimation = (ibuf[29] == DECIMATION_ENAB);
2113 cam->params.yuvThreshold.yThreshold = ibuf[30];
2114 cam->params.yuvThreshold.uvThreshold = ibuf[31];
2115 cam->params.status.systemState = ibuf[32];
2116 cam->params.status.grabState = ibuf[33];
2117 cam->params.status.streamState = ibuf[34];
2118 cam->params.status.fatalError = ibuf[35];
2119 cam->params.status.cmdError = ibuf[36];
2120 cam->params.status.debugFlags = ibuf[37];
2121 cam->params.status.vpStatus = ibuf[38];
2122 cam->params.status.errorCode = ibuf[39];
2123 cam->fps = ibuf[41];
2124 mutex_unlock(&cam->param_lock);
2126 linesize = skipcount(cols, out_fmt);
2127 ibuf += FRAME_HEADER_SIZE;
2128 size -= FRAME_HEADER_SIZE;
2129 ll = ibuf[0] | (ibuf[1] << 8);
2136 LOG("Insufficient data in buffer\n");
2141 if (!compressed || (compressed && !(*ibuf & 1))) {
2142 if(subsample_422 || even_line) {
2143 obuf += yuvconvert(ibuf, obuf, out_fmt,
2144 in_uyvy, cam->mmap_kludge);
2148 /* SUBSAMPLE_420 on an odd line */
2149 obuf += convert420(ibuf, obuf,
2156 /*skip compressed interval from previous frame*/
2157 obuf += skipcount(*ibuf >> 1, out_fmt);
2158 if (obuf > end_obuf) {
2159 LOG("Insufficient buffer size\n");
2168 DBG("EOL not found giving up after %d/%d"
2169 " bytes\n", origsize-size, origsize);
2173 ++ibuf; /* skip over EOL */
2175 if ((size > 3) && (ibuf[0] == EOI) && (ibuf[1] == EOI) &&
2176 (ibuf[2] == EOI) && (ibuf[3] == EOI)) {
2182 /* skip the odd lines for now */
2187 ll = ibuf[0] | (ibuf[1] << 8);
2188 ibuf += 2; /* skip over line length */
2191 even_line = !even_line;
2193 LOG("line length was not 1 but %d after %d/%d bytes\n",
2194 ll, origsize-size, origsize);
2200 /* interpolate odd rows */
2203 prev = cam->decompressed_frame.data;
2204 obuf = prev+linesize;
2205 next = obuf+linesize;
2206 for(i=1; i<rows-1; i+=2) {
2207 for(j=0; j<linesize; ++j) {
2208 *obuf++ = ((int)*prev++ + *next++) / 2;
2214 /* last row is odd, just copy previous row */
2215 memcpy(obuf, prev, linesize);
2218 cam->decompressed_frame.count = obuf-cam->decompressed_frame.data;
2220 return cam->decompressed_frame.count;
2223 /* InitStreamCap wrapper to select correct start line */
2224 static inline int init_stream_cap(struct cam_data *cam)
2226 return do_command(cam, CPIA_COMMAND_InitStreamCap,
2227 0, cam->params.streamStartLine, 0, 0);
2231 /* find_over_exposure
2232 * Finds a suitable value of OverExposure for use with SetFlickerCtrl
2233 * Some calculation is required because this value changes with the brightness
2234 * set with SetColourParameters
2236 * Parameters: Brightness - last brightness value set with SetColourParameters
2238 * Returns: OverExposure value to use with SetFlickerCtrl
2240 #define FLICKER_MAX_EXPOSURE 250
2241 #define FLICKER_ALLOWABLE_OVER_EXPOSURE 146
2242 #define FLICKER_BRIGHTNESS_CONSTANT 59
2243 static int find_over_exposure(int brightness)
2245 int MaxAllowableOverExposure, OverExposure;
2247 MaxAllowableOverExposure = FLICKER_MAX_EXPOSURE - brightness -
2248 FLICKER_BRIGHTNESS_CONSTANT;
2250 if (MaxAllowableOverExposure < FLICKER_ALLOWABLE_OVER_EXPOSURE) {
2251 OverExposure = MaxAllowableOverExposure;
2253 OverExposure = FLICKER_ALLOWABLE_OVER_EXPOSURE;
2256 return OverExposure;
2258 #undef FLICKER_MAX_EXPOSURE
2259 #undef FLICKER_ALLOWABLE_OVER_EXPOSURE
2260 #undef FLICKER_BRIGHTNESS_CONSTANT
2262 /* update various camera modes and settings */
2263 static void dispatch_commands(struct cam_data *cam)
2265 mutex_lock(&cam->param_lock);
2266 if (cam->cmd_queue==COMMAND_NONE) {
2267 mutex_unlock(&cam->param_lock);
2270 DEB_BYTE(cam->cmd_queue);
2271 DEB_BYTE(cam->cmd_queue>>8);
2272 if (cam->cmd_queue & COMMAND_SETFORMAT) {
2273 do_command(cam, CPIA_COMMAND_SetFormat,
2274 cam->params.format.videoSize,
2275 cam->params.format.subSample,
2276 cam->params.format.yuvOrder, 0);
2277 do_command(cam, CPIA_COMMAND_SetROI,
2278 cam->params.roi.colStart, cam->params.roi.colEnd,
2279 cam->params.roi.rowStart, cam->params.roi.rowEnd);
2280 cam->first_frame = 1;
2283 if (cam->cmd_queue & COMMAND_SETCOLOURPARAMS)
2284 do_command(cam, CPIA_COMMAND_SetColourParams,
2285 cam->params.colourParams.brightness,
2286 cam->params.colourParams.contrast,
2287 cam->params.colourParams.saturation, 0);
2289 if (cam->cmd_queue & COMMAND_SETAPCOR)
2290 do_command(cam, CPIA_COMMAND_SetApcor,
2291 cam->params.apcor.gain1,
2292 cam->params.apcor.gain2,
2293 cam->params.apcor.gain4,
2294 cam->params.apcor.gain8);
2296 if (cam->cmd_queue & COMMAND_SETVLOFFSET)
2297 do_command(cam, CPIA_COMMAND_SetVLOffset,
2298 cam->params.vlOffset.gain1,
2299 cam->params.vlOffset.gain2,
2300 cam->params.vlOffset.gain4,
2301 cam->params.vlOffset.gain8);
2303 if (cam->cmd_queue & COMMAND_SETEXPOSURE) {
2304 do_command_extended(cam, CPIA_COMMAND_SetExposure,
2305 cam->params.exposure.gainMode,
2307 cam->params.exposure.compMode,
2308 cam->params.exposure.centreWeight,
2309 cam->params.exposure.gain,
2310 cam->params.exposure.fineExp,
2311 cam->params.exposure.coarseExpLo,
2312 cam->params.exposure.coarseExpHi,
2313 cam->params.exposure.redComp,
2314 cam->params.exposure.green1Comp,
2315 cam->params.exposure.green2Comp,
2316 cam->params.exposure.blueComp);
2317 if(cam->params.exposure.expMode != 1) {
2318 do_command_extended(cam, CPIA_COMMAND_SetExposure,
2320 cam->params.exposure.expMode,
2322 cam->params.exposure.gain,
2323 cam->params.exposure.fineExp,
2324 cam->params.exposure.coarseExpLo,
2325 cam->params.exposure.coarseExpHi,
2330 if (cam->cmd_queue & COMMAND_SETCOLOURBALANCE) {
2331 if (cam->params.colourBalance.balanceMode == 1) {
2332 do_command(cam, CPIA_COMMAND_SetColourBalance,
2334 cam->params.colourBalance.redGain,
2335 cam->params.colourBalance.greenGain,
2336 cam->params.colourBalance.blueGain);
2337 do_command(cam, CPIA_COMMAND_SetColourBalance,
2340 if (cam->params.colourBalance.balanceMode == 2) {
2341 do_command(cam, CPIA_COMMAND_SetColourBalance,
2344 if (cam->params.colourBalance.balanceMode == 3) {
2345 do_command(cam, CPIA_COMMAND_SetColourBalance,
2350 if (cam->cmd_queue & COMMAND_SETCOMPRESSIONTARGET)
2351 do_command(cam, CPIA_COMMAND_SetCompressionTarget,
2352 cam->params.compressionTarget.frTargeting,
2353 cam->params.compressionTarget.targetFR,
2354 cam->params.compressionTarget.targetQ, 0);
2356 if (cam->cmd_queue & COMMAND_SETYUVTHRESH)
2357 do_command(cam, CPIA_COMMAND_SetYUVThresh,
2358 cam->params.yuvThreshold.yThreshold,
2359 cam->params.yuvThreshold.uvThreshold, 0, 0);
2361 if (cam->cmd_queue & COMMAND_SETCOMPRESSIONPARAMS)
2362 do_command_extended(cam, CPIA_COMMAND_SetCompressionParams,
2364 cam->params.compressionParams.hysteresis,
2365 cam->params.compressionParams.threshMax,
2366 cam->params.compressionParams.smallStep,
2367 cam->params.compressionParams.largeStep,
2368 cam->params.compressionParams.decimationHysteresis,
2369 cam->params.compressionParams.frDiffStepThresh,
2370 cam->params.compressionParams.qDiffStepThresh,
2371 cam->params.compressionParams.decimationThreshMod);
2373 if (cam->cmd_queue & COMMAND_SETCOMPRESSION)
2374 do_command(cam, CPIA_COMMAND_SetCompression,
2375 cam->params.compression.mode,
2376 cam->params.compression.decimation, 0, 0);
2378 if (cam->cmd_queue & COMMAND_SETSENSORFPS)
2379 do_command(cam, CPIA_COMMAND_SetSensorFPS,
2380 cam->params.sensorFps.divisor,
2381 cam->params.sensorFps.baserate, 0, 0);
2383 if (cam->cmd_queue & COMMAND_SETFLICKERCTRL)
2384 do_command(cam, CPIA_COMMAND_SetFlickerCtrl,
2385 cam->params.flickerControl.flickerMode,
2386 cam->params.flickerControl.coarseJump,
2387 abs(cam->params.flickerControl.allowableOverExposure),
2390 if (cam->cmd_queue & COMMAND_SETECPTIMING)
2391 do_command(cam, CPIA_COMMAND_SetECPTiming,
2392 cam->params.ecpTiming, 0, 0, 0);
2394 if (cam->cmd_queue & COMMAND_PAUSE)
2395 do_command(cam, CPIA_COMMAND_EndStreamCap, 0, 0, 0, 0);
2397 if (cam->cmd_queue & COMMAND_RESUME)
2398 init_stream_cap(cam);
2400 if (cam->cmd_queue & COMMAND_SETLIGHTS && cam->params.qx3.qx3_detected)
2402 int p1 = (cam->params.qx3.bottomlight == 0) << 1;
2403 int p2 = (cam->params.qx3.toplight == 0) << 3;
2404 do_command(cam, CPIA_COMMAND_WriteVCReg, 0x90, 0x8F, 0x50, 0);
2405 do_command(cam, CPIA_COMMAND_WriteMCPort, 2, 0, (p1|p2|0xE0), 0);
2408 cam->cmd_queue = COMMAND_NONE;
2409 mutex_unlock(&cam->param_lock);
2415 static void set_flicker(struct cam_params *params, volatile u32 *command_flags,
2418 /* Everything in here is from the Windows driver */
2419 #define FIRMWARE_VERSION(x,y) (params->version.firmwareVersion == (x) && \
2420 params->version.firmwareRevision == (y))
2421 /* define for compgain calculation */
2423 #define COMPGAIN(base, curexp, newexp) \
2424 (u8) ((((float) base - 128.0) * ((float) curexp / (float) newexp)) + 128.5)
2425 #define EXP_FROM_COMP(basecomp, curcomp, curexp) \
2426 (u16)((float)curexp * (float)(u8)(curcomp + 128) / (float)(u8)(basecomp - 128))
2428 /* equivalent functions without floating point math */
2429 #define COMPGAIN(base, curexp, newexp) \
2430 (u8)(128 + (((u32)(2*(base-128)*curexp + newexp)) / (2* newexp)) )
2431 #define EXP_FROM_COMP(basecomp, curcomp, curexp) \
2432 (u16)(((u32)(curexp * (u8)(curcomp + 128)) / (u8)(basecomp - 128)))
2436 int currentexp = params->exposure.coarseExpLo +
2437 params->exposure.coarseExpHi*256;
2440 int cj = params->flickerControl.coarseJump;
2441 params->flickerControl.flickerMode = 1;
2442 params->flickerControl.disabled = 0;
2443 if(params->exposure.expMode != 2)
2444 *command_flags |= COMMAND_SETEXPOSURE;
2445 params->exposure.expMode = 2;
2446 currentexp = currentexp << params->exposure.gain;
2447 params->exposure.gain = 0;
2448 /* round down current exposure to nearest value */
2449 startexp = (currentexp + ROUND_UP_EXP_FOR_FLICKER) / cj;
2452 startexp = (startexp * cj) - 1;
2453 if(FIRMWARE_VERSION(1,2))
2454 while(startexp > MAX_EXP_102)
2457 while(startexp > MAX_EXP)
2459 params->exposure.coarseExpLo = startexp & 0xff;
2460 params->exposure.coarseExpHi = startexp >> 8;
2461 if (currentexp > startexp) {
2462 if (currentexp > (2 * startexp))
2463 currentexp = 2 * startexp;
2464 params->exposure.redComp = COMPGAIN (COMP_RED, currentexp, startexp);
2465 params->exposure.green1Comp = COMPGAIN (COMP_GREEN1, currentexp, startexp);
2466 params->exposure.green2Comp = COMPGAIN (COMP_GREEN2, currentexp, startexp);
2467 params->exposure.blueComp = COMPGAIN (COMP_BLUE, currentexp, startexp);
2469 params->exposure.redComp = COMP_RED;
2470 params->exposure.green1Comp = COMP_GREEN1;
2471 params->exposure.green2Comp = COMP_GREEN2;
2472 params->exposure.blueComp = COMP_BLUE;
2474 if(FIRMWARE_VERSION(1,2))
2475 params->exposure.compMode = 0;
2477 params->exposure.compMode = 1;
2479 params->apcor.gain1 = 0x18;
2480 params->apcor.gain2 = 0x18;
2481 params->apcor.gain4 = 0x16;
2482 params->apcor.gain8 = 0x14;
2483 *command_flags |= COMMAND_SETAPCOR;
2485 params->flickerControl.flickerMode = 0;
2486 params->flickerControl.disabled = 1;
2487 /* Coarse = average of equivalent coarse for each comp channel */
2488 startexp = EXP_FROM_COMP(COMP_RED, params->exposure.redComp, currentexp);
2489 startexp += EXP_FROM_COMP(COMP_GREEN1, params->exposure.green1Comp, currentexp);
2490 startexp += EXP_FROM_COMP(COMP_GREEN2, params->exposure.green2Comp, currentexp);
2491 startexp += EXP_FROM_COMP(COMP_BLUE, params->exposure.blueComp, currentexp);
2492 startexp = startexp >> 2;
2493 while(startexp > MAX_EXP &&
2494 params->exposure.gain < params->exposure.gainMode-1) {
2495 startexp = startexp >> 1;
2496 ++params->exposure.gain;
2498 if(FIRMWARE_VERSION(1,2) && startexp > MAX_EXP_102)
2499 startexp = MAX_EXP_102;
2500 if(startexp > MAX_EXP)
2502 params->exposure.coarseExpLo = startexp&0xff;
2503 params->exposure.coarseExpHi = startexp >> 8;
2504 params->exposure.redComp = COMP_RED;
2505 params->exposure.green1Comp = COMP_GREEN1;
2506 params->exposure.green2Comp = COMP_GREEN2;
2507 params->exposure.blueComp = COMP_BLUE;
2508 params->exposure.compMode = 1;
2509 *command_flags |= COMMAND_SETEXPOSURE;
2510 params->apcor.gain1 = 0x18;
2511 params->apcor.gain2 = 0x16;
2512 params->apcor.gain4 = 0x24;
2513 params->apcor.gain8 = 0x34;
2514 *command_flags |= COMMAND_SETAPCOR;
2516 params->vlOffset.gain1 = 20;
2517 params->vlOffset.gain2 = 24;
2518 params->vlOffset.gain4 = 26;
2519 params->vlOffset.gain8 = 26;
2520 *command_flags |= COMMAND_SETVLOFFSET;
2521 #undef FIRMWARE_VERSION
2522 #undef EXP_FROM_COMP
2526 #define FIRMWARE_VERSION(x,y) (cam->params.version.firmwareVersion == (x) && \
2527 cam->params.version.firmwareRevision == (y))
2528 /* monitor the exposure and adjust the sensor frame rate if needed */
2529 static void monitor_exposure(struct cam_data *cam)
2531 u8 exp_acc, bcomp, gain, coarseL, cmd[8], data[8];
2532 int retval, light_exp, dark_exp, very_dark_exp;
2533 int old_exposure, new_exposure, framerate;
2535 /* get necessary stats and register settings from camera */
2536 /* do_command can't handle this, so do it ourselves */
2537 cmd[0] = CPIA_COMMAND_ReadVPRegs>>8;
2538 cmd[1] = CPIA_COMMAND_ReadVPRegs&0xff;
2545 retval = cam->ops->transferCmd(cam->lowlevel_data, cmd, data);
2547 LOG("ReadVPRegs(30,4,9,8) - failed, retval=%d\n",
2556 mutex_lock(&cam->param_lock);
2557 light_exp = cam->params.colourParams.brightness +
2558 TC - 50 + EXP_ACC_LIGHT;
2561 dark_exp = cam->params.colourParams.brightness +
2562 TC - 50 - EXP_ACC_DARK;
2565 very_dark_exp = dark_exp/2;
2567 old_exposure = cam->params.exposure.coarseExpHi * 256 +
2568 cam->params.exposure.coarseExpLo;
2570 if(!cam->params.flickerControl.disabled) {
2571 /* Flicker control on */
2572 int max_comp = FIRMWARE_VERSION(1,2) ? MAX_COMP : HIGH_COMP_102;
2573 bcomp += 128; /* decode */
2574 if(bcomp >= max_comp && exp_acc < dark_exp) {
2576 if(exp_acc < very_dark_exp) {
2578 if(cam->exposure_status == EXPOSURE_VERY_DARK)
2579 ++cam->exposure_count;
2581 cam->exposure_status = EXPOSURE_VERY_DARK;
2582 cam->exposure_count = 1;
2586 if(cam->exposure_status == EXPOSURE_DARK)
2587 ++cam->exposure_count;
2589 cam->exposure_status = EXPOSURE_DARK;
2590 cam->exposure_count = 1;
2593 } else if(old_exposure <= LOW_EXP || exp_acc > light_exp) {
2595 if(old_exposure <= VERY_LOW_EXP) {
2597 if(cam->exposure_status == EXPOSURE_VERY_LIGHT)
2598 ++cam->exposure_count;
2600 cam->exposure_status = EXPOSURE_VERY_LIGHT;
2601 cam->exposure_count = 1;
2605 if(cam->exposure_status == EXPOSURE_LIGHT)
2606 ++cam->exposure_count;
2608 cam->exposure_status = EXPOSURE_LIGHT;
2609 cam->exposure_count = 1;
2613 /* not dark or light */
2614 cam->exposure_status = EXPOSURE_NORMAL;
2617 /* Flicker control off */
2618 if(old_exposure >= MAX_EXP && exp_acc < dark_exp) {
2620 if(exp_acc < very_dark_exp) {
2622 if(cam->exposure_status == EXPOSURE_VERY_DARK)
2623 ++cam->exposure_count;
2625 cam->exposure_status = EXPOSURE_VERY_DARK;
2626 cam->exposure_count = 1;
2630 if(cam->exposure_status == EXPOSURE_DARK)
2631 ++cam->exposure_count;
2633 cam->exposure_status = EXPOSURE_DARK;
2634 cam->exposure_count = 1;
2637 } else if(old_exposure <= LOW_EXP || exp_acc > light_exp) {
2639 if(old_exposure <= VERY_LOW_EXP) {
2641 if(cam->exposure_status == EXPOSURE_VERY_LIGHT)
2642 ++cam->exposure_count;
2644 cam->exposure_status = EXPOSURE_VERY_LIGHT;
2645 cam->exposure_count = 1;
2649 if(cam->exposure_status == EXPOSURE_LIGHT)
2650 ++cam->exposure_count;
2652 cam->exposure_status = EXPOSURE_LIGHT;
2653 cam->exposure_count = 1;
2657 /* not dark or light */
2658 cam->exposure_status = EXPOSURE_NORMAL;
2662 framerate = cam->fps;
2663 if(framerate > 30 || framerate < 1)
2666 if(!cam->params.flickerControl.disabled) {
2667 /* Flicker control on */
2668 if((cam->exposure_status == EXPOSURE_VERY_DARK ||
2669 cam->exposure_status == EXPOSURE_DARK) &&
2670 cam->exposure_count >= DARK_TIME*framerate &&
2671 cam->params.sensorFps.divisor < 3) {
2673 /* dark for too long */
2674 ++cam->params.sensorFps.divisor;
2675 cam->cmd_queue |= COMMAND_SETSENSORFPS;
2677 cam->params.flickerControl.coarseJump =
2678 flicker_jumps[cam->mainsFreq]
2679 [cam->params.sensorFps.baserate]
2680 [cam->params.sensorFps.divisor];
2681 cam->cmd_queue |= COMMAND_SETFLICKERCTRL;
2683 new_exposure = cam->params.flickerControl.coarseJump-1;
2684 while(new_exposure < old_exposure/2)
2685 new_exposure += cam->params.flickerControl.coarseJump;
2686 cam->params.exposure.coarseExpLo = new_exposure & 0xff;
2687 cam->params.exposure.coarseExpHi = new_exposure >> 8;
2688 cam->cmd_queue |= COMMAND_SETEXPOSURE;
2689 cam->exposure_status = EXPOSURE_NORMAL;
2690 LOG("Automatically decreasing sensor_fps\n");
2692 } else if((cam->exposure_status == EXPOSURE_VERY_LIGHT ||
2693 cam->exposure_status == EXPOSURE_LIGHT) &&
2694 cam->exposure_count >= LIGHT_TIME*framerate &&
2695 cam->params.sensorFps.divisor > 0) {
2697 /* light for too long */
2698 int max_exp = FIRMWARE_VERSION(1,2) ? MAX_EXP_102 : MAX_EXP ;
2700 --cam->params.sensorFps.divisor;
2701 cam->cmd_queue |= COMMAND_SETSENSORFPS;
2703 cam->params.flickerControl.coarseJump =
2704 flicker_jumps[cam->mainsFreq]
2705 [cam->params.sensorFps.baserate]
2706 [cam->params.sensorFps.divisor];
2707 cam->cmd_queue |= COMMAND_SETFLICKERCTRL;
2709 new_exposure = cam->params.flickerControl.coarseJump-1;
2710 while(new_exposure < 2*old_exposure &&
2712 cam->params.flickerControl.coarseJump < max_exp)
2713 new_exposure += cam->params.flickerControl.coarseJump;
2714 cam->params.exposure.coarseExpLo = new_exposure & 0xff;
2715 cam->params.exposure.coarseExpHi = new_exposure >> 8;
2716 cam->cmd_queue |= COMMAND_SETEXPOSURE;
2717 cam->exposure_status = EXPOSURE_NORMAL;
2718 LOG("Automatically increasing sensor_fps\n");
2721 /* Flicker control off */
2722 if((cam->exposure_status == EXPOSURE_VERY_DARK ||
2723 cam->exposure_status == EXPOSURE_DARK) &&
2724 cam->exposure_count >= DARK_TIME*framerate &&
2725 cam->params.sensorFps.divisor < 3) {
2727 /* dark for too long */
2728 ++cam->params.sensorFps.divisor;
2729 cam->cmd_queue |= COMMAND_SETSENSORFPS;
2731 if(cam->params.exposure.gain > 0) {
2732 --cam->params.exposure.gain;
2733 cam->cmd_queue |= COMMAND_SETEXPOSURE;
2735 cam->exposure_status = EXPOSURE_NORMAL;
2736 LOG("Automatically decreasing sensor_fps\n");
2738 } else if((cam->exposure_status == EXPOSURE_VERY_LIGHT ||
2739 cam->exposure_status == EXPOSURE_LIGHT) &&
2740 cam->exposure_count >= LIGHT_TIME*framerate &&
2741 cam->params.sensorFps.divisor > 0) {
2743 /* light for too long */
2744 --cam->params.sensorFps.divisor;
2745 cam->cmd_queue |= COMMAND_SETSENSORFPS;
2747 if(cam->params.exposure.gain <
2748 cam->params.exposure.gainMode-1) {
2749 ++cam->params.exposure.gain;
2750 cam->cmd_queue |= COMMAND_SETEXPOSURE;
2752 cam->exposure_status = EXPOSURE_NORMAL;
2753 LOG("Automatically increasing sensor_fps\n");
2756 mutex_unlock(&cam->param_lock);
2759 /*-----------------------------------------------------------------*/
2760 /* if flicker is switched off, this function switches it back on.It checks,
2761 however, that conditions are suitable before restarting it.
2762 This should only be called for firmware version 1.2.
2764 It also adjust the colour balance when an exposure step is detected - as
2765 long as flicker is running
2767 static void restart_flicker(struct cam_data *cam)
2769 int cam_exposure, old_exp;
2770 if(!FIRMWARE_VERSION(1,2))
2772 mutex_lock(&cam->param_lock);
2773 if(cam->params.flickerControl.flickerMode == 0 ||
2774 cam->raw_image[39] == 0) {
2775 mutex_unlock(&cam->param_lock);
2778 cam_exposure = cam->raw_image[39]*2;
2779 old_exp = cam->params.exposure.coarseExpLo +
2780 cam->params.exposure.coarseExpHi*256;
2782 see how far away camera exposure is from a valid
2783 flicker exposure value
2785 cam_exposure %= cam->params.flickerControl.coarseJump;
2786 if(!cam->params.flickerControl.disabled &&
2787 cam_exposure <= cam->params.flickerControl.coarseJump - 3) {
2788 /* Flicker control auto-disabled */
2789 cam->params.flickerControl.disabled = 1;
2792 if(cam->params.flickerControl.disabled &&
2793 cam->params.flickerControl.flickerMode &&
2794 old_exp > cam->params.flickerControl.coarseJump +
2795 ROUND_UP_EXP_FOR_FLICKER) {
2796 /* exposure is now high enough to switch
2797 flicker control back on */
2798 set_flicker(&cam->params, &cam->cmd_queue, 1);
2799 if((cam->cmd_queue & COMMAND_SETEXPOSURE) &&
2800 cam->params.exposure.expMode == 2)
2801 cam->exposure_status = EXPOSURE_NORMAL;
2804 mutex_unlock(&cam->param_lock);
2806 #undef FIRMWARE_VERSION
2808 static int clear_stall(struct cam_data *cam)
2810 /* FIXME: Does this actually work? */
2811 LOG("Clearing stall\n");
2813 cam->ops->streamRead(cam->lowlevel_data, cam->raw_image, 0);
2814 do_command(cam, CPIA_COMMAND_GetCameraStatus,0,0,0,0);
2815 return cam->params.status.streamState != STREAM_PAUSED;
2818 /* kernel thread function to read image from camera */
2819 static int fetch_frame(void *data)
2821 int image_size, retry;
2822 struct cam_data *cam = (struct cam_data *)data;
2823 unsigned long oldjif, rate, diff;
2825 /* Allow up to two bad images in a row to be read and
2826 * ignored before an error is reported */
2827 for (retry = 0; retry < 3; ++retry) {
2829 DBG("retry=%d\n", retry);
2834 /* load first frame always uncompressed */
2835 if (cam->first_frame &&
2836 cam->params.compression.mode != CPIA_COMPRESSION_NONE) {
2837 do_command(cam, CPIA_COMMAND_SetCompression,
2838 CPIA_COMPRESSION_NONE,
2839 NO_DECIMATION, 0, 0);
2840 /* Trial & error - Discarding a frame prevents the
2841 first frame from having an error in the data. */
2842 do_command(cam, CPIA_COMMAND_DiscardFrame, 0, 0, 0, 0);
2845 /* init camera upload */
2846 if (do_command(cam, CPIA_COMMAND_GrabFrame, 0,
2847 cam->params.streamStartLine, 0, 0))
2850 if (cam->ops->wait_for_stream_ready) {
2851 /* loop until image ready */
2853 do_command(cam, CPIA_COMMAND_GetCameraStatus,0,0,0,0);
2854 while (cam->params.status.streamState != STREAM_READY) {
2855 if(++count > READY_TIMEOUT)
2857 if(cam->params.status.streamState ==
2860 if(!clear_stall(cam))
2866 /* sleep for 10 ms, hopefully ;) */
2867 msleep_interruptible(10);
2868 if (signal_pending(current))
2871 do_command(cam, CPIA_COMMAND_GetCameraStatus,
2874 if(cam->params.status.streamState != STREAM_READY) {
2881 /* grab image from camera */
2883 image_size = cam->ops->streamRead(cam->lowlevel_data,
2885 if (image_size <= 0) {
2886 DBG("streamRead failed: %d\n", image_size);
2890 rate = image_size * HZ / 1024;
2891 diff = jiffies-oldjif;
2892 cam->transfer_rate = diff==0 ? rate : rate/diff;
2893 /* diff==0 ? unlikely but possible */
2895 /* Switch flicker control back on if it got turned off */
2896 restart_flicker(cam);
2898 /* If AEC is enabled, monitor the exposure and
2899 adjust the sensor frame rate if needed */
2900 if(cam->params.exposure.expMode == 2)
2901 monitor_exposure(cam);
2903 /* camera idle now so dispatch queued commands */
2904 dispatch_commands(cam);
2906 /* Update our knowledge of the camera state */
2907 do_command(cam, CPIA_COMMAND_GetColourBalance, 0, 0, 0, 0);
2908 do_command(cam, CPIA_COMMAND_GetExposure, 0, 0, 0, 0);
2909 do_command(cam, CPIA_COMMAND_ReadMCPorts, 0, 0, 0, 0);
2911 /* decompress and convert image to by copying it from
2912 * raw_image to decompressed_frame
2917 cam->image_size = parse_picture(cam, image_size);
2918 if (cam->image_size <= 0) {
2919 DBG("parse_picture failed %d\n", cam->image_size);
2920 if(cam->params.compression.mode !=
2921 CPIA_COMPRESSION_NONE) {
2922 /* Compression may not work right if we
2923 had a bad frame, get the next one
2925 cam->first_frame = 1;
2926 do_command(cam, CPIA_COMMAND_SetGrabMode,
2927 CPIA_GRAB_SINGLE, 0, 0, 0);
2928 /* FIXME: Trial & error - need up to 70ms for
2929 the grab mode change to complete ? */
2930 msleep_interruptible(70);
2931 if (signal_pending(current))
2939 /* FIXME: this only works for double buffering */
2940 if (cam->frame[cam->curframe].state == FRAME_READY) {
2941 memcpy(cam->frame[cam->curframe].data,
2942 cam->decompressed_frame.data,
2943 cam->decompressed_frame.count);
2944 cam->frame[cam->curframe].state = FRAME_DONE;
2946 cam->decompressed_frame.state = FRAME_DONE;
2948 if (cam->first_frame) {
2949 cam->first_frame = 0;
2950 do_command(cam, CPIA_COMMAND_SetCompression,
2951 cam->params.compression.mode,
2952 cam->params.compression.decimation, 0, 0);
2954 /* Switch from single-grab to continuous grab */
2955 do_command(cam, CPIA_COMMAND_SetGrabMode,
2956 CPIA_GRAB_CONTINUOUS, 0, 0, 0);
2963 static int capture_frame(struct cam_data *cam, struct video_mmap *vm)
2965 if (!cam->frame_buf) {
2966 /* we do lazy allocation */
2968 if ((err = allocate_frame_buf(cam)))
2972 cam->curframe = vm->frame;
2973 cam->frame[cam->curframe].state = FRAME_READY;
2974 return fetch_frame(cam);
2977 static int goto_high_power(struct cam_data *cam)
2979 if (do_command(cam, CPIA_COMMAND_GotoHiPower, 0, 0, 0, 0))
2981 msleep_interruptible(40); /* windows driver does it too */
2982 if(signal_pending(current))
2984 if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0))
2986 if (cam->params.status.systemState == HI_POWER_STATE) {
2987 DBG("camera now in HIGH power state\n");
2994 static int goto_low_power(struct cam_data *cam)
2996 if (do_command(cam, CPIA_COMMAND_GotoLoPower, 0, 0, 0, 0))
2998 if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0))
3000 if (cam->params.status.systemState == LO_POWER_STATE) {
3001 DBG("camera now in LOW power state\n");
3008 static void save_camera_state(struct cam_data *cam)
3010 if(!(cam->cmd_queue & COMMAND_SETCOLOURBALANCE))
3011 do_command(cam, CPIA_COMMAND_GetColourBalance, 0, 0, 0, 0);
3012 if(!(cam->cmd_queue & COMMAND_SETEXPOSURE))
3013 do_command(cam, CPIA_COMMAND_GetExposure, 0, 0, 0, 0);
3015 DBG("%d/%d/%d/%d/%d/%d/%d/%d\n",
3016 cam->params.exposure.gain,
3017 cam->params.exposure.fineExp,
3018 cam->params.exposure.coarseExpLo,
3019 cam->params.exposure.coarseExpHi,
3020 cam->params.exposure.redComp,
3021 cam->params.exposure.green1Comp,
3022 cam->params.exposure.green2Comp,
3023 cam->params.exposure.blueComp);
3025 cam->params.colourBalance.redGain,
3026 cam->params.colourBalance.greenGain,
3027 cam->params.colourBalance.blueGain);
3030 static int set_camera_state(struct cam_data *cam)
3032 cam->cmd_queue = COMMAND_SETCOMPRESSION |
3033 COMMAND_SETCOMPRESSIONTARGET |
3034 COMMAND_SETCOLOURPARAMS |
3036 COMMAND_SETYUVTHRESH |
3037 COMMAND_SETECPTIMING |
3038 COMMAND_SETCOMPRESSIONPARAMS |
3039 COMMAND_SETEXPOSURE |
3040 COMMAND_SETCOLOURBALANCE |
3041 COMMAND_SETSENSORFPS |
3043 COMMAND_SETFLICKERCTRL |
3044 COMMAND_SETVLOFFSET;
3046 do_command(cam, CPIA_COMMAND_SetGrabMode, CPIA_GRAB_SINGLE,0,0,0);
3047 dispatch_commands(cam);
3049 /* Wait 6 frames for the sensor to get all settings and
3050 AEC/ACB to settle */
3051 msleep_interruptible(6*(cam->params.sensorFps.baserate ? 33 : 40) *
3052 (1 << cam->params.sensorFps.divisor) + 10);
3054 if(signal_pending(current))
3057 save_camera_state(cam);
3062 static void get_version_information(struct cam_data *cam)
3064 /* GetCPIAVersion */
3065 do_command(cam, CPIA_COMMAND_GetCPIAVersion, 0, 0, 0, 0);
3068 do_command(cam, CPIA_COMMAND_GetPnPID, 0, 0, 0, 0);
3071 /* initialize camera */
3072 static int reset_camera(struct cam_data *cam)
3075 /* Start the camera in low power mode */
3076 if (goto_low_power(cam)) {
3077 if (cam->params.status.systemState != WARM_BOOT_STATE)
3080 /* FIXME: this is just dirty trial and error */
3081 err = goto_high_power(cam);
3084 do_command(cam, CPIA_COMMAND_DiscardFrame, 0, 0, 0, 0);
3085 if (goto_low_power(cam))
3089 /* procedure described in developer's guide p3-28 */
3091 /* Check the firmware version. */
3092 cam->params.version.firmwareVersion = 0;
3093 get_version_information(cam);
3094 if (cam->params.version.firmwareVersion != 1)
3097 /* A bug in firmware 1-02 limits gainMode to 2 */
3098 if(cam->params.version.firmwareRevision <= 2 &&
3099 cam->params.exposure.gainMode > 2) {
3100 cam->params.exposure.gainMode = 2;
3103 /* set QX3 detected flag */
3104 cam->params.qx3.qx3_detected = (cam->params.pnpID.vendor == 0x0813 &&
3105 cam->params.pnpID.product == 0x0001);
3107 /* The fatal error checking should be done after
3108 * the camera powers up (developer's guide p 3-38) */
3110 /* Set streamState before transition to high power to avoid bug
3111 * in firmware 1-02 */
3112 do_command(cam, CPIA_COMMAND_ModifyCameraStatus, STREAMSTATE, 0,
3113 STREAM_NOT_READY, 0);
3116 err = goto_high_power(cam);
3120 /* Check the camera status */
3121 if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0))
3124 if (cam->params.status.fatalError) {
3125 DBG("fatal_error: %#04x\n",
3126 cam->params.status.fatalError);
3127 DBG("vp_status: %#04x\n",
3128 cam->params.status.vpStatus);
3129 if (cam->params.status.fatalError & ~(COM_FLAG|CPIA_FLAG)) {
3130 /* Fatal error in camera */
3132 } else if (cam->params.status.fatalError & (COM_FLAG|CPIA_FLAG)) {
3133 /* Firmware 1-02 may do this for parallel port cameras,
3134 * just clear the flags (developer's guide p 3-38) */
3135 do_command(cam, CPIA_COMMAND_ModifyCameraStatus,
3136 FATALERROR, ~(COM_FLAG|CPIA_FLAG), 0, 0);
3140 /* Check the camera status again */
3141 if (cam->params.status.fatalError) {
3142 if (cam->params.status.fatalError)
3146 /* VPVersion can't be retrieved before the camera is in HiPower,
3147 * so get it here instead of in get_version_information. */
3148 do_command(cam, CPIA_COMMAND_GetVPVersion, 0, 0, 0, 0);
3150 /* set camera to a known state */
3151 return set_camera_state(cam);
3154 static void put_cam(struct cpia_camera_ops* ops)
3156 module_put(ops->owner);
3159 /* ------------------------- V4L interface --------------------- */
3160 static int cpia_open(struct inode *inode, struct file *file)
3162 struct video_device *dev = video_devdata(file);
3163 struct cam_data *cam = dev->priv;
3167 DBG("Internal error, cam_data not found!\n");
3171 if (cam->open_count > 0) {
3172 DBG("Camera already open\n");
3176 if (!try_module_get(cam->ops->owner))
3179 mutex_lock(&cam->busy_lock);
3181 if (!cam->raw_image) {
3182 cam->raw_image = rvmalloc(CPIA_MAX_IMAGE_SIZE);
3183 if (!cam->raw_image)
3187 if (!cam->decompressed_frame.data) {
3188 cam->decompressed_frame.data = rvmalloc(CPIA_MAX_FRAME_SIZE);
3189 if (!cam->decompressed_frame.data)
3195 if (cam->ops->open(cam->lowlevel_data))
3198 /* reset the camera */
3199 if ((err = reset_camera(cam)) != 0) {
3200 cam->ops->close(cam->lowlevel_data);
3205 if(signal_pending(current))
3208 /* Set ownership of /proc/cpia/videoX to current user */
3210 cam->proc_entry->uid = current->uid;
3212 /* set mark for loading first frame uncompressed */
3213 cam->first_frame = 1;
3215 /* init it to something */
3216 cam->mmap_kludge = 0;
3219 file->private_data = dev;
3220 mutex_unlock(&cam->busy_lock);
3224 if (cam->decompressed_frame.data) {
3225 rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE);
3226 cam->decompressed_frame.data = NULL;
3228 if (cam->raw_image) {
3229 rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
3230 cam->raw_image = NULL;
3232 mutex_unlock(&cam->busy_lock);
3237 static int cpia_close(struct inode *inode, struct file *file)
3239 struct video_device *dev = file->private_data;
3240 struct cam_data *cam = dev->priv;
3243 /* Return ownership of /proc/cpia/videoX to root */
3245 cam->proc_entry->uid = 0;
3247 /* save camera state for later open (developers guide ch 3.5.3) */
3248 save_camera_state(cam);
3251 goto_low_power(cam);
3253 /* Update the camera status */
3254 do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0);
3256 /* cleanup internal state stuff */
3257 free_frames(cam->frame);
3260 cam->ops->close(cam->lowlevel_data);
3265 if (--cam->open_count == 0) {
3266 /* clean up capture-buffers */
3267 if (cam->raw_image) {
3268 rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
3269 cam->raw_image = NULL;
3272 if (cam->decompressed_frame.data) {
3273 rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE);
3274 cam->decompressed_frame.data = NULL;
3278 free_frame_buf(cam);
3283 file->private_data = NULL;
3288 static ssize_t cpia_read(struct file *file, char __user *buf,
3289 size_t count, loff_t *ppos)
3291 struct video_device *dev = file->private_data;
3292 struct cam_data *cam = dev->priv;
3295 /* make this _really_ smp and multithread-safe */
3296 if (mutex_lock_interruptible(&cam->busy_lock))
3301 mutex_unlock(&cam->busy_lock);
3307 mutex_unlock(&cam->busy_lock);
3313 mutex_unlock(&cam->busy_lock);
3318 cam->decompressed_frame.state = FRAME_READY;
3320 if((err = fetch_frame(cam)) != 0) {
3321 DBG("ERROR from fetch_frame: %d\n", err);
3322 mutex_unlock(&cam->busy_lock);
3325 cam->decompressed_frame.state = FRAME_UNUSED;
3327 /* copy data to user space */
3328 if (cam->decompressed_frame.count > count) {
3329 DBG("count wrong: %d, %lu\n", cam->decompressed_frame.count,
3330 (unsigned long) count);
3331 mutex_unlock(&cam->busy_lock);
3334 if (copy_to_user(buf, cam->decompressed_frame.data,
3335 cam->decompressed_frame.count)) {
3336 DBG("copy_to_user failed\n");
3337 mutex_unlock(&cam->busy_lock);
3341 mutex_unlock(&cam->busy_lock);
3342 return cam->decompressed_frame.count;
3345 static int cpia_do_ioctl(struct inode *inode, struct file *file,
3346 unsigned int ioctlnr, void *arg)
3348 struct video_device *dev = file->private_data;
3349 struct cam_data *cam = dev->priv;
3352 if (!cam || !cam->ops)
3355 /* make this _really_ smp-safe */
3356 if (mutex_lock_interruptible(&cam->busy_lock))
3359 //DBG("cpia_ioctl: %u\n", ioctlnr);
3362 /* query capabilities */
3365 struct video_capability *b = arg;
3367 DBG("VIDIOCGCAP\n");
3368 strcpy(b->name, "CPiA Camera");
3369 b->type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE;
3372 b->maxwidth = 352; /* VIDEOSIZE_CIF */
3374 b->minwidth = 48; /* VIDEOSIZE_48_48 */
3379 /* get/set video source - we are a camera and nothing else */
3382 struct video_channel *v = arg;
3384 DBG("VIDIOCGCHAN\n");
3385 if (v->channel != 0) {
3391 strcpy(v->name, "Camera");
3394 v->type = VIDEO_TYPE_CAMERA;
3401 struct video_channel *v = arg;
3403 DBG("VIDIOCSCHAN\n");
3404 if (v->channel != 0)
3409 /* image properties */
3412 struct video_picture *pic = arg;
3413 DBG("VIDIOCGPICT\n");
3420 struct video_picture *vp = arg;
3422 DBG("VIDIOCSPICT\n");
3424 /* check validity */
3425 DBG("palette: %d\n", vp->palette);
3426 DBG("depth: %d\n", vp->depth);
3427 if (!valid_mode(vp->palette, vp->depth)) {
3432 mutex_lock(&cam->param_lock);
3433 /* brightness, colour, contrast need no check 0-65535 */
3435 /* update cam->params.colourParams */
3436 cam->params.colourParams.brightness = vp->brightness*100/65535;
3437 cam->params.colourParams.contrast = vp->contrast*100/65535;
3438 cam->params.colourParams.saturation = vp->colour*100/65535;
3439 /* contrast is in steps of 8, so round */
3440 cam->params.colourParams.contrast =
3441 ((cam->params.colourParams.contrast + 3) / 8) * 8;
3442 if (cam->params.version.firmwareVersion == 1 &&
3443 cam->params.version.firmwareRevision == 2 &&
3444 cam->params.colourParams.contrast > 80) {
3445 /* 1-02 firmware limits contrast to 80 */
3446 cam->params.colourParams.contrast = 80;
3449 /* Adjust flicker control if necessary */
3450 if(cam->params.flickerControl.allowableOverExposure < 0)
3451 cam->params.flickerControl.allowableOverExposure =
3452 -find_over_exposure(cam->params.colourParams.brightness);
3453 if(cam->params.flickerControl.flickerMode != 0)
3454 cam->cmd_queue |= COMMAND_SETFLICKERCTRL;
3457 /* queue command to update camera */
3458 cam->cmd_queue |= COMMAND_SETCOLOURPARAMS;
3459 mutex_unlock(&cam->param_lock);
3460 DBG("VIDIOCSPICT: %d / %d // %d / %d / %d / %d\n",
3461 vp->depth, vp->palette, vp->brightness, vp->hue, vp->colour,
3466 /* get/set capture window */
3469 struct video_window *vw = arg;
3470 DBG("VIDIOCGWIN\n");
3478 /* copy_from_user, check validity, copy to internal structure */
3479 struct video_window *vw = arg;
3480 DBG("VIDIOCSWIN\n");
3482 if (vw->clipcount != 0) { /* clipping not supported */
3486 if (vw->clips != NULL) { /* clipping not supported */
3491 /* we set the video window to something smaller or equal to what
3492 * is requested by the user???
3494 mutex_lock(&cam->param_lock);
3495 if (vw->width != cam->vw.width || vw->height != cam->vw.height) {
3496 int video_size = match_videosize(vw->width, vw->height);
3498 if (video_size < 0) {
3500 mutex_unlock(&cam->param_lock);
3503 cam->video_size = video_size;
3505 /* video size is changing, reset the subcapture area */
3506 memset(&cam->vc, 0, sizeof(cam->vc));
3509 DBG("%d / %d\n", cam->vw.width, cam->vw.height);
3510 cam->cmd_queue |= COMMAND_SETFORMAT;
3513 mutex_unlock(&cam->param_lock);
3515 /* setformat ignored by camera during streaming,
3516 * so stop/dispatch/start */
3517 if (cam->cmd_queue & COMMAND_SETFORMAT) {
3519 dispatch_commands(cam);
3521 DBG("%d/%d:%d\n", cam->video_size,
3522 cam->vw.width, cam->vw.height);
3526 /* mmap interface */
3529 struct video_mbuf *vm = arg;
3532 DBG("VIDIOCGMBUF\n");
3533 memset(vm, 0, sizeof(*vm));
3534 vm->size = CPIA_MAX_FRAME_SIZE*FRAME_NUM;
3535 vm->frames = FRAME_NUM;
3536 for (i = 0; i < FRAME_NUM; i++)
3537 vm->offsets[i] = CPIA_MAX_FRAME_SIZE * i;
3541 case VIDIOCMCAPTURE:
3543 struct video_mmap *vm = arg;
3546 DBG("VIDIOCMCAPTURE: %d / %d / %dx%d\n", vm->format, vm->frame,
3547 vm->width, vm->height);
3548 if (vm->frame<0||vm->frame>=FRAME_NUM) {
3553 /* set video format */
3554 cam->vp.palette = vm->format;
3555 switch(vm->format) {
3556 case VIDEO_PALETTE_GREY:
3559 case VIDEO_PALETTE_RGB555:
3560 case VIDEO_PALETTE_RGB565:
3561 case VIDEO_PALETTE_YUV422:
3562 case VIDEO_PALETTE_YUYV:
3563 case VIDEO_PALETTE_UYVY:
3566 case VIDEO_PALETTE_RGB24:
3569 case VIDEO_PALETTE_RGB32:
3579 /* set video size */
3580 video_size = match_videosize(vm->width, vm->height);
3581 if (video_size < 0) {
3585 if (video_size != cam->video_size) {
3586 cam->video_size = video_size;
3588 /* video size is changing, reset the subcapture area */
3589 memset(&cam->vc, 0, sizeof(cam->vc));
3592 cam->cmd_queue |= COMMAND_SETFORMAT;
3593 dispatch_commands(cam);
3595 /* according to v4l-spec we must start streaming here */
3596 cam->mmap_kludge = 1;
3597 retval = capture_frame(cam, vm);
3606 //DBG("VIDIOCSYNC: %d\n", *frame);
3608 if (*frame<0 || *frame >= FRAME_NUM) {
3613 switch (cam->frame[*frame].state) {
3616 case FRAME_GRABBING:
3617 DBG("sync to unused frame %d\n", *frame);
3622 cam->frame[*frame].state = FRAME_UNUSED;
3623 //DBG("VIDIOCSYNC: %d synced\n", *frame);
3626 if (retval == -EINTR) {
3627 /* FIXME - xawtv does not handle this nice */
3633 case VIDIOCGCAPTURE:
3635 struct video_capture *vc = arg;
3637 DBG("VIDIOCGCAPTURE\n");
3644 case VIDIOCSCAPTURE:
3646 struct video_capture *vc = arg;
3648 DBG("VIDIOCSCAPTURE\n");
3650 if (vc->decimation != 0) { /* How should this be used? */
3654 if (vc->flags != 0) { /* Even/odd grab not supported */
3659 /* Clip to the resolution we can set for the ROI
3660 (every 8 columns and 4 rows) */
3661 vc->x = vc->x & ~(__u32)7;
3662 vc->y = vc->y & ~(__u32)3;
3663 vc->width = vc->width & ~(__u32)7;
3664 vc->height = vc->height & ~(__u32)3;
3666 if(vc->width == 0 || vc->height == 0 ||
3667 vc->x + vc->width > cam->vw.width ||
3668 vc->y + vc->height > cam->vw.height) {
3673 DBG("%d,%d/%dx%d\n", vc->x,vc->y,vc->width, vc->height);
3675 mutex_lock(&cam->param_lock);
3679 cam->vc.width = vc->width;
3680 cam->vc.height = vc->height;
3683 cam->cmd_queue |= COMMAND_SETFORMAT;
3685 mutex_unlock(&cam->param_lock);
3687 /* setformat ignored by camera during streaming,
3688 * so stop/dispatch/start */
3689 dispatch_commands(cam);
3695 struct video_unit *vu = arg;
3697 DBG("VIDIOCGUNIT\n");
3699 vu->video = cam->vdev.minor;
3700 vu->vbi = VIDEO_NO_UNIT;
3701 vu->radio = VIDEO_NO_UNIT;
3702 vu->audio = VIDEO_NO_UNIT;
3703 vu->teletext = VIDEO_NO_UNIT;
3709 /* pointless to implement overlay with this camera */
3714 /* tuner interface - we have none */
3719 /* audio interface - we have none */
3725 retval = -ENOIOCTLCMD;
3729 mutex_unlock(&cam->busy_lock);
3733 static int cpia_ioctl(struct inode *inode, struct file *file,
3734 unsigned int cmd, unsigned long arg)
3736 return video_usercopy(inode, file, cmd, arg, cpia_do_ioctl);
3741 static int cpia_mmap(struct file *file, struct vm_area_struct *vma)
3743 struct video_device *dev = file->private_data;
3744 unsigned long start = vma->vm_start;
3745 unsigned long size = vma->vm_end - vma->vm_start;
3746 unsigned long page, pos;
3747 struct cam_data *cam = dev->priv;
3750 if (!cam || !cam->ops)
3753 DBG("cpia_mmap: %ld\n", size);
3755 if (size > FRAME_NUM*CPIA_MAX_FRAME_SIZE)
3758 if (!cam || !cam->ops)
3761 /* make this _really_ smp-safe */
3762 if (mutex_lock_interruptible(&cam->busy_lock))
3765 if (!cam->frame_buf) { /* we do lazy allocation */
3766 if ((retval = allocate_frame_buf(cam))) {
3767 mutex_unlock(&cam->busy_lock);
3772 pos = (unsigned long)(cam->frame_buf);
3774 page = vmalloc_to_pfn((void *)pos);
3775 if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
3776 mutex_unlock(&cam->busy_lock);
3781 if (size > PAGE_SIZE)
3787 DBG("cpia_mmap: %ld\n", size);
3788 mutex_unlock(&cam->busy_lock);
3793 static const struct file_operations cpia_fops = {
3794 .owner = THIS_MODULE,
3796 .release = cpia_close,
3799 .ioctl = cpia_ioctl,
3800 .compat_ioctl = v4l_compat_ioctl32,
3801 .llseek = no_llseek,
3804 static struct video_device cpia_template = {
3805 .owner = THIS_MODULE,
3806 .name = "CPiA Camera",
3807 .type = VID_TYPE_CAPTURE,
3808 .hardware = VID_HARDWARE_CPIA,
3812 /* initialise cam_data structure */
3813 static void reset_camera_struct(struct cam_data *cam)
3815 /* The following parameter values are the defaults from
3816 * "Software Developer's Guide for CPiA Cameras". Any changes
3817 * to the defaults are noted in comments. */
3818 cam->params.colourParams.brightness = 50;
3819 cam->params.colourParams.contrast = 48;
3820 cam->params.colourParams.saturation = 50;
3821 cam->params.exposure.gainMode = 4;
3822 cam->params.exposure.expMode = 2; /* AEC */
3823 cam->params.exposure.compMode = 1;
3824 cam->params.exposure.centreWeight = 1;
3825 cam->params.exposure.gain = 0;
3826 cam->params.exposure.fineExp = 0;
3827 cam->params.exposure.coarseExpLo = 185;
3828 cam->params.exposure.coarseExpHi = 0;
3829 cam->params.exposure.redComp = COMP_RED;
3830 cam->params.exposure.green1Comp = COMP_GREEN1;
3831 cam->params.exposure.green2Comp = COMP_GREEN2;
3832 cam->params.exposure.blueComp = COMP_BLUE;
3833 cam->params.colourBalance.balanceMode = 2; /* ACB */
3834 cam->params.colourBalance.redGain = 32;
3835 cam->params.colourBalance.greenGain = 6;
3836 cam->params.colourBalance.blueGain = 92;
3837 cam->params.apcor.gain1 = 0x18;
3838 cam->params.apcor.gain2 = 0x16;
3839 cam->params.apcor.gain4 = 0x24;
3840 cam->params.apcor.gain8 = 0x34;
3841 cam->params.flickerControl.flickerMode = 0;
3842 cam->params.flickerControl.disabled = 1;
3844 cam->params.flickerControl.coarseJump =
3845 flicker_jumps[cam->mainsFreq]
3846 [cam->params.sensorFps.baserate]
3847 [cam->params.sensorFps.divisor];
3848 cam->params.flickerControl.allowableOverExposure =
3849 -find_over_exposure(cam->params.colourParams.brightness);
3850 cam->params.vlOffset.gain1 = 20;
3851 cam->params.vlOffset.gain2 = 24;
3852 cam->params.vlOffset.gain4 = 26;
3853 cam->params.vlOffset.gain8 = 26;
3854 cam->params.compressionParams.hysteresis = 3;
3855 cam->params.compressionParams.threshMax = 11;
3856 cam->params.compressionParams.smallStep = 1;
3857 cam->params.compressionParams.largeStep = 3;
3858 cam->params.compressionParams.decimationHysteresis = 2;
3859 cam->params.compressionParams.frDiffStepThresh = 5;
3860 cam->params.compressionParams.qDiffStepThresh = 3;
3861 cam->params.compressionParams.decimationThreshMod = 2;
3862 /* End of default values from Software Developer's Guide */
3864 cam->transfer_rate = 0;
3865 cam->exposure_status = EXPOSURE_NORMAL;
3867 /* Set Sensor FPS to 15fps. This seems better than 30fps
3868 * for indoor lighting. */
3869 cam->params.sensorFps.divisor = 1;
3870 cam->params.sensorFps.baserate = 1;
3872 cam->params.yuvThreshold.yThreshold = 6; /* From windows driver */
3873 cam->params.yuvThreshold.uvThreshold = 6; /* From windows driver */
3875 cam->params.format.subSample = SUBSAMPLE_422;
3876 cam->params.format.yuvOrder = YUVORDER_YUYV;
3878 cam->params.compression.mode = CPIA_COMPRESSION_AUTO;
3879 cam->params.compressionTarget.frTargeting =
3880 CPIA_COMPRESSION_TARGET_QUALITY;
3881 cam->params.compressionTarget.targetFR = 15; /* From windows driver */
3882 cam->params.compressionTarget.targetQ = 5; /* From windows driver */
3884 cam->params.qx3.qx3_detected = 0;
3885 cam->params.qx3.toplight = 0;
3886 cam->params.qx3.bottomlight = 0;
3887 cam->params.qx3.button = 0;
3888 cam->params.qx3.cradled = 0;
3890 cam->video_size = VIDEOSIZE_CIF;
3892 cam->vp.colour = 32768; /* 50% */
3893 cam->vp.hue = 32768; /* 50% */
3894 cam->vp.brightness = 32768; /* 50% */
3895 cam->vp.contrast = 32768; /* 50% */
3896 cam->vp.whiteness = 0; /* not used -> grayscale only */
3897 cam->vp.depth = 24; /* to be set by user */
3898 cam->vp.palette = VIDEO_PALETTE_RGB24; /* to be set by user */
3908 cam->vw.chromakey = 0;
3910 cam->vw.clipcount = 0;
3911 cam->vw.clips = NULL;
3913 cam->cmd_queue = COMMAND_NONE;
3914 cam->first_frame = 1;
3919 /* initialize cam_data structure */
3920 static void init_camera_struct(struct cam_data *cam,
3921 struct cpia_camera_ops *ops )
3925 /* Default everything to 0 */
3926 memset(cam, 0, sizeof(struct cam_data));
3929 mutex_init(&cam->param_lock);
3930 mutex_init(&cam->busy_lock);
3932 reset_camera_struct(cam);
3934 cam->proc_entry = NULL;
3936 memcpy(&cam->vdev, &cpia_template, sizeof(cpia_template));
3937 cam->vdev.priv = cam;
3940 for (i = 0; i < FRAME_NUM; i++) {
3941 cam->frame[i].width = 0;
3942 cam->frame[i].height = 0;
3943 cam->frame[i].state = FRAME_UNUSED;
3944 cam->frame[i].data = NULL;
3946 cam->decompressed_frame.width = 0;
3947 cam->decompressed_frame.height = 0;
3948 cam->decompressed_frame.state = FRAME_UNUSED;
3949 cam->decompressed_frame.data = NULL;
3952 struct cam_data *cpia_register_camera(struct cpia_camera_ops *ops, void *lowlevel)
3954 struct cam_data *camera;
3956 if ((camera = kmalloc(sizeof(struct cam_data), GFP_KERNEL)) == NULL)
3960 init_camera_struct( camera, ops );
3961 camera->lowlevel_data = lowlevel;
3963 /* register v4l device */
3964 if (video_register_device(&camera->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
3966 printk(KERN_DEBUG "video_register_device failed\n");
3970 /* get version information from camera: open/reset/close */
3973 if (camera->ops->open(camera->lowlevel_data))
3976 /* reset the camera */
3977 if (reset_camera(camera) != 0) {
3978 camera->ops->close(camera->lowlevel_data);
3983 camera->ops->close(camera->lowlevel_data);
3985 #ifdef CONFIG_PROC_FS
3986 create_proc_cpia_cam(camera);
3989 printk(KERN_INFO " CPiA Version: %d.%02d (%d.%d)\n",
3990 camera->params.version.firmwareVersion,
3991 camera->params.version.firmwareRevision,
3992 camera->params.version.vcVersion,
3993 camera->params.version.vcRevision);
3994 printk(KERN_INFO " CPiA PnP-ID: %04x:%04x:%04x\n",
3995 camera->params.pnpID.vendor,
3996 camera->params.pnpID.product,
3997 camera->params.pnpID.deviceRevision);
3998 printk(KERN_INFO " VP-Version: %d.%d %04x\n",
3999 camera->params.vpVersion.vpVersion,
4000 camera->params.vpVersion.vpRevision,
4001 camera->params.vpVersion.cameraHeadID);
4006 void cpia_unregister_camera(struct cam_data *cam)
4008 DBG("unregistering video\n");
4009 video_unregister_device(&cam->vdev);
4010 if (cam->open_count) {
4012 DBG("camera open -- setting ops to NULL\n");
4016 #ifdef CONFIG_PROC_FS
4017 DBG("destroying /proc/cpia/video%d\n", cam->vdev.minor);
4018 destroy_proc_cpia_cam(cam);
4020 if (!cam->open_count) {
4021 DBG("freeing camera\n");
4026 static int __init cpia_init(void)
4028 printk(KERN_INFO "%s v%d.%d.%d\n", ABOUT,
4029 CPIA_MAJ_VER, CPIA_MIN_VER, CPIA_PATCH_VER);
4031 printk(KERN_WARNING "Since in-kernel colorspace conversion is not "
4032 "allowed, it is disabled by default now. Users should fix the "
4033 "applications in case they don't work without conversion "
4034 "reenabled by setting the 'colorspace_conv' module "
4035 "parameter to 1\n");
4037 #ifdef CONFIG_PROC_FS
4044 static void __exit cpia_exit(void)
4046 #ifdef CONFIG_PROC_FS
4047 proc_cpia_destroy();
4051 module_init(cpia_init);
4052 module_exit(cpia_exit);
4054 /* Exported symbols for modules. */
4056 EXPORT_SYMBOL(cpia_register_camera);
4057 EXPORT_SYMBOL(cpia_unregister_camera);