4 * Supports CPiA based Video Camera's.
6 * (C) Copyright 1999-2000 Peter Pregler
7 * (C) Copyright 1999-2000 Scott J. Bertin
8 * (C) Copyright 1999-2000 Johannes Erdfelt <johannes@erdfelt.com>
9 * (C) Copyright 2000 STMicroelectronics
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 /* define _CPIA_DEBUG_ for verbose debug output (see cpia.h) */
27 /* #define _CPIA_DEBUG_ 1 */
29 #include <linux/config.h>
31 #include <linux/module.h>
32 #include <linux/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>
40 #include <asm/semaphore.h>
43 #include <linux/kmod.h>
48 #ifdef CONFIG_VIDEO_CPIA_PP
49 extern int cpia_pp_init(void);
51 #ifdef CONFIG_VIDEO_CPIA_USB
52 extern int cpia_usb_init(void);
55 static int video_nr = -1;
58 MODULE_PARM(video_nr,"i");
59 MODULE_AUTHOR("Scott J. Bertin <sbertin@securenym.net> & Peter Pregler <Peter_Pregler@email.com> & Johannes Erdfelt <johannes@erdfeld.com>");
60 MODULE_DESCRIPTION("V4L-driver for Vision CPiA based cameras");
61 MODULE_LICENSE("GPL");
62 MODULE_SUPPORTED_DEVICE("video");
65 #define ABOUT "V4L-Driver for Vision CPiA based cameras"
67 #ifndef VID_HARDWARE_CPIA
68 #define VID_HARDWARE_CPIA 24 /* FIXME -> from linux/videodev.h */
71 #define CPIA_MODULE_CPIA (0<<5)
72 #define CPIA_MODULE_SYSTEM (1<<5)
73 #define CPIA_MODULE_VP_CTRL (5<<5)
74 #define CPIA_MODULE_CAPTURE (6<<5)
75 #define CPIA_MODULE_DEBUG (7<<5)
77 #define INPUT (DATA_IN << 8)
78 #define OUTPUT (DATA_OUT << 8)
80 #define CPIA_COMMAND_GetCPIAVersion (INPUT | CPIA_MODULE_CPIA | 1)
81 #define CPIA_COMMAND_GetPnPID (INPUT | CPIA_MODULE_CPIA | 2)
82 #define CPIA_COMMAND_GetCameraStatus (INPUT | CPIA_MODULE_CPIA | 3)
83 #define CPIA_COMMAND_GotoHiPower (OUTPUT | CPIA_MODULE_CPIA | 4)
84 #define CPIA_COMMAND_GotoLoPower (OUTPUT | CPIA_MODULE_CPIA | 5)
85 #define CPIA_COMMAND_GotoSuspend (OUTPUT | CPIA_MODULE_CPIA | 7)
86 #define CPIA_COMMAND_GotoPassThrough (OUTPUT | CPIA_MODULE_CPIA | 8)
87 #define CPIA_COMMAND_ModifyCameraStatus (OUTPUT | CPIA_MODULE_CPIA | 10)
89 #define CPIA_COMMAND_ReadVCRegs (INPUT | CPIA_MODULE_SYSTEM | 1)
90 #define CPIA_COMMAND_WriteVCReg (OUTPUT | CPIA_MODULE_SYSTEM | 2)
91 #define CPIA_COMMAND_ReadMCPorts (INPUT | CPIA_MODULE_SYSTEM | 3)
92 #define CPIA_COMMAND_WriteMCPort (OUTPUT | CPIA_MODULE_SYSTEM | 4)
93 #define CPIA_COMMAND_SetBaudRate (OUTPUT | CPIA_MODULE_SYSTEM | 5)
94 #define CPIA_COMMAND_SetECPTiming (OUTPUT | CPIA_MODULE_SYSTEM | 6)
95 #define CPIA_COMMAND_ReadIDATA (INPUT | CPIA_MODULE_SYSTEM | 7)
96 #define CPIA_COMMAND_WriteIDATA (OUTPUT | CPIA_MODULE_SYSTEM | 8)
97 #define CPIA_COMMAND_GenericCall (OUTPUT | CPIA_MODULE_SYSTEM | 9)
98 #define CPIA_COMMAND_I2CStart (OUTPUT | CPIA_MODULE_SYSTEM | 10)
99 #define CPIA_COMMAND_I2CStop (OUTPUT | CPIA_MODULE_SYSTEM | 11)
100 #define CPIA_COMMAND_I2CWrite (OUTPUT | CPIA_MODULE_SYSTEM | 12)
101 #define CPIA_COMMAND_I2CRead (INPUT | CPIA_MODULE_SYSTEM | 13)
103 #define CPIA_COMMAND_GetVPVersion (INPUT | CPIA_MODULE_VP_CTRL | 1)
104 #define CPIA_COMMAND_ResetFrameCounter (INPUT | CPIA_MODULE_VP_CTRL | 2)
105 #define CPIA_COMMAND_SetColourParams (OUTPUT | CPIA_MODULE_VP_CTRL | 3)
106 #define CPIA_COMMAND_SetExposure (OUTPUT | CPIA_MODULE_VP_CTRL | 4)
107 #define CPIA_COMMAND_SetColourBalance (OUTPUT | CPIA_MODULE_VP_CTRL | 6)
108 #define CPIA_COMMAND_SetSensorFPS (OUTPUT | CPIA_MODULE_VP_CTRL | 7)
109 #define CPIA_COMMAND_SetVPDefaults (OUTPUT | CPIA_MODULE_VP_CTRL | 8)
110 #define CPIA_COMMAND_SetApcor (OUTPUT | CPIA_MODULE_VP_CTRL | 9)
111 #define CPIA_COMMAND_SetFlickerCtrl (OUTPUT | CPIA_MODULE_VP_CTRL | 10)
112 #define CPIA_COMMAND_SetVLOffset (OUTPUT | CPIA_MODULE_VP_CTRL | 11)
113 #define CPIA_COMMAND_GetColourParams (INPUT | CPIA_MODULE_VP_CTRL | 16)
114 #define CPIA_COMMAND_GetColourBalance (INPUT | CPIA_MODULE_VP_CTRL | 17)
115 #define CPIA_COMMAND_GetExposure (INPUT | CPIA_MODULE_VP_CTRL | 18)
116 #define CPIA_COMMAND_SetSensorMatrix (OUTPUT | CPIA_MODULE_VP_CTRL | 19)
117 #define CPIA_COMMAND_ColourBars (OUTPUT | CPIA_MODULE_VP_CTRL | 25)
118 #define CPIA_COMMAND_ReadVPRegs (INPUT | CPIA_MODULE_VP_CTRL | 30)
119 #define CPIA_COMMAND_WriteVPReg (OUTPUT | CPIA_MODULE_VP_CTRL | 31)
121 #define CPIA_COMMAND_GrabFrame (OUTPUT | CPIA_MODULE_CAPTURE | 1)
122 #define CPIA_COMMAND_UploadFrame (OUTPUT | CPIA_MODULE_CAPTURE | 2)
123 #define CPIA_COMMAND_SetGrabMode (OUTPUT | CPIA_MODULE_CAPTURE | 3)
124 #define CPIA_COMMAND_InitStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 4)
125 #define CPIA_COMMAND_FiniStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 5)
126 #define CPIA_COMMAND_StartStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 6)
127 #define CPIA_COMMAND_EndStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 7)
128 #define CPIA_COMMAND_SetFormat (OUTPUT | CPIA_MODULE_CAPTURE | 8)
129 #define CPIA_COMMAND_SetROI (OUTPUT | CPIA_MODULE_CAPTURE | 9)
130 #define CPIA_COMMAND_SetCompression (OUTPUT | CPIA_MODULE_CAPTURE | 10)
131 #define CPIA_COMMAND_SetCompressionTarget (OUTPUT | CPIA_MODULE_CAPTURE | 11)
132 #define CPIA_COMMAND_SetYUVThresh (OUTPUT | CPIA_MODULE_CAPTURE | 12)
133 #define CPIA_COMMAND_SetCompressionParams (OUTPUT | CPIA_MODULE_CAPTURE | 13)
134 #define CPIA_COMMAND_DiscardFrame (OUTPUT | CPIA_MODULE_CAPTURE | 14)
135 #define CPIA_COMMAND_GrabReset (OUTPUT | CPIA_MODULE_CAPTURE | 15)
137 #define CPIA_COMMAND_OutputRS232 (OUTPUT | CPIA_MODULE_DEBUG | 1)
138 #define CPIA_COMMAND_AbortProcess (OUTPUT | CPIA_MODULE_DEBUG | 4)
139 #define CPIA_COMMAND_SetDramPage (OUTPUT | CPIA_MODULE_DEBUG | 5)
140 #define CPIA_COMMAND_StartDramUpload (OUTPUT | CPIA_MODULE_DEBUG | 6)
141 #define CPIA_COMMAND_StartDummyDtream (OUTPUT | CPIA_MODULE_DEBUG | 8)
142 #define CPIA_COMMAND_AbortStream (OUTPUT | CPIA_MODULE_DEBUG | 9)
143 #define CPIA_COMMAND_DownloadDRAM (OUTPUT | CPIA_MODULE_DEBUG | 10)
144 #define CPIA_COMMAND_Null (OUTPUT | CPIA_MODULE_DEBUG | 11)
147 FRAME_READY, /* Ready to grab into */
148 FRAME_GRABBING, /* In the process of being grabbed into */
149 FRAME_DONE, /* Finished grabbing, but not been synced yet */
150 FRAME_UNUSED, /* Unused (no MCAPTURE) */
153 #define COMMAND_NONE 0x0000
154 #define COMMAND_SETCOMPRESSION 0x0001
155 #define COMMAND_SETCOMPRESSIONTARGET 0x0002
156 #define COMMAND_SETCOLOURPARAMS 0x0004
157 #define COMMAND_SETFORMAT 0x0008
158 #define COMMAND_PAUSE 0x0010
159 #define COMMAND_RESUME 0x0020
160 #define COMMAND_SETYUVTHRESH 0x0040
161 #define COMMAND_SETECPTIMING 0x0080
162 #define COMMAND_SETCOMPRESSIONPARAMS 0x0100
163 #define COMMAND_SETEXPOSURE 0x0200
164 #define COMMAND_SETCOLOURBALANCE 0x0400
165 #define COMMAND_SETSENSORFPS 0x0800
166 #define COMMAND_SETAPCOR 0x1000
167 #define COMMAND_SETFLICKERCTRL 0x2000
168 #define COMMAND_SETVLOFFSET 0x4000
169 #define COMMAND_SETLIGHTS 0x8000
171 #define ROUND_UP_EXP_FOR_FLICKER 15
173 /* Constants for automatic frame rate adjustment */
175 #define MAX_EXP_102 255
177 #define VERY_LOW_EXP 70
179 #define EXP_ACC_DARK 50
180 #define EXP_ACC_LIGHT 90
181 #define HIGH_COMP_102 160
186 /* Maximum number of 10ms loops to wait for the stream to become ready */
187 #define READY_TIMEOUT 100
189 /* Developer's Guide Table 5 p 3-34
190 * indexed by [mains][sensorFps.baserate][sensorFps.divisor]*/
191 static u8 flicker_jumps[2][2][4] =
192 { { { 76, 38, 19, 9 }, { 92, 46, 23, 11 } },
193 { { 64, 32, 16, 8 }, { 76, 38, 19, 9} }
196 /* forward declaration of local function */
197 static void reset_camera_struct(struct cam_data *cam);
198 static int find_over_exposure(int brightness);
199 static void set_flicker(struct cam_params *params, volatile u32 *command_flags,
203 /**********************************************************************
207 **********************************************************************/
209 /* Here we want the physical address of the memory.
210 * This is used when initializing the contents of the area.
212 static inline unsigned long kvirt_to_pa(unsigned long adr)
214 unsigned long kva, ret;
216 kva = (unsigned long) page_address(vmalloc_to_page((void *)adr));
217 kva |= adr & (PAGE_SIZE-1); /* restore the offset */
222 static void *rvmalloc(unsigned long size)
227 size = PAGE_ALIGN(size);
228 mem = vmalloc_32(size);
232 memset(mem, 0, size); /* Clear the ram out, no junk to the user */
233 adr = (unsigned long) mem;
235 SetPageReserved(vmalloc_to_page((void *)adr));
243 static void rvfree(void *mem, unsigned long size)
250 adr = (unsigned long) mem;
251 while ((long) size > 0) {
252 ClearPageReserved(vmalloc_to_page((void *)adr));
259 /**********************************************************************
263 **********************************************************************/
264 #ifdef CONFIG_PROC_FS
265 static struct proc_dir_entry *cpia_proc_root=NULL;
267 static int cpia_read_proc(char *page, char **start, off_t off,
268 int count, int *eof, void *data)
272 struct cam_data *cam = data;
275 /* IMPORTANT: This output MUST be kept under PAGE_SIZE
276 * or we need to get more sophisticated. */
278 out += sprintf(out, "read-only\n-----------------------\n");
279 out += sprintf(out, "V4L Driver version: %d.%d.%d\n",
280 CPIA_MAJ_VER, CPIA_MIN_VER, CPIA_PATCH_VER);
281 out += sprintf(out, "CPIA Version: %d.%02d (%d.%d)\n",
282 cam->params.version.firmwareVersion,
283 cam->params.version.firmwareRevision,
284 cam->params.version.vcVersion,
285 cam->params.version.vcRevision);
286 out += sprintf(out, "CPIA PnP-ID: %04x:%04x:%04x\n",
287 cam->params.pnpID.vendor, cam->params.pnpID.product,
288 cam->params.pnpID.deviceRevision);
289 out += sprintf(out, "VP-Version: %d.%d %04x\n",
290 cam->params.vpVersion.vpVersion,
291 cam->params.vpVersion.vpRevision,
292 cam->params.vpVersion.cameraHeadID);
294 out += sprintf(out, "system_state: %#04x\n",
295 cam->params.status.systemState);
296 out += sprintf(out, "grab_state: %#04x\n",
297 cam->params.status.grabState);
298 out += sprintf(out, "stream_state: %#04x\n",
299 cam->params.status.streamState);
300 out += sprintf(out, "fatal_error: %#04x\n",
301 cam->params.status.fatalError);
302 out += sprintf(out, "cmd_error: %#04x\n",
303 cam->params.status.cmdError);
304 out += sprintf(out, "debug_flags: %#04x\n",
305 cam->params.status.debugFlags);
306 out += sprintf(out, "vp_status: %#04x\n",
307 cam->params.status.vpStatus);
308 out += sprintf(out, "error_code: %#04x\n",
309 cam->params.status.errorCode);
310 /* QX3 specific entries */
311 if (cam->params.qx3.qx3_detected) {
312 out += sprintf(out, "button: %4d\n",
313 cam->params.qx3.button);
314 out += sprintf(out, "cradled: %4d\n",
315 cam->params.qx3.cradled);
317 out += sprintf(out, "video_size: %s\n",
318 cam->params.format.videoSize == VIDEOSIZE_CIF ?
320 out += sprintf(out, "roi: (%3d, %3d) to (%3d, %3d)\n",
321 cam->params.roi.colStart*8,
322 cam->params.roi.rowStart*4,
323 cam->params.roi.colEnd*8,
324 cam->params.roi.rowEnd*4);
325 out += sprintf(out, "actual_fps: %3d\n", cam->fps);
326 out += sprintf(out, "transfer_rate: %4dkB/s\n",
329 out += sprintf(out, "\nread-write\n");
330 out += sprintf(out, "----------------------- current min"
331 " max default comment\n");
332 out += sprintf(out, "brightness: %8d %8d %8d %8d\n",
333 cam->params.colourParams.brightness, 0, 100, 50);
334 if (cam->params.version.firmwareVersion == 1 &&
335 cam->params.version.firmwareRevision == 2)
336 /* 1-02 firmware limits contrast to 80 */
341 out += sprintf(out, "contrast: %8d %8d %8d %8d"
343 cam->params.colourParams.contrast, 0, tmp, 48);
344 out += sprintf(out, "saturation: %8d %8d %8d %8d\n",
345 cam->params.colourParams.saturation, 0, 100, 50);
346 tmp = (25000+5000*cam->params.sensorFps.baserate)/
347 (1<<cam->params.sensorFps.divisor);
348 out += sprintf(out, "sensor_fps: %4d.%03d %8d %8d %8d\n",
349 tmp/1000, tmp%1000, 3, 30, 15);
350 out += sprintf(out, "stream_start_line: %8d %8d %8d %8d\n",
351 2*cam->params.streamStartLine, 0,
352 cam->params.format.videoSize == VIDEOSIZE_CIF ? 288:144,
353 cam->params.format.videoSize == VIDEOSIZE_CIF ? 240:120);
354 out += sprintf(out, "sub_sample: %8s %8s %8s %8s\n",
355 cam->params.format.subSample == SUBSAMPLE_420 ?
356 "420" : "422", "420", "422", "422");
357 out += sprintf(out, "yuv_order: %8s %8s %8s %8s\n",
358 cam->params.format.yuvOrder == YUVORDER_YUYV ?
359 "YUYV" : "UYVY", "YUYV" , "UYVY", "YUYV");
360 out += sprintf(out, "ecp_timing: %8s %8s %8s %8s\n",
361 cam->params.ecpTiming ? "slow" : "normal", "slow",
364 if (cam->params.colourBalance.balanceMode == 2) {
365 sprintf(tmpstr, "auto");
367 sprintf(tmpstr, "manual");
369 out += sprintf(out, "color_balance_mode: %8s %8s %8s"
370 " %8s\n", tmpstr, "manual", "auto", "auto");
371 out += sprintf(out, "red_gain: %8d %8d %8d %8d\n",
372 cam->params.colourBalance.redGain, 0, 212, 32);
373 out += sprintf(out, "green_gain: %8d %8d %8d %8d\n",
374 cam->params.colourBalance.greenGain, 0, 212, 6);
375 out += sprintf(out, "blue_gain: %8d %8d %8d %8d\n",
376 cam->params.colourBalance.blueGain, 0, 212, 92);
378 if (cam->params.version.firmwareVersion == 1 &&
379 cam->params.version.firmwareRevision == 2)
380 /* 1-02 firmware limits gain to 2 */
381 sprintf(tmpstr, "%8d %8d %8d", 1, 2, 2);
383 sprintf(tmpstr, "%8d %8d %8d", 1, 8, 2);
385 if (cam->params.exposure.gainMode == 0)
386 out += sprintf(out, "max_gain: unknown %28s"
387 " powers of 2\n", tmpstr);
389 out += sprintf(out, "max_gain: %8d %28s"
391 1<<(cam->params.exposure.gainMode-1), tmpstr);
393 switch(cam->params.exposure.expMode) {
396 sprintf(tmpstr, "manual");
399 sprintf(tmpstr, "auto");
402 sprintf(tmpstr, "unknown");
405 out += sprintf(out, "exposure_mode: %8s %8s %8s"
406 " %8s\n", tmpstr, "manual", "auto", "auto");
407 out += sprintf(out, "centre_weight: %8s %8s %8s %8s\n",
408 (2-cam->params.exposure.centreWeight) ? "on" : "off",
410 out += sprintf(out, "gain: %8d %8d max_gain %8d 1,2,4,8 possible\n",
411 1<<cam->params.exposure.gain, 1, 1);
412 if (cam->params.version.firmwareVersion == 1 &&
413 cam->params.version.firmwareRevision == 2)
414 /* 1-02 firmware limits fineExp/2 to 127 */
419 out += sprintf(out, "fine_exp: %8d %8d %8d %8d\n",
420 cam->params.exposure.fineExp*2, 0, tmp, 0);
421 if (cam->params.version.firmwareVersion == 1 &&
422 cam->params.version.firmwareRevision == 2)
423 /* 1-02 firmware limits coarseExpHi to 0 */
428 out += sprintf(out, "coarse_exp: %8d %8d %8d"
429 " %8d\n", cam->params.exposure.coarseExpLo+
430 256*cam->params.exposure.coarseExpHi, 0, tmp, 185);
431 out += sprintf(out, "red_comp: %8d %8d %8d %8d\n",
432 cam->params.exposure.redComp, COMP_RED, 255, COMP_RED);
433 out += sprintf(out, "green1_comp: %8d %8d %8d %8d\n",
434 cam->params.exposure.green1Comp, COMP_GREEN1, 255,
436 out += sprintf(out, "green2_comp: %8d %8d %8d %8d\n",
437 cam->params.exposure.green2Comp, COMP_GREEN2, 255,
439 out += sprintf(out, "blue_comp: %8d %8d %8d %8d\n",
440 cam->params.exposure.blueComp, COMP_BLUE, 255, COMP_BLUE);
442 out += sprintf(out, "apcor_gain1: %#8x %#8x %#8x %#8x\n",
443 cam->params.apcor.gain1, 0, 0xff, 0x1c);
444 out += sprintf(out, "apcor_gain2: %#8x %#8x %#8x %#8x\n",
445 cam->params.apcor.gain2, 0, 0xff, 0x1a);
446 out += sprintf(out, "apcor_gain4: %#8x %#8x %#8x %#8x\n",
447 cam->params.apcor.gain4, 0, 0xff, 0x2d);
448 out += sprintf(out, "apcor_gain8: %#8x %#8x %#8x %#8x\n",
449 cam->params.apcor.gain8, 0, 0xff, 0x2a);
450 out += sprintf(out, "vl_offset_gain1: %8d %8d %8d %8d\n",
451 cam->params.vlOffset.gain1, 0, 255, 24);
452 out += sprintf(out, "vl_offset_gain2: %8d %8d %8d %8d\n",
453 cam->params.vlOffset.gain2, 0, 255, 28);
454 out += sprintf(out, "vl_offset_gain4: %8d %8d %8d %8d\n",
455 cam->params.vlOffset.gain4, 0, 255, 30);
456 out += sprintf(out, "vl_offset_gain8: %8d %8d %8d %8d\n",
457 cam->params.vlOffset.gain8, 0, 255, 30);
458 out += sprintf(out, "flicker_control: %8s %8s %8s %8s\n",
459 cam->params.flickerControl.flickerMode ? "on" : "off",
461 out += sprintf(out, "mains_frequency: %8d %8d %8d %8d"
463 cam->mainsFreq ? 60 : 50, 50, 60, 50);
464 if(cam->params.flickerControl.allowableOverExposure < 0)
465 out += sprintf(out, "allowable_overexposure: %4dauto auto %8d auto\n",
466 -cam->params.flickerControl.allowableOverExposure,
469 out += sprintf(out, "allowable_overexposure: %8d auto %8d auto\n",
470 cam->params.flickerControl.allowableOverExposure,
472 out += sprintf(out, "compression_mode: ");
473 switch(cam->params.compression.mode) {
474 case CPIA_COMPRESSION_NONE:
475 out += sprintf(out, "%8s", "none");
477 case CPIA_COMPRESSION_AUTO:
478 out += sprintf(out, "%8s", "auto");
480 case CPIA_COMPRESSION_MANUAL:
481 out += sprintf(out, "%8s", "manual");
484 out += sprintf(out, "%8s", "unknown");
487 out += sprintf(out, " none,auto,manual auto\n");
488 out += sprintf(out, "decimation_enable: %8s %8s %8s %8s\n",
489 cam->params.compression.decimation ==
490 DECIMATION_ENAB ? "on":"off", "off", "on",
492 out += sprintf(out, "compression_target: %9s %9s %9s %9s\n",
493 cam->params.compressionTarget.frTargeting ==
494 CPIA_COMPRESSION_TARGET_FRAMERATE ?
495 "framerate":"quality",
496 "framerate", "quality", "quality");
497 out += sprintf(out, "target_framerate: %8d %8d %8d %8d\n",
498 cam->params.compressionTarget.targetFR, 1, 30, 15);
499 out += sprintf(out, "target_quality: %8d %8d %8d %8d\n",
500 cam->params.compressionTarget.targetQ, 1, 64, 5);
501 out += sprintf(out, "y_threshold: %8d %8d %8d %8d\n",
502 cam->params.yuvThreshold.yThreshold, 0, 31, 6);
503 out += sprintf(out, "uv_threshold: %8d %8d %8d %8d\n",
504 cam->params.yuvThreshold.uvThreshold, 0, 31, 6);
505 out += sprintf(out, "hysteresis: %8d %8d %8d %8d\n",
506 cam->params.compressionParams.hysteresis, 0, 255, 3);
507 out += sprintf(out, "threshold_max: %8d %8d %8d %8d\n",
508 cam->params.compressionParams.threshMax, 0, 255, 11);
509 out += sprintf(out, "small_step: %8d %8d %8d %8d\n",
510 cam->params.compressionParams.smallStep, 0, 255, 1);
511 out += sprintf(out, "large_step: %8d %8d %8d %8d\n",
512 cam->params.compressionParams.largeStep, 0, 255, 3);
513 out += sprintf(out, "decimation_hysteresis: %8d %8d %8d %8d\n",
514 cam->params.compressionParams.decimationHysteresis,
516 out += sprintf(out, "fr_diff_step_thresh: %8d %8d %8d %8d\n",
517 cam->params.compressionParams.frDiffStepThresh,
519 out += sprintf(out, "q_diff_step_thresh: %8d %8d %8d %8d\n",
520 cam->params.compressionParams.qDiffStepThresh,
522 out += sprintf(out, "decimation_thresh_mod: %8d %8d %8d %8d\n",
523 cam->params.compressionParams.decimationThreshMod,
525 /* QX3 specific entries */
526 if (cam->params.qx3.qx3_detected) {
527 out += sprintf(out, "toplight: %8s %8s %8s %8s\n",
528 cam->params.qx3.toplight ? "on" : "off",
530 out += sprintf(out, "bottomlight: %8s %8s %8s %8s\n",
531 cam->params.qx3.bottomlight ? "on" : "off",
539 if (len <= 0) return 0;
548 static int match(char *checkstr, char **buffer, unsigned long *count,
549 int *find_colon, int *err)
551 int ret, colon_found = 1;
552 int len = strlen(checkstr);
553 ret = (len <= *count && strncmp(*buffer, checkstr, len) == 0);
559 while (*count && (**buffer == ' ' || **buffer == '\t' ||
560 (!colon_found && **buffer == ':'))) {
566 if (!*count || !colon_found)
574 static unsigned long int value(char **buffer, unsigned long *count, int *err)
577 unsigned long int ret;
578 ret = simple_strtoul(*buffer, &p, 0);
582 *count -= p - *buffer;
588 static int cpia_write_proc(struct file *file, const char __user *buf,
589 unsigned long count, void *data)
591 struct cam_data *cam = data;
592 struct cam_params new_params;
594 int retval, find_colon;
596 unsigned long val = 0;
597 u32 command_flags = 0;
601 * This code to copy from buf to page is shamelessly copied
602 * from the comx driver
604 if (count > PAGE_SIZE) {
605 printk(KERN_ERR "count is %lu > %d!!!\n", count, (int)PAGE_SIZE);
609 if (!(page = (char *)__get_free_page(GFP_KERNEL))) return -ENOMEM;
611 if(copy_from_user(page, buf, count))
617 if (page[count-1] == '\n')
618 page[count-1] = '\0';
619 else if (count < PAGE_SIZE)
621 else if (page[count]) {
628 if (down_interruptible(&cam->param_lock))
632 * Skip over leading whitespace
634 while (count && isspace(*buffer)) {
639 memcpy(&new_params, &cam->params, sizeof(struct cam_params));
640 new_mains = cam->mainsFreq;
642 #define MATCH(x) (match(x, &buffer, &count, &find_colon, &retval))
643 #define VALUE (value(&buffer,&count, &retval))
644 #define FIRMWARE_VERSION(x,y) (new_params.version.firmwareVersion == (x) && \
645 new_params.version.firmwareRevision == (y))
648 while (count && !retval) {
650 if (MATCH("brightness")) {
656 new_params.colourParams.brightness = val;
660 command_flags |= COMMAND_SETCOLOURPARAMS;
661 if(new_params.flickerControl.allowableOverExposure < 0)
662 new_params.flickerControl.allowableOverExposure =
663 -find_over_exposure(new_params.colourParams.brightness);
664 if(new_params.flickerControl.flickerMode != 0)
665 command_flags |= COMMAND_SETFLICKERCTRL;
667 } else if (MATCH("contrast")) {
673 /* contrast is in steps of 8, so round*/
674 val = ((val + 3) / 8) * 8;
675 /* 1-02 firmware limits contrast to 80*/
676 if (FIRMWARE_VERSION(1,2) && val > 80)
679 new_params.colourParams.contrast = val;
683 command_flags |= COMMAND_SETCOLOURPARAMS;
684 } else if (MATCH("saturation")) {
690 new_params.colourParams.saturation = val;
694 command_flags |= COMMAND_SETCOLOURPARAMS;
695 } else if (MATCH("sensor_fps")) {
700 /* find values so that sensorFPS is minimized,
705 new_params.sensorFps.divisor = 0;
706 new_params.sensorFps.baserate = 1;
707 } else if (val > 15) {
708 new_params.sensorFps.divisor = 0;
709 new_params.sensorFps.baserate = 0;
710 } else if (val > 12) {
711 new_params.sensorFps.divisor = 1;
712 new_params.sensorFps.baserate = 1;
713 } else if (val > 7) {
714 new_params.sensorFps.divisor = 1;
715 new_params.sensorFps.baserate = 0;
716 } else if (val > 6) {
717 new_params.sensorFps.divisor = 2;
718 new_params.sensorFps.baserate = 1;
719 } else if (val > 3) {
720 new_params.sensorFps.divisor = 2;
721 new_params.sensorFps.baserate = 0;
723 new_params.sensorFps.divisor = 3;
724 /* Either base rate would work here */
725 new_params.sensorFps.baserate = 1;
727 new_params.flickerControl.coarseJump =
728 flicker_jumps[new_mains]
729 [new_params.sensorFps.baserate]
730 [new_params.sensorFps.divisor];
731 if (new_params.flickerControl.flickerMode)
732 command_flags |= COMMAND_SETFLICKERCTRL;
734 command_flags |= COMMAND_SETSENSORFPS;
735 cam->exposure_status = EXPOSURE_NORMAL;
736 } else if (MATCH("stream_start_line")) {
743 if (new_params.format.videoSize == VIDEOSIZE_QCIF)
746 new_params.streamStartLine = val/2;
750 } else if (MATCH("sub_sample")) {
751 if (!retval && MATCH("420"))
752 new_params.format.subSample = SUBSAMPLE_420;
753 else if (!retval && MATCH("422"))
754 new_params.format.subSample = SUBSAMPLE_422;
758 command_flags |= COMMAND_SETFORMAT;
759 } else if (MATCH("yuv_order")) {
760 if (!retval && MATCH("YUYV"))
761 new_params.format.yuvOrder = YUVORDER_YUYV;
762 else if (!retval && MATCH("UYVY"))
763 new_params.format.yuvOrder = YUVORDER_UYVY;
767 command_flags |= COMMAND_SETFORMAT;
768 } else if (MATCH("ecp_timing")) {
769 if (!retval && MATCH("normal"))
770 new_params.ecpTiming = 0;
771 else if (!retval && MATCH("slow"))
772 new_params.ecpTiming = 1;
776 command_flags |= COMMAND_SETECPTIMING;
777 } else if (MATCH("color_balance_mode")) {
778 if (!retval && MATCH("manual"))
779 new_params.colourBalance.balanceMode = 3;
780 else if (!retval && MATCH("auto"))
781 new_params.colourBalance.balanceMode = 2;
785 command_flags |= COMMAND_SETCOLOURBALANCE;
786 } else if (MATCH("red_gain")) {
792 new_params.colourBalance.redGain = val;
793 new_params.colourBalance.balanceMode = 1;
797 command_flags |= COMMAND_SETCOLOURBALANCE;
798 } else if (MATCH("green_gain")) {
804 new_params.colourBalance.greenGain = val;
805 new_params.colourBalance.balanceMode = 1;
809 command_flags |= COMMAND_SETCOLOURBALANCE;
810 } else if (MATCH("blue_gain")) {
816 new_params.colourBalance.blueGain = val;
817 new_params.colourBalance.balanceMode = 1;
821 command_flags |= COMMAND_SETCOLOURBALANCE;
822 } else if (MATCH("max_gain")) {
827 /* 1-02 firmware limits gain to 2 */
828 if (FIRMWARE_VERSION(1,2) && val > 2)
832 new_params.exposure.gainMode = 1;
835 new_params.exposure.gainMode = 2;
838 new_params.exposure.gainMode = 3;
841 new_params.exposure.gainMode = 4;
848 command_flags |= COMMAND_SETEXPOSURE;
849 } else if (MATCH("exposure_mode")) {
850 if (!retval && MATCH("auto"))
851 new_params.exposure.expMode = 2;
852 else if (!retval && MATCH("manual")) {
853 if (new_params.exposure.expMode == 2)
854 new_params.exposure.expMode = 3;
855 if(new_params.flickerControl.flickerMode != 0)
856 command_flags |= COMMAND_SETFLICKERCTRL;
857 new_params.flickerControl.flickerMode = 0;
861 command_flags |= COMMAND_SETEXPOSURE;
862 } else if (MATCH("centre_weight")) {
863 if (!retval && MATCH("on"))
864 new_params.exposure.centreWeight = 1;
865 else if (!retval && MATCH("off"))
866 new_params.exposure.centreWeight = 2;
870 command_flags |= COMMAND_SETEXPOSURE;
871 } else if (MATCH("gain")) {
878 new_params.exposure.gain = 0;
881 new_params.exposure.gain = 1;
884 new_params.exposure.gain = 2;
887 new_params.exposure.gain = 3;
893 new_params.exposure.expMode = 1;
894 if(new_params.flickerControl.flickerMode != 0)
895 command_flags |= COMMAND_SETFLICKERCTRL;
896 new_params.flickerControl.flickerMode = 0;
897 command_flags |= COMMAND_SETEXPOSURE;
898 if (new_params.exposure.gain >
899 new_params.exposure.gainMode-1)
902 } else if (MATCH("fine_exp")) {
908 /* 1-02 firmware limits fineExp/2 to 127*/
909 if (FIRMWARE_VERSION(1,2) && val > 127)
911 new_params.exposure.fineExp = val;
912 new_params.exposure.expMode = 1;
913 command_flags |= COMMAND_SETEXPOSURE;
914 if(new_params.flickerControl.flickerMode != 0)
915 command_flags |= COMMAND_SETFLICKERCTRL;
916 new_params.flickerControl.flickerMode = 0;
917 command_flags |= COMMAND_SETFLICKERCTRL;
921 } else if (MATCH("coarse_exp")) {
926 if (val <= MAX_EXP) {
927 if (FIRMWARE_VERSION(1,2) &&
930 new_params.exposure.coarseExpLo =
932 new_params.exposure.coarseExpHi =
934 new_params.exposure.expMode = 1;
935 command_flags |= COMMAND_SETEXPOSURE;
936 if(new_params.flickerControl.flickerMode != 0)
937 command_flags |= COMMAND_SETFLICKERCTRL;
938 new_params.flickerControl.flickerMode = 0;
939 command_flags |= COMMAND_SETFLICKERCTRL;
943 } else if (MATCH("red_comp")) {
948 if (val >= COMP_RED && val <= 255) {
949 new_params.exposure.redComp = val;
950 new_params.exposure.compMode = 1;
951 command_flags |= COMMAND_SETEXPOSURE;
955 } else if (MATCH("green1_comp")) {
960 if (val >= COMP_GREEN1 && val <= 255) {
961 new_params.exposure.green1Comp = val;
962 new_params.exposure.compMode = 1;
963 command_flags |= COMMAND_SETEXPOSURE;
967 } else if (MATCH("green2_comp")) {
972 if (val >= COMP_GREEN2 && val <= 255) {
973 new_params.exposure.green2Comp = val;
974 new_params.exposure.compMode = 1;
975 command_flags |= COMMAND_SETEXPOSURE;
979 } else if (MATCH("blue_comp")) {
984 if (val >= COMP_BLUE && val <= 255) {
985 new_params.exposure.blueComp = val;
986 new_params.exposure.compMode = 1;
987 command_flags |= COMMAND_SETEXPOSURE;
991 } else if (MATCH("apcor_gain1")) {
996 command_flags |= COMMAND_SETAPCOR;
998 new_params.apcor.gain1 = val;
1002 } else if (MATCH("apcor_gain2")) {
1007 command_flags |= COMMAND_SETAPCOR;
1009 new_params.apcor.gain2 = val;
1013 } else if (MATCH("apcor_gain4")) {
1018 command_flags |= COMMAND_SETAPCOR;
1020 new_params.apcor.gain4 = val;
1024 } else if (MATCH("apcor_gain8")) {
1029 command_flags |= COMMAND_SETAPCOR;
1031 new_params.apcor.gain8 = val;
1035 } else if (MATCH("vl_offset_gain1")) {
1041 new_params.vlOffset.gain1 = val;
1045 command_flags |= COMMAND_SETVLOFFSET;
1046 } else if (MATCH("vl_offset_gain2")) {
1052 new_params.vlOffset.gain2 = val;
1056 command_flags |= COMMAND_SETVLOFFSET;
1057 } else if (MATCH("vl_offset_gain4")) {
1063 new_params.vlOffset.gain4 = val;
1067 command_flags |= COMMAND_SETVLOFFSET;
1068 } else if (MATCH("vl_offset_gain8")) {
1074 new_params.vlOffset.gain8 = val;
1078 command_flags |= COMMAND_SETVLOFFSET;
1079 } else if (MATCH("flicker_control")) {
1080 if (!retval && MATCH("on")) {
1081 set_flicker(&new_params, &command_flags, 1);
1082 } else if (!retval && MATCH("off")) {
1083 set_flicker(&new_params, &command_flags, 0);
1087 command_flags |= COMMAND_SETFLICKERCTRL;
1088 } else if (MATCH("mains_frequency")) {
1089 if (!retval && MATCH("50")) {
1091 new_params.flickerControl.coarseJump =
1092 flicker_jumps[new_mains]
1093 [new_params.sensorFps.baserate]
1094 [new_params.sensorFps.divisor];
1095 if (new_params.flickerControl.flickerMode)
1096 command_flags |= COMMAND_SETFLICKERCTRL;
1097 } else if (!retval && MATCH("60")) {
1099 new_params.flickerControl.coarseJump =
1100 flicker_jumps[new_mains]
1101 [new_params.sensorFps.baserate]
1102 [new_params.sensorFps.divisor];
1103 if (new_params.flickerControl.flickerMode)
1104 command_flags |= COMMAND_SETFLICKERCTRL;
1107 } else if (MATCH("allowable_overexposure")) {
1108 if (!retval && MATCH("auto")) {
1109 new_params.flickerControl.allowableOverExposure =
1110 -find_over_exposure(new_params.colourParams.brightness);
1111 if(new_params.flickerControl.flickerMode != 0)
1112 command_flags |= COMMAND_SETFLICKERCTRL;
1119 new_params.flickerControl.
1120 allowableOverExposure = val;
1121 if(new_params.flickerControl.flickerMode != 0)
1122 command_flags |= COMMAND_SETFLICKERCTRL;
1127 } else if (MATCH("compression_mode")) {
1128 if (!retval && MATCH("none"))
1129 new_params.compression.mode =
1130 CPIA_COMPRESSION_NONE;
1131 else if (!retval && MATCH("auto"))
1132 new_params.compression.mode =
1133 CPIA_COMPRESSION_AUTO;
1134 else if (!retval && MATCH("manual"))
1135 new_params.compression.mode =
1136 CPIA_COMPRESSION_MANUAL;
1140 command_flags |= COMMAND_SETCOMPRESSION;
1141 } else if (MATCH("decimation_enable")) {
1142 if (!retval && MATCH("off"))
1143 new_params.compression.decimation = 0;
1144 else if (!retval && MATCH("on"))
1145 new_params.compression.decimation = 1;
1149 command_flags |= COMMAND_SETCOMPRESSION;
1150 } else if (MATCH("compression_target")) {
1151 if (!retval && MATCH("quality"))
1152 new_params.compressionTarget.frTargeting =
1153 CPIA_COMPRESSION_TARGET_QUALITY;
1154 else if (!retval && MATCH("framerate"))
1155 new_params.compressionTarget.frTargeting =
1156 CPIA_COMPRESSION_TARGET_FRAMERATE;
1160 command_flags |= COMMAND_SETCOMPRESSIONTARGET;
1161 } else if (MATCH("target_framerate")) {
1166 if(val > 0 && val <= 30)
1167 new_params.compressionTarget.targetFR = val;
1171 command_flags |= COMMAND_SETCOMPRESSIONTARGET;
1172 } else if (MATCH("target_quality")) {
1177 if(val > 0 && val <= 64)
1178 new_params.compressionTarget.targetQ = val;
1182 command_flags |= COMMAND_SETCOMPRESSIONTARGET;
1183 } else if (MATCH("y_threshold")) {
1189 new_params.yuvThreshold.yThreshold = val;
1193 command_flags |= COMMAND_SETYUVTHRESH;
1194 } else if (MATCH("uv_threshold")) {
1200 new_params.yuvThreshold.uvThreshold = val;
1204 command_flags |= COMMAND_SETYUVTHRESH;
1205 } else if (MATCH("hysteresis")) {
1211 new_params.compressionParams.hysteresis = val;
1215 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1216 } else if (MATCH("threshold_max")) {
1222 new_params.compressionParams.threshMax = val;
1226 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1227 } else if (MATCH("small_step")) {
1233 new_params.compressionParams.smallStep = val;
1237 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1238 } else if (MATCH("large_step")) {
1244 new_params.compressionParams.largeStep = val;
1248 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1249 } else if (MATCH("decimation_hysteresis")) {
1255 new_params.compressionParams.decimationHysteresis = val;
1259 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1260 } else if (MATCH("fr_diff_step_thresh")) {
1266 new_params.compressionParams.frDiffStepThresh = val;
1270 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1271 } else if (MATCH("q_diff_step_thresh")) {
1277 new_params.compressionParams.qDiffStepThresh = val;
1281 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1282 } else if (MATCH("decimation_thresh_mod")) {
1288 new_params.compressionParams.decimationThreshMod = val;
1292 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1293 } else if (MATCH("toplight")) {
1294 if (!retval && MATCH("on"))
1295 new_params.qx3.toplight = 1;
1296 else if (!retval && MATCH("off"))
1297 new_params.qx3.toplight = 0;
1300 command_flags |= COMMAND_SETLIGHTS;
1301 } else if (MATCH("bottomlight")) {
1302 if (!retval && MATCH("on"))
1303 new_params.qx3.bottomlight = 1;
1304 else if (!retval && MATCH("off"))
1305 new_params.qx3.bottomlight = 0;
1308 command_flags |= COMMAND_SETLIGHTS;
1310 DBG("No match found\n");
1315 while (count && isspace(*buffer) && *buffer != '\n') {
1320 if (*buffer == '\0' && count != 1)
1322 else if (*buffer != '\n' && *buffer != ';' &&
1334 #undef FIRMWARE_VERSION
1336 if (command_flags & COMMAND_SETCOLOURPARAMS) {
1337 /* Adjust cam->vp to reflect these changes */
1338 cam->vp.brightness =
1339 new_params.colourParams.brightness*65535/100;
1341 new_params.colourParams.contrast*65535/100;
1343 new_params.colourParams.saturation*65535/100;
1345 if((command_flags & COMMAND_SETEXPOSURE) &&
1346 new_params.exposure.expMode == 2)
1347 cam->exposure_status = EXPOSURE_NORMAL;
1349 memcpy(&cam->params, &new_params, sizeof(struct cam_params));
1350 cam->mainsFreq = new_mains;
1351 cam->cmd_queue |= command_flags;
1354 DBG("error: %d\n", retval);
1356 up(&cam->param_lock);
1359 free_page((unsigned long)page);
1363 static void create_proc_cpia_cam(struct cam_data *cam)
1366 struct proc_dir_entry *ent;
1368 if (!cpia_proc_root || !cam)
1371 sprintf(name, "video%d", cam->vdev.minor);
1373 ent = create_proc_entry(name, S_IFREG|S_IRUGO|S_IWUSR, cpia_proc_root);
1378 ent->read_proc = cpia_read_proc;
1379 ent->write_proc = cpia_write_proc;
1381 size of the proc entry is 3736 bytes for the standard webcam;
1382 the extra features of the QX3 microscope add 189 bytes.
1383 (we have not yet probed the camera to see which type it is).
1385 ent->size = 3736 + 189;
1386 cam->proc_entry = ent;
1389 static void destroy_proc_cpia_cam(struct cam_data *cam)
1393 if (!cam || !cam->proc_entry)
1396 sprintf(name, "video%d", cam->vdev.minor);
1397 remove_proc_entry(name, cpia_proc_root);
1398 cam->proc_entry = NULL;
1401 static void proc_cpia_create(void)
1403 cpia_proc_root = create_proc_entry("cpia", S_IFDIR, NULL);
1406 cpia_proc_root->owner = THIS_MODULE;
1408 LOG("Unable to initialise /proc/cpia\n");
1411 static void __exit proc_cpia_destroy(void)
1413 remove_proc_entry("cpia", NULL);
1415 #endif /* CONFIG_PROC_FS */
1417 /* ----------------------- debug functions ---------------------- */
1419 #define printstatus(cam) \
1420 DBG("%02x %02x %02x %02x %02x %02x %02x %02x\n",\
1421 cam->params.status.systemState, cam->params.status.grabState, \
1422 cam->params.status.streamState, cam->params.status.fatalError, \
1423 cam->params.status.cmdError, cam->params.status.debugFlags, \
1424 cam->params.status.vpStatus, cam->params.status.errorCode);
1426 /* ----------------------- v4l helpers -------------------------- */
1428 /* supported frame palettes and depths */
1429 static inline int valid_mode(u16 palette, u16 depth)
1431 return (palette == VIDEO_PALETTE_GREY && depth == 8) ||
1432 (palette == VIDEO_PALETTE_RGB555 && depth == 16) ||
1433 (palette == VIDEO_PALETTE_RGB565 && depth == 16) ||
1434 (palette == VIDEO_PALETTE_RGB24 && depth == 24) ||
1435 (palette == VIDEO_PALETTE_RGB32 && depth == 32) ||
1436 (palette == VIDEO_PALETTE_YUV422 && depth == 16) ||
1437 (palette == VIDEO_PALETTE_YUYV && depth == 16) ||
1438 (palette == VIDEO_PALETTE_UYVY && depth == 16);
1441 static int match_videosize( int width, int height )
1443 /* return the best match, where 'best' is as always
1444 * the largest that is not bigger than what is requested. */
1445 if (width>=352 && height>=288)
1446 return VIDEOSIZE_352_288; /* CIF */
1448 if (width>=320 && height>=240)
1449 return VIDEOSIZE_320_240; /* SIF */
1451 if (width>=288 && height>=216)
1452 return VIDEOSIZE_288_216;
1454 if (width>=256 && height>=192)
1455 return VIDEOSIZE_256_192;
1457 if (width>=224 && height>=168)
1458 return VIDEOSIZE_224_168;
1460 if (width>=192 && height>=144)
1461 return VIDEOSIZE_192_144;
1463 if (width>=176 && height>=144)
1464 return VIDEOSIZE_176_144; /* QCIF */
1466 if (width>=160 && height>=120)
1467 return VIDEOSIZE_160_120; /* QSIF */
1469 if (width>=128 && height>=96)
1470 return VIDEOSIZE_128_96;
1472 if (width>=88 && height>=72)
1473 return VIDEOSIZE_88_72;
1475 if (width>=64 && height>=48)
1476 return VIDEOSIZE_64_48;
1478 if (width>=48 && height>=48)
1479 return VIDEOSIZE_48_48;
1484 /* these are the capture sizes we support */
1485 static void set_vw_size(struct cam_data *cam)
1487 /* the col/row/start/end values are the result of simple math */
1488 /* study the SetROI-command in cpia developers guide p 2-22 */
1489 /* streamStartLine is set to the recommended value in the cpia */
1490 /* developers guide p 3-37 */
1491 switch(cam->video_size) {
1493 cam->vw.width = 352;
1494 cam->vw.height = 288;
1495 cam->params.format.videoSize=VIDEOSIZE_CIF;
1496 cam->params.roi.colStart=0;
1497 cam->params.roi.rowStart=0;
1498 cam->params.streamStartLine = 120;
1501 cam->vw.width = 320;
1502 cam->vw.height = 240;
1503 cam->params.format.videoSize=VIDEOSIZE_CIF;
1504 cam->params.roi.colStart=2;
1505 cam->params.roi.rowStart=6;
1506 cam->params.streamStartLine = 120;
1508 case VIDEOSIZE_288_216:
1509 cam->vw.width = 288;
1510 cam->vw.height = 216;
1511 cam->params.format.videoSize=VIDEOSIZE_CIF;
1512 cam->params.roi.colStart=4;
1513 cam->params.roi.rowStart=9;
1514 cam->params.streamStartLine = 120;
1516 case VIDEOSIZE_256_192:
1517 cam->vw.width = 256;
1518 cam->vw.height = 192;
1519 cam->params.format.videoSize=VIDEOSIZE_CIF;
1520 cam->params.roi.colStart=6;
1521 cam->params.roi.rowStart=12;
1522 cam->params.streamStartLine = 120;
1524 case VIDEOSIZE_224_168:
1525 cam->vw.width = 224;
1526 cam->vw.height = 168;
1527 cam->params.format.videoSize=VIDEOSIZE_CIF;
1528 cam->params.roi.colStart=8;
1529 cam->params.roi.rowStart=15;
1530 cam->params.streamStartLine = 120;
1532 case VIDEOSIZE_192_144:
1533 cam->vw.width = 192;
1534 cam->vw.height = 144;
1535 cam->params.format.videoSize=VIDEOSIZE_CIF;
1536 cam->params.roi.colStart=10;
1537 cam->params.roi.rowStart=18;
1538 cam->params.streamStartLine = 120;
1540 case VIDEOSIZE_QCIF:
1541 cam->vw.width = 176;
1542 cam->vw.height = 144;
1543 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1544 cam->params.roi.colStart=0;
1545 cam->params.roi.rowStart=0;
1546 cam->params.streamStartLine = 60;
1548 case VIDEOSIZE_QSIF:
1549 cam->vw.width = 160;
1550 cam->vw.height = 120;
1551 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1552 cam->params.roi.colStart=1;
1553 cam->params.roi.rowStart=3;
1554 cam->params.streamStartLine = 60;
1556 case VIDEOSIZE_128_96:
1557 cam->vw.width = 128;
1558 cam->vw.height = 96;
1559 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1560 cam->params.roi.colStart=3;
1561 cam->params.roi.rowStart=6;
1562 cam->params.streamStartLine = 60;
1564 case VIDEOSIZE_88_72:
1566 cam->vw.height = 72;
1567 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1568 cam->params.roi.colStart=5;
1569 cam->params.roi.rowStart=9;
1570 cam->params.streamStartLine = 60;
1572 case VIDEOSIZE_64_48:
1574 cam->vw.height = 48;
1575 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1576 cam->params.roi.colStart=7;
1577 cam->params.roi.rowStart=12;
1578 cam->params.streamStartLine = 60;
1580 case VIDEOSIZE_48_48:
1582 cam->vw.height = 48;
1583 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1584 cam->params.roi.colStart=8;
1585 cam->params.roi.rowStart=6;
1586 cam->params.streamStartLine = 60;
1589 LOG("bad videosize value: %d\n", cam->video_size);
1593 if(cam->vc.width == 0)
1594 cam->vc.width = cam->vw.width;
1595 if(cam->vc.height == 0)
1596 cam->vc.height = cam->vw.height;
1598 cam->params.roi.colStart += cam->vc.x >> 3;
1599 cam->params.roi.colEnd = cam->params.roi.colStart +
1600 (cam->vc.width >> 3);
1601 cam->params.roi.rowStart += cam->vc.y >> 2;
1602 cam->params.roi.rowEnd = cam->params.roi.rowStart +
1603 (cam->vc.height >> 2);
1608 static int allocate_frame_buf(struct cam_data *cam)
1612 cam->frame_buf = rvmalloc(FRAME_NUM * CPIA_MAX_FRAME_SIZE);
1613 if (!cam->frame_buf)
1616 for (i = 0; i < FRAME_NUM; i++)
1617 cam->frame[i].data = cam->frame_buf + i * CPIA_MAX_FRAME_SIZE;
1622 static int free_frame_buf(struct cam_data *cam)
1626 rvfree(cam->frame_buf, FRAME_NUM*CPIA_MAX_FRAME_SIZE);
1627 cam->frame_buf = NULL;
1628 for (i=0; i < FRAME_NUM; i++)
1629 cam->frame[i].data = NULL;
1635 static inline void free_frames(struct cpia_frame frame[FRAME_NUM])
1639 for (i=0; i < FRAME_NUM; i++)
1640 frame[i].state = FRAME_UNUSED;
1644 /**********************************************************************
1648 **********************************************************************/
1649 /* send an arbitrary command to the camera */
1650 static int do_command(struct cam_data *cam, u16 command, u8 a, u8 b, u8 c, u8 d)
1652 int retval, datasize;
1656 case CPIA_COMMAND_GetCPIAVersion:
1657 case CPIA_COMMAND_GetPnPID:
1658 case CPIA_COMMAND_GetCameraStatus:
1659 case CPIA_COMMAND_GetVPVersion:
1662 case CPIA_COMMAND_GetColourParams:
1663 case CPIA_COMMAND_GetColourBalance:
1664 case CPIA_COMMAND_GetExposure:
1665 down(&cam->param_lock);
1668 case CPIA_COMMAND_ReadMCPorts:
1669 case CPIA_COMMAND_ReadVCRegs:
1677 cmd[0] = command>>8;
1678 cmd[1] = command&0xff;
1686 retval = cam->ops->transferCmd(cam->lowlevel_data, cmd, data);
1688 DBG("%x - failed, retval=%d\n", command, retval);
1689 if (command == CPIA_COMMAND_GetColourParams ||
1690 command == CPIA_COMMAND_GetColourBalance ||
1691 command == CPIA_COMMAND_GetExposure)
1692 up(&cam->param_lock);
1695 case CPIA_COMMAND_GetCPIAVersion:
1696 cam->params.version.firmwareVersion = data[0];
1697 cam->params.version.firmwareRevision = data[1];
1698 cam->params.version.vcVersion = data[2];
1699 cam->params.version.vcRevision = data[3];
1701 case CPIA_COMMAND_GetPnPID:
1702 cam->params.pnpID.vendor = data[0]+(((u16)data[1])<<8);
1703 cam->params.pnpID.product = data[2]+(((u16)data[3])<<8);
1704 cam->params.pnpID.deviceRevision =
1705 data[4]+(((u16)data[5])<<8);
1707 case CPIA_COMMAND_GetCameraStatus:
1708 cam->params.status.systemState = data[0];
1709 cam->params.status.grabState = data[1];
1710 cam->params.status.streamState = data[2];
1711 cam->params.status.fatalError = data[3];
1712 cam->params.status.cmdError = data[4];
1713 cam->params.status.debugFlags = data[5];
1714 cam->params.status.vpStatus = data[6];
1715 cam->params.status.errorCode = data[7];
1717 case CPIA_COMMAND_GetVPVersion:
1718 cam->params.vpVersion.vpVersion = data[0];
1719 cam->params.vpVersion.vpRevision = data[1];
1720 cam->params.vpVersion.cameraHeadID =
1721 data[2]+(((u16)data[3])<<8);
1723 case CPIA_COMMAND_GetColourParams:
1724 cam->params.colourParams.brightness = data[0];
1725 cam->params.colourParams.contrast = data[1];
1726 cam->params.colourParams.saturation = data[2];
1727 up(&cam->param_lock);
1729 case CPIA_COMMAND_GetColourBalance:
1730 cam->params.colourBalance.redGain = data[0];
1731 cam->params.colourBalance.greenGain = data[1];
1732 cam->params.colourBalance.blueGain = data[2];
1733 up(&cam->param_lock);
1735 case CPIA_COMMAND_GetExposure:
1736 cam->params.exposure.gain = data[0];
1737 cam->params.exposure.fineExp = data[1];
1738 cam->params.exposure.coarseExpLo = data[2];
1739 cam->params.exposure.coarseExpHi = data[3];
1740 cam->params.exposure.redComp = data[4];
1741 cam->params.exposure.green1Comp = data[5];
1742 cam->params.exposure.green2Comp = data[6];
1743 cam->params.exposure.blueComp = data[7];
1744 up(&cam->param_lock);
1747 case CPIA_COMMAND_ReadMCPorts:
1748 if (!cam->params.qx3.qx3_detected)
1750 /* test button press */
1751 cam->params.qx3.button = ((data[1] & 0x02) == 0);
1752 if (cam->params.qx3.button) {
1753 /* button pressed - unlock the latch */
1754 do_command(cam,CPIA_COMMAND_WriteMCPort,3,0xDF,0xDF,0);
1755 do_command(cam,CPIA_COMMAND_WriteMCPort,3,0xFF,0xFF,0);
1758 /* test whether microscope is cradled */
1759 cam->params.qx3.cradled = ((data[2] & 0x40) == 0);
1769 /* send a command to the camera with an additional data transaction */
1770 static int do_command_extended(struct cam_data *cam, u16 command,
1771 u8 a, u8 b, u8 c, u8 d,
1772 u8 e, u8 f, u8 g, u8 h,
1773 u8 i, u8 j, u8 k, u8 l)
1778 cmd[0] = command>>8;
1779 cmd[1] = command&0xff;
1795 retval = cam->ops->transferCmd(cam->lowlevel_data, cmd, data);
1797 DBG("%x - failed\n", command);
1802 /**********************************************************************
1804 * Colorspace conversion
1806 **********************************************************************/
1807 #define LIMIT(x) ((((x)>0xffffff)?0xff0000:(((x)<=0xffff)?0:(x)&0xff0000))>>16)
1809 static int convert420(unsigned char *yuv, unsigned char *rgb, int out_fmt,
1810 int linesize, int mmap_kludge)
1812 int y, u, v, r, g, b, y1;
1814 /* Odd lines use the same u and v as the previous line.
1815 * Because of compression, it is necessary to get this
1816 * information from the decoded image. */
1818 case VIDEO_PALETTE_RGB555:
1819 y = (*yuv++ - 16) * 76310;
1820 y1 = (*yuv - 16) * 76310;
1821 r = ((*(rgb+1-linesize)) & 0x7c) << 1;
1822 g = ((*(rgb-linesize)) & 0xe0) >> 4 |
1823 ((*(rgb+1-linesize)) & 0x03) << 6;
1824 b = ((*(rgb-linesize)) & 0x1f) << 3;
1825 u = (-53294 * r - 104635 * g + 157929 * b) / 5756495;
1826 v = (157968 * r - 132278 * g - 25690 * b) / 5366159;
1828 g = -25690 * u - 53294 * v;
1830 *rgb++ = ((LIMIT(g+y) & 0xf8) << 2) | (LIMIT(b+y) >> 3);
1831 *rgb++ = ((LIMIT(r+y) & 0xf8) >> 1) | (LIMIT(g+y) >> 6);
1832 *rgb++ = ((LIMIT(g+y1) & 0xf8) << 2) | (LIMIT(b+y1) >> 3);
1833 *rgb = ((LIMIT(r+y1) & 0xf8) >> 1) | (LIMIT(g+y1) >> 6);
1835 case VIDEO_PALETTE_RGB565:
1836 y = (*yuv++ - 16) * 76310;
1837 y1 = (*yuv - 16) * 76310;
1838 r = (*(rgb+1-linesize)) & 0xf8;
1839 g = ((*(rgb-linesize)) & 0xe0) >> 3 |
1840 ((*(rgb+1-linesize)) & 0x07) << 5;
1841 b = ((*(rgb-linesize)) & 0x1f) << 3;
1842 u = (-53294 * r - 104635 * g + 157929 * b) / 5756495;
1843 v = (157968 * r - 132278 * g - 25690 * b) / 5366159;
1845 g = -25690 * u - 53294 * v;
1847 *rgb++ = ((LIMIT(g+y) & 0xfc) << 3) | (LIMIT(b+y) >> 3);
1848 *rgb++ = (LIMIT(r+y) & 0xf8) | (LIMIT(g+y) >> 5);
1849 *rgb++ = ((LIMIT(g+y1) & 0xfc) << 3) | (LIMIT(b+y1) >> 3);
1850 *rgb = (LIMIT(r+y1) & 0xf8) | (LIMIT(g+y1) >> 5);
1853 case VIDEO_PALETTE_RGB24:
1854 case VIDEO_PALETTE_RGB32:
1855 y = (*yuv++ - 16) * 76310;
1856 y1 = (*yuv - 16) * 76310;
1858 r = *(rgb+2-linesize);
1859 g = *(rgb+1-linesize);
1860 b = *(rgb-linesize);
1862 r = *(rgb-linesize);
1863 g = *(rgb+1-linesize);
1864 b = *(rgb+2-linesize);
1866 u = (-53294 * r - 104635 * g + 157929 * b) / 5756495;
1867 v = (157968 * r - 132278 * g - 25690 * b) / 5366159;
1869 g = -25690 * u + -53294 * v;
1872 *rgb++ = LIMIT(b+y);
1873 *rgb++ = LIMIT(g+y);
1874 *rgb++ = LIMIT(r+y);
1875 if(out_fmt == VIDEO_PALETTE_RGB32)
1877 *rgb++ = LIMIT(b+y1);
1878 *rgb++ = LIMIT(g+y1);
1881 *rgb++ = LIMIT(r+y);
1882 *rgb++ = LIMIT(g+y);
1883 *rgb++ = LIMIT(b+y);
1884 if(out_fmt == VIDEO_PALETTE_RGB32)
1886 *rgb++ = LIMIT(r+y1);
1887 *rgb++ = LIMIT(g+y1);
1890 if(out_fmt == VIDEO_PALETTE_RGB32)
1893 case VIDEO_PALETTE_YUV422:
1894 case VIDEO_PALETTE_YUYV:
1896 u = *(rgb+1-linesize);
1898 v = *(rgb+3-linesize);
1904 case VIDEO_PALETTE_UYVY:
1905 u = *(rgb-linesize);
1907 v = *(rgb+2-linesize);
1914 case VIDEO_PALETTE_GREY:
1919 DBG("Empty: %d\n", out_fmt);
1925 static int yuvconvert(unsigned char *yuv, unsigned char *rgb, int out_fmt,
1926 int in_uyvy, int mmap_kludge)
1928 int y, u, v, r, g, b, y1;
1931 case VIDEO_PALETTE_RGB555:
1932 case VIDEO_PALETTE_RGB565:
1933 case VIDEO_PALETTE_RGB24:
1934 case VIDEO_PALETTE_RGB32:
1937 y = (*yuv++ - 16) * 76310;
1939 y1 = (*yuv - 16) * 76310;
1941 y = (*yuv++ - 16) * 76310;
1943 y1 = (*yuv++ - 16) * 76310;
1947 g = -25690 * u + -53294 * v;
1955 /* Just to avoid compiler warnings */
1962 case VIDEO_PALETTE_RGB555:
1963 *rgb++ = ((LIMIT(g+y) & 0xf8) << 2) | (LIMIT(b+y) >> 3);
1964 *rgb++ = ((LIMIT(r+y) & 0xf8) >> 1) | (LIMIT(g+y) >> 6);
1965 *rgb++ = ((LIMIT(g+y1) & 0xf8) << 2) | (LIMIT(b+y1) >> 3);
1966 *rgb = ((LIMIT(r+y1) & 0xf8) >> 1) | (LIMIT(g+y1) >> 6);
1968 case VIDEO_PALETTE_RGB565:
1969 *rgb++ = ((LIMIT(g+y) & 0xfc) << 3) | (LIMIT(b+y) >> 3);
1970 *rgb++ = (LIMIT(r+y) & 0xf8) | (LIMIT(g+y) >> 5);
1971 *rgb++ = ((LIMIT(g+y1) & 0xfc) << 3) | (LIMIT(b+y1) >> 3);
1972 *rgb = (LIMIT(r+y1) & 0xf8) | (LIMIT(g+y1) >> 5);
1974 case VIDEO_PALETTE_RGB24:
1976 *rgb++ = LIMIT(b+y);
1977 *rgb++ = LIMIT(g+y);
1978 *rgb++ = LIMIT(r+y);
1979 *rgb++ = LIMIT(b+y1);
1980 *rgb++ = LIMIT(g+y1);
1983 *rgb++ = LIMIT(r+y);
1984 *rgb++ = LIMIT(g+y);
1985 *rgb++ = LIMIT(b+y);
1986 *rgb++ = LIMIT(r+y1);
1987 *rgb++ = LIMIT(g+y1);
1991 case VIDEO_PALETTE_RGB32:
1993 *rgb++ = LIMIT(b+y);
1994 *rgb++ = LIMIT(g+y);
1995 *rgb++ = LIMIT(r+y);
1997 *rgb++ = LIMIT(b+y1);
1998 *rgb++ = LIMIT(g+y1);
2001 *rgb++ = LIMIT(r+y);
2002 *rgb++ = LIMIT(g+y);
2003 *rgb++ = LIMIT(b+y);
2005 *rgb++ = LIMIT(r+y1);
2006 *rgb++ = LIMIT(g+y1);
2010 case VIDEO_PALETTE_GREY:
2014 case VIDEO_PALETTE_YUV422:
2015 case VIDEO_PALETTE_YUYV:
2021 case VIDEO_PALETTE_UYVY:
2028 DBG("Empty: %d\n", out_fmt);
2033 static int skipcount(int count, int fmt)
2036 case VIDEO_PALETTE_GREY:
2038 case VIDEO_PALETTE_RGB555:
2039 case VIDEO_PALETTE_RGB565:
2040 case VIDEO_PALETTE_YUV422:
2041 case VIDEO_PALETTE_YUYV:
2042 case VIDEO_PALETTE_UYVY:
2044 case VIDEO_PALETTE_RGB24:
2046 case VIDEO_PALETTE_RGB32:
2053 static int parse_picture(struct cam_data *cam, int size)
2055 u8 *obuf, *ibuf, *end_obuf;
2056 int ll, in_uyvy, compressed, decimation, even_line, origsize, out_fmt;
2057 int rows, cols, linesize, subsample_422;
2059 /* make sure params don't change while we are decoding */
2060 down(&cam->param_lock);
2062 obuf = cam->decompressed_frame.data;
2063 end_obuf = obuf+CPIA_MAX_FRAME_SIZE;
2064 ibuf = cam->raw_image;
2066 out_fmt = cam->vp.palette;
2068 if ((ibuf[0] != MAGIC_0) || (ibuf[1] != MAGIC_1)) {
2069 LOG("header not found\n");
2070 up(&cam->param_lock);
2074 if ((ibuf[16] != VIDEOSIZE_QCIF) && (ibuf[16] != VIDEOSIZE_CIF)) {
2075 LOG("wrong video size\n");
2076 up(&cam->param_lock);
2080 if (ibuf[17] != SUBSAMPLE_420 && ibuf[17] != SUBSAMPLE_422) {
2081 LOG("illegal subtype %d\n",ibuf[17]);
2082 up(&cam->param_lock);
2085 subsample_422 = ibuf[17] == SUBSAMPLE_422;
2087 if (ibuf[18] != YUVORDER_YUYV && ibuf[18] != YUVORDER_UYVY) {
2088 LOG("illegal yuvorder %d\n",ibuf[18]);
2089 up(&cam->param_lock);
2092 in_uyvy = ibuf[18] == YUVORDER_UYVY;
2094 if ((ibuf[24] != cam->params.roi.colStart) ||
2095 (ibuf[25] != cam->params.roi.colEnd) ||
2096 (ibuf[26] != cam->params.roi.rowStart) ||
2097 (ibuf[27] != cam->params.roi.rowEnd)) {
2098 LOG("ROI mismatch\n");
2099 up(&cam->param_lock);
2102 cols = 8*(ibuf[25] - ibuf[24]);
2103 rows = 4*(ibuf[27] - ibuf[26]);
2106 if ((ibuf[28] != NOT_COMPRESSED) && (ibuf[28] != COMPRESSED)) {
2107 LOG("illegal compression %d\n",ibuf[28]);
2108 up(&cam->param_lock);
2111 compressed = (ibuf[28] == COMPRESSED);
2113 if (ibuf[29] != NO_DECIMATION && ibuf[29] != DECIMATION_ENAB) {
2114 LOG("illegal decimation %d\n",ibuf[29]);
2115 up(&cam->param_lock);
2118 decimation = (ibuf[29] == DECIMATION_ENAB);
2120 cam->params.yuvThreshold.yThreshold = ibuf[30];
2121 cam->params.yuvThreshold.uvThreshold = ibuf[31];
2122 cam->params.status.systemState = ibuf[32];
2123 cam->params.status.grabState = ibuf[33];
2124 cam->params.status.streamState = ibuf[34];
2125 cam->params.status.fatalError = ibuf[35];
2126 cam->params.status.cmdError = ibuf[36];
2127 cam->params.status.debugFlags = ibuf[37];
2128 cam->params.status.vpStatus = ibuf[38];
2129 cam->params.status.errorCode = ibuf[39];
2130 cam->fps = ibuf[41];
2131 up(&cam->param_lock);
2133 linesize = skipcount(cols, out_fmt);
2134 ibuf += FRAME_HEADER_SIZE;
2135 size -= FRAME_HEADER_SIZE;
2136 ll = ibuf[0] | (ibuf[1] << 8);
2143 LOG("Insufficient data in buffer\n");
2148 if (!compressed || (compressed && !(*ibuf & 1))) {
2149 if(subsample_422 || even_line) {
2150 obuf += yuvconvert(ibuf, obuf, out_fmt,
2151 in_uyvy, cam->mmap_kludge);
2155 /* SUBSAMPLE_420 on an odd line */
2156 obuf += convert420(ibuf, obuf,
2163 /*skip compressed interval from previous frame*/
2164 obuf += skipcount(*ibuf >> 1, out_fmt);
2165 if (obuf > end_obuf) {
2166 LOG("Insufficient buffer size\n");
2175 DBG("EOL not found giving up after %d/%d"
2176 " bytes\n", origsize-size, origsize);
2180 ++ibuf; /* skip over EOL */
2182 if ((size > 3) && (ibuf[0] == EOI) && (ibuf[1] == EOI) &&
2183 (ibuf[2] == EOI) && (ibuf[3] == EOI)) {
2189 /* skip the odd lines for now */
2194 ll = ibuf[0] | (ibuf[1] << 8);
2195 ibuf += 2; /* skip over line length */
2198 even_line = !even_line;
2200 LOG("line length was not 1 but %d after %d/%d bytes\n",
2201 ll, origsize-size, origsize);
2207 /* interpolate odd rows */
2210 prev = cam->decompressed_frame.data;
2211 obuf = prev+linesize;
2212 next = obuf+linesize;
2213 for(i=1; i<rows-1; i+=2) {
2214 for(j=0; j<linesize; ++j) {
2215 *obuf++ = ((int)*prev++ + *next++) / 2;
2221 /* last row is odd, just copy previous row */
2222 memcpy(obuf, prev, linesize);
2225 cam->decompressed_frame.count = obuf-cam->decompressed_frame.data;
2227 return cam->decompressed_frame.count;
2230 /* InitStreamCap wrapper to select correct start line */
2231 static inline int init_stream_cap(struct cam_data *cam)
2233 return do_command(cam, CPIA_COMMAND_InitStreamCap,
2234 0, cam->params.streamStartLine, 0, 0);
2238 /* find_over_exposure
2239 * Finds a suitable value of OverExposure for use with SetFlickerCtrl
2240 * Some calculation is required because this value changes with the brightness
2241 * set with SetColourParameters
2243 * Parameters: Brightness - last brightness value set with SetColourParameters
2245 * Returns: OverExposure value to use with SetFlickerCtrl
2247 #define FLICKER_MAX_EXPOSURE 250
2248 #define FLICKER_ALLOWABLE_OVER_EXPOSURE 146
2249 #define FLICKER_BRIGHTNESS_CONSTANT 59
2250 static int find_over_exposure(int brightness)
2252 int MaxAllowableOverExposure, OverExposure;
2254 MaxAllowableOverExposure = FLICKER_MAX_EXPOSURE - brightness -
2255 FLICKER_BRIGHTNESS_CONSTANT;
2257 if (MaxAllowableOverExposure < FLICKER_ALLOWABLE_OVER_EXPOSURE) {
2258 OverExposure = MaxAllowableOverExposure;
2260 OverExposure = FLICKER_ALLOWABLE_OVER_EXPOSURE;
2263 return OverExposure;
2265 #undef FLICKER_MAX_EXPOSURE
2266 #undef FLICKER_ALLOWABLE_OVER_EXPOSURE
2267 #undef FLICKER_BRIGHTNESS_CONSTANT
2269 /* update various camera modes and settings */
2270 static void dispatch_commands(struct cam_data *cam)
2272 down(&cam->param_lock);
2273 if (cam->cmd_queue==COMMAND_NONE) {
2274 up(&cam->param_lock);
2277 DEB_BYTE(cam->cmd_queue);
2278 DEB_BYTE(cam->cmd_queue>>8);
2279 if (cam->cmd_queue & COMMAND_SETFORMAT) {
2280 do_command(cam, CPIA_COMMAND_SetFormat,
2281 cam->params.format.videoSize,
2282 cam->params.format.subSample,
2283 cam->params.format.yuvOrder, 0);
2284 do_command(cam, CPIA_COMMAND_SetROI,
2285 cam->params.roi.colStart, cam->params.roi.colEnd,
2286 cam->params.roi.rowStart, cam->params.roi.rowEnd);
2287 cam->first_frame = 1;
2290 if (cam->cmd_queue & COMMAND_SETCOLOURPARAMS)
2291 do_command(cam, CPIA_COMMAND_SetColourParams,
2292 cam->params.colourParams.brightness,
2293 cam->params.colourParams.contrast,
2294 cam->params.colourParams.saturation, 0);
2296 if (cam->cmd_queue & COMMAND_SETAPCOR)
2297 do_command(cam, CPIA_COMMAND_SetApcor,
2298 cam->params.apcor.gain1,
2299 cam->params.apcor.gain2,
2300 cam->params.apcor.gain4,
2301 cam->params.apcor.gain8);
2303 if (cam->cmd_queue & COMMAND_SETVLOFFSET)
2304 do_command(cam, CPIA_COMMAND_SetVLOffset,
2305 cam->params.vlOffset.gain1,
2306 cam->params.vlOffset.gain2,
2307 cam->params.vlOffset.gain4,
2308 cam->params.vlOffset.gain8);
2310 if (cam->cmd_queue & COMMAND_SETEXPOSURE) {
2311 do_command_extended(cam, CPIA_COMMAND_SetExposure,
2312 cam->params.exposure.gainMode,
2314 cam->params.exposure.compMode,
2315 cam->params.exposure.centreWeight,
2316 cam->params.exposure.gain,
2317 cam->params.exposure.fineExp,
2318 cam->params.exposure.coarseExpLo,
2319 cam->params.exposure.coarseExpHi,
2320 cam->params.exposure.redComp,
2321 cam->params.exposure.green1Comp,
2322 cam->params.exposure.green2Comp,
2323 cam->params.exposure.blueComp);
2324 if(cam->params.exposure.expMode != 1) {
2325 do_command_extended(cam, CPIA_COMMAND_SetExposure,
2327 cam->params.exposure.expMode,
2329 cam->params.exposure.gain,
2330 cam->params.exposure.fineExp,
2331 cam->params.exposure.coarseExpLo,
2332 cam->params.exposure.coarseExpHi,
2337 if (cam->cmd_queue & COMMAND_SETCOLOURBALANCE) {
2338 if (cam->params.colourBalance.balanceMode == 1) {
2339 do_command(cam, CPIA_COMMAND_SetColourBalance,
2341 cam->params.colourBalance.redGain,
2342 cam->params.colourBalance.greenGain,
2343 cam->params.colourBalance.blueGain);
2344 do_command(cam, CPIA_COMMAND_SetColourBalance,
2347 if (cam->params.colourBalance.balanceMode == 2) {
2348 do_command(cam, CPIA_COMMAND_SetColourBalance,
2351 if (cam->params.colourBalance.balanceMode == 3) {
2352 do_command(cam, CPIA_COMMAND_SetColourBalance,
2357 if (cam->cmd_queue & COMMAND_SETCOMPRESSIONTARGET)
2358 do_command(cam, CPIA_COMMAND_SetCompressionTarget,
2359 cam->params.compressionTarget.frTargeting,
2360 cam->params.compressionTarget.targetFR,
2361 cam->params.compressionTarget.targetQ, 0);
2363 if (cam->cmd_queue & COMMAND_SETYUVTHRESH)
2364 do_command(cam, CPIA_COMMAND_SetYUVThresh,
2365 cam->params.yuvThreshold.yThreshold,
2366 cam->params.yuvThreshold.uvThreshold, 0, 0);
2368 if (cam->cmd_queue & COMMAND_SETCOMPRESSIONPARAMS)
2369 do_command_extended(cam, CPIA_COMMAND_SetCompressionParams,
2371 cam->params.compressionParams.hysteresis,
2372 cam->params.compressionParams.threshMax,
2373 cam->params.compressionParams.smallStep,
2374 cam->params.compressionParams.largeStep,
2375 cam->params.compressionParams.decimationHysteresis,
2376 cam->params.compressionParams.frDiffStepThresh,
2377 cam->params.compressionParams.qDiffStepThresh,
2378 cam->params.compressionParams.decimationThreshMod);
2380 if (cam->cmd_queue & COMMAND_SETCOMPRESSION)
2381 do_command(cam, CPIA_COMMAND_SetCompression,
2382 cam->params.compression.mode,
2383 cam->params.compression.decimation, 0, 0);
2385 if (cam->cmd_queue & COMMAND_SETSENSORFPS)
2386 do_command(cam, CPIA_COMMAND_SetSensorFPS,
2387 cam->params.sensorFps.divisor,
2388 cam->params.sensorFps.baserate, 0, 0);
2390 if (cam->cmd_queue & COMMAND_SETFLICKERCTRL)
2391 do_command(cam, CPIA_COMMAND_SetFlickerCtrl,
2392 cam->params.flickerControl.flickerMode,
2393 cam->params.flickerControl.coarseJump,
2394 abs(cam->params.flickerControl.allowableOverExposure),
2397 if (cam->cmd_queue & COMMAND_SETECPTIMING)
2398 do_command(cam, CPIA_COMMAND_SetECPTiming,
2399 cam->params.ecpTiming, 0, 0, 0);
2401 if (cam->cmd_queue & COMMAND_PAUSE)
2402 do_command(cam, CPIA_COMMAND_EndStreamCap, 0, 0, 0, 0);
2404 if (cam->cmd_queue & COMMAND_RESUME)
2405 init_stream_cap(cam);
2407 if (cam->cmd_queue & COMMAND_SETLIGHTS && cam->params.qx3.qx3_detected)
2409 int p1 = (cam->params.qx3.bottomlight == 0) << 1;
2410 int p2 = (cam->params.qx3.toplight == 0) << 3;
2411 do_command(cam, CPIA_COMMAND_WriteVCReg, 0x90, 0x8F, 0x50, 0);
2412 do_command(cam, CPIA_COMMAND_WriteMCPort, 2, 0, (p1|p2|0xE0), 0);
2415 cam->cmd_queue = COMMAND_NONE;
2416 up(&cam->param_lock);
2422 static void set_flicker(struct cam_params *params, volatile u32 *command_flags,
2425 /* Everything in here is from the Windows driver */
2426 #define FIRMWARE_VERSION(x,y) (params->version.firmwareVersion == (x) && \
2427 params->version.firmwareRevision == (y))
2428 /* define for compgain calculation */
2430 #define COMPGAIN(base, curexp, newexp) \
2431 (u8) ((((float) base - 128.0) * ((float) curexp / (float) newexp)) + 128.5)
2432 #define EXP_FROM_COMP(basecomp, curcomp, curexp) \
2433 (u16)((float)curexp * (float)(u8)(curcomp + 128) / (float)(u8)(basecomp - 128))
2435 /* equivalent functions without floating point math */
2436 #define COMPGAIN(base, curexp, newexp) \
2437 (u8)(128 + (((u32)(2*(base-128)*curexp + newexp)) / (2* newexp)) )
2438 #define EXP_FROM_COMP(basecomp, curcomp, curexp) \
2439 (u16)(((u32)(curexp * (u8)(curcomp + 128)) / (u8)(basecomp - 128)))
2443 int currentexp = params->exposure.coarseExpLo +
2444 params->exposure.coarseExpHi*256;
2447 int cj = params->flickerControl.coarseJump;
2448 params->flickerControl.flickerMode = 1;
2449 params->flickerControl.disabled = 0;
2450 if(params->exposure.expMode != 2)
2451 *command_flags |= COMMAND_SETEXPOSURE;
2452 params->exposure.expMode = 2;
2453 currentexp = currentexp << params->exposure.gain;
2454 params->exposure.gain = 0;
2455 /* round down current exposure to nearest value */
2456 startexp = (currentexp + ROUND_UP_EXP_FOR_FLICKER) / cj;
2459 startexp = (startexp * cj) - 1;
2460 if(FIRMWARE_VERSION(1,2))
2461 while(startexp > MAX_EXP_102)
2464 while(startexp > MAX_EXP)
2466 params->exposure.coarseExpLo = startexp & 0xff;
2467 params->exposure.coarseExpHi = startexp >> 8;
2468 if (currentexp > startexp) {
2469 if (currentexp > (2 * startexp))
2470 currentexp = 2 * startexp;
2471 params->exposure.redComp = COMPGAIN (COMP_RED, currentexp, startexp);
2472 params->exposure.green1Comp = COMPGAIN (COMP_GREEN1, currentexp, startexp);
2473 params->exposure.green2Comp = COMPGAIN (COMP_GREEN2, currentexp, startexp);
2474 params->exposure.blueComp = COMPGAIN (COMP_BLUE, currentexp, startexp);
2476 params->exposure.redComp = COMP_RED;
2477 params->exposure.green1Comp = COMP_GREEN1;
2478 params->exposure.green2Comp = COMP_GREEN2;
2479 params->exposure.blueComp = COMP_BLUE;
2481 if(FIRMWARE_VERSION(1,2))
2482 params->exposure.compMode = 0;
2484 params->exposure.compMode = 1;
2486 params->apcor.gain1 = 0x18;
2487 params->apcor.gain2 = 0x18;
2488 params->apcor.gain4 = 0x16;
2489 params->apcor.gain8 = 0x14;
2490 *command_flags |= COMMAND_SETAPCOR;
2492 params->flickerControl.flickerMode = 0;
2493 params->flickerControl.disabled = 1;
2494 /* Coarse = average of equivalent coarse for each comp channel */
2495 startexp = EXP_FROM_COMP(COMP_RED, params->exposure.redComp, currentexp);
2496 startexp += EXP_FROM_COMP(COMP_GREEN1, params->exposure.green1Comp, currentexp);
2497 startexp += EXP_FROM_COMP(COMP_GREEN2, params->exposure.green2Comp, currentexp);
2498 startexp += EXP_FROM_COMP(COMP_BLUE, params->exposure.blueComp, currentexp);
2499 startexp = startexp >> 2;
2500 while(startexp > MAX_EXP &&
2501 params->exposure.gain < params->exposure.gainMode-1) {
2502 startexp = startexp >> 1;
2503 ++params->exposure.gain;
2505 if(FIRMWARE_VERSION(1,2) && startexp > MAX_EXP_102)
2506 startexp = MAX_EXP_102;
2507 if(startexp > MAX_EXP)
2509 params->exposure.coarseExpLo = startexp&0xff;
2510 params->exposure.coarseExpHi = startexp >> 8;
2511 params->exposure.redComp = COMP_RED;
2512 params->exposure.green1Comp = COMP_GREEN1;
2513 params->exposure.green2Comp = COMP_GREEN2;
2514 params->exposure.blueComp = COMP_BLUE;
2515 params->exposure.compMode = 1;
2516 *command_flags |= COMMAND_SETEXPOSURE;
2517 params->apcor.gain1 = 0x18;
2518 params->apcor.gain2 = 0x16;
2519 params->apcor.gain4 = 0x24;
2520 params->apcor.gain8 = 0x34;
2521 *command_flags |= COMMAND_SETAPCOR;
2523 params->vlOffset.gain1 = 20;
2524 params->vlOffset.gain2 = 24;
2525 params->vlOffset.gain4 = 26;
2526 params->vlOffset.gain8 = 26;
2527 *command_flags |= COMMAND_SETVLOFFSET;
2528 #undef FIRMWARE_VERSION
2529 #undef EXP_FROM_COMP
2533 #define FIRMWARE_VERSION(x,y) (cam->params.version.firmwareVersion == (x) && \
2534 cam->params.version.firmwareRevision == (y))
2535 /* monitor the exposure and adjust the sensor frame rate if needed */
2536 static void monitor_exposure(struct cam_data *cam)
2538 u8 exp_acc, bcomp, gain, coarseL, cmd[8], data[8];
2539 int retval, light_exp, dark_exp, very_dark_exp;
2540 int old_exposure, new_exposure, framerate;
2542 /* get necessary stats and register settings from camera */
2543 /* do_command can't handle this, so do it ourselves */
2544 cmd[0] = CPIA_COMMAND_ReadVPRegs>>8;
2545 cmd[1] = CPIA_COMMAND_ReadVPRegs&0xff;
2552 retval = cam->ops->transferCmd(cam->lowlevel_data, cmd, data);
2554 LOG("ReadVPRegs(30,4,9,8) - failed, retval=%d\n",
2563 down(&cam->param_lock);
2564 light_exp = cam->params.colourParams.brightness +
2565 TC - 50 + EXP_ACC_LIGHT;
2568 dark_exp = cam->params.colourParams.brightness +
2569 TC - 50 - EXP_ACC_DARK;
2572 very_dark_exp = dark_exp/2;
2574 old_exposure = cam->params.exposure.coarseExpHi * 256 +
2575 cam->params.exposure.coarseExpLo;
2577 if(!cam->params.flickerControl.disabled) {
2578 /* Flicker control on */
2579 int max_comp = FIRMWARE_VERSION(1,2) ? MAX_COMP : HIGH_COMP_102;
2580 bcomp += 128; /* decode */
2581 if(bcomp >= max_comp && exp_acc < dark_exp) {
2583 if(exp_acc < very_dark_exp) {
2585 if(cam->exposure_status == EXPOSURE_VERY_DARK)
2586 ++cam->exposure_count;
2588 cam->exposure_status = EXPOSURE_VERY_DARK;
2589 cam->exposure_count = 1;
2593 if(cam->exposure_status == EXPOSURE_DARK)
2594 ++cam->exposure_count;
2596 cam->exposure_status = EXPOSURE_DARK;
2597 cam->exposure_count = 1;
2600 } else if(old_exposure <= LOW_EXP || exp_acc > light_exp) {
2602 if(old_exposure <= VERY_LOW_EXP) {
2604 if(cam->exposure_status == EXPOSURE_VERY_LIGHT)
2605 ++cam->exposure_count;
2607 cam->exposure_status = EXPOSURE_VERY_LIGHT;
2608 cam->exposure_count = 1;
2612 if(cam->exposure_status == EXPOSURE_LIGHT)
2613 ++cam->exposure_count;
2615 cam->exposure_status = EXPOSURE_LIGHT;
2616 cam->exposure_count = 1;
2620 /* not dark or light */
2621 cam->exposure_status = EXPOSURE_NORMAL;
2624 /* Flicker control off */
2625 if(old_exposure >= MAX_EXP && exp_acc < dark_exp) {
2627 if(exp_acc < very_dark_exp) {
2629 if(cam->exposure_status == EXPOSURE_VERY_DARK)
2630 ++cam->exposure_count;
2632 cam->exposure_status = EXPOSURE_VERY_DARK;
2633 cam->exposure_count = 1;
2637 if(cam->exposure_status == EXPOSURE_DARK)
2638 ++cam->exposure_count;
2640 cam->exposure_status = EXPOSURE_DARK;
2641 cam->exposure_count = 1;
2644 } else if(old_exposure <= LOW_EXP || exp_acc > light_exp) {
2646 if(old_exposure <= VERY_LOW_EXP) {
2648 if(cam->exposure_status == EXPOSURE_VERY_LIGHT)
2649 ++cam->exposure_count;
2651 cam->exposure_status = EXPOSURE_VERY_LIGHT;
2652 cam->exposure_count = 1;
2656 if(cam->exposure_status == EXPOSURE_LIGHT)
2657 ++cam->exposure_count;
2659 cam->exposure_status = EXPOSURE_LIGHT;
2660 cam->exposure_count = 1;
2664 /* not dark or light */
2665 cam->exposure_status = EXPOSURE_NORMAL;
2669 framerate = cam->fps;
2670 if(framerate > 30 || framerate < 1)
2673 if(!cam->params.flickerControl.disabled) {
2674 /* Flicker control on */
2675 if((cam->exposure_status == EXPOSURE_VERY_DARK ||
2676 cam->exposure_status == EXPOSURE_DARK) &&
2677 cam->exposure_count >= DARK_TIME*framerate &&
2678 cam->params.sensorFps.divisor < 3) {
2680 /* dark for too long */
2681 ++cam->params.sensorFps.divisor;
2682 cam->cmd_queue |= COMMAND_SETSENSORFPS;
2684 cam->params.flickerControl.coarseJump =
2685 flicker_jumps[cam->mainsFreq]
2686 [cam->params.sensorFps.baserate]
2687 [cam->params.sensorFps.divisor];
2688 cam->cmd_queue |= COMMAND_SETFLICKERCTRL;
2690 new_exposure = cam->params.flickerControl.coarseJump-1;
2691 while(new_exposure < old_exposure/2)
2692 new_exposure += cam->params.flickerControl.coarseJump;
2693 cam->params.exposure.coarseExpLo = new_exposure & 0xff;
2694 cam->params.exposure.coarseExpHi = new_exposure >> 8;
2695 cam->cmd_queue |= COMMAND_SETEXPOSURE;
2696 cam->exposure_status = EXPOSURE_NORMAL;
2697 LOG("Automatically decreasing sensor_fps\n");
2699 } else if((cam->exposure_status == EXPOSURE_VERY_LIGHT ||
2700 cam->exposure_status == EXPOSURE_LIGHT) &&
2701 cam->exposure_count >= LIGHT_TIME*framerate &&
2702 cam->params.sensorFps.divisor > 0) {
2704 /* light for too long */
2705 int max_exp = FIRMWARE_VERSION(1,2) ? MAX_EXP_102 : MAX_EXP ;
2707 --cam->params.sensorFps.divisor;
2708 cam->cmd_queue |= COMMAND_SETSENSORFPS;
2710 cam->params.flickerControl.coarseJump =
2711 flicker_jumps[cam->mainsFreq]
2712 [cam->params.sensorFps.baserate]
2713 [cam->params.sensorFps.divisor];
2714 cam->cmd_queue |= COMMAND_SETFLICKERCTRL;
2716 new_exposure = cam->params.flickerControl.coarseJump-1;
2717 while(new_exposure < 2*old_exposure &&
2719 cam->params.flickerControl.coarseJump < max_exp)
2720 new_exposure += cam->params.flickerControl.coarseJump;
2721 cam->params.exposure.coarseExpLo = new_exposure & 0xff;
2722 cam->params.exposure.coarseExpHi = new_exposure >> 8;
2723 cam->cmd_queue |= COMMAND_SETEXPOSURE;
2724 cam->exposure_status = EXPOSURE_NORMAL;
2725 LOG("Automatically increasing sensor_fps\n");
2728 /* Flicker control off */
2729 if((cam->exposure_status == EXPOSURE_VERY_DARK ||
2730 cam->exposure_status == EXPOSURE_DARK) &&
2731 cam->exposure_count >= DARK_TIME*framerate &&
2732 cam->params.sensorFps.divisor < 3) {
2734 /* dark for too long */
2735 ++cam->params.sensorFps.divisor;
2736 cam->cmd_queue |= COMMAND_SETSENSORFPS;
2738 if(cam->params.exposure.gain > 0) {
2739 --cam->params.exposure.gain;
2740 cam->cmd_queue |= COMMAND_SETEXPOSURE;
2742 cam->exposure_status = EXPOSURE_NORMAL;
2743 LOG("Automatically decreasing sensor_fps\n");
2745 } else if((cam->exposure_status == EXPOSURE_VERY_LIGHT ||
2746 cam->exposure_status == EXPOSURE_LIGHT) &&
2747 cam->exposure_count >= LIGHT_TIME*framerate &&
2748 cam->params.sensorFps.divisor > 0) {
2750 /* light for too long */
2751 --cam->params.sensorFps.divisor;
2752 cam->cmd_queue |= COMMAND_SETSENSORFPS;
2754 if(cam->params.exposure.gain <
2755 cam->params.exposure.gainMode-1) {
2756 ++cam->params.exposure.gain;
2757 cam->cmd_queue |= COMMAND_SETEXPOSURE;
2759 cam->exposure_status = EXPOSURE_NORMAL;
2760 LOG("Automatically increasing sensor_fps\n");
2763 up(&cam->param_lock);
2766 /*-----------------------------------------------------------------*/
2767 /* if flicker is switched off, this function switches it back on.It checks,
2768 however, that conditions are suitable before restarting it.
2769 This should only be called for firmware version 1.2.
2771 It also adjust the colour balance when an exposure step is detected - as
2772 long as flicker is running
2774 static void restart_flicker(struct cam_data *cam)
2776 int cam_exposure, old_exp;
2777 if(!FIRMWARE_VERSION(1,2))
2779 down(&cam->param_lock);
2780 if(cam->params.flickerControl.flickerMode == 0 ||
2781 cam->raw_image[39] == 0) {
2782 up(&cam->param_lock);
2785 cam_exposure = cam->raw_image[39]*2;
2786 old_exp = cam->params.exposure.coarseExpLo +
2787 cam->params.exposure.coarseExpHi*256;
2789 see how far away camera exposure is from a valid
2790 flicker exposure value
2792 cam_exposure %= cam->params.flickerControl.coarseJump;
2793 if(!cam->params.flickerControl.disabled &&
2794 cam_exposure <= cam->params.flickerControl.coarseJump - 3) {
2795 /* Flicker control auto-disabled */
2796 cam->params.flickerControl.disabled = 1;
2799 if(cam->params.flickerControl.disabled &&
2800 cam->params.flickerControl.flickerMode &&
2801 old_exp > cam->params.flickerControl.coarseJump +
2802 ROUND_UP_EXP_FOR_FLICKER) {
2803 /* exposure is now high enough to switch
2804 flicker control back on */
2805 set_flicker(&cam->params, &cam->cmd_queue, 1);
2806 if((cam->cmd_queue & COMMAND_SETEXPOSURE) &&
2807 cam->params.exposure.expMode == 2)
2808 cam->exposure_status = EXPOSURE_NORMAL;
2811 up(&cam->param_lock);
2813 #undef FIRMWARE_VERSION
2815 static int clear_stall(struct cam_data *cam)
2817 /* FIXME: Does this actually work? */
2818 LOG("Clearing stall\n");
2820 cam->ops->streamRead(cam->lowlevel_data, cam->raw_image, 0);
2821 do_command(cam, CPIA_COMMAND_GetCameraStatus,0,0,0,0);
2822 return cam->params.status.streamState != STREAM_PAUSED;
2825 /* kernel thread function to read image from camera */
2826 static int fetch_frame(void *data)
2828 int image_size, retry;
2829 struct cam_data *cam = (struct cam_data *)data;
2830 unsigned long oldjif, rate, diff;
2832 /* Allow up to two bad images in a row to be read and
2833 * ignored before an error is reported */
2834 for (retry = 0; retry < 3; ++retry) {
2836 DBG("retry=%d\n", retry);
2841 /* load first frame always uncompressed */
2842 if (cam->first_frame &&
2843 cam->params.compression.mode != CPIA_COMPRESSION_NONE) {
2844 do_command(cam, CPIA_COMMAND_SetCompression,
2845 CPIA_COMPRESSION_NONE,
2846 NO_DECIMATION, 0, 0);
2847 /* Trial & error - Discarding a frame prevents the
2848 first frame from having an error in the data. */
2849 do_command(cam, CPIA_COMMAND_DiscardFrame, 0, 0, 0, 0);
2852 /* init camera upload */
2853 if (do_command(cam, CPIA_COMMAND_GrabFrame, 0,
2854 cam->params.streamStartLine, 0, 0))
2857 if (cam->ops->wait_for_stream_ready) {
2858 /* loop until image ready */
2860 do_command(cam, CPIA_COMMAND_GetCameraStatus,0,0,0,0);
2861 while (cam->params.status.streamState != STREAM_READY) {
2862 if(++count > READY_TIMEOUT)
2864 if(cam->params.status.streamState ==
2867 if(!clear_stall(cam))
2873 /* sleep for 10 ms, hopefully ;) */
2874 current->state = TASK_INTERRUPTIBLE;
2876 schedule_timeout(10*HZ/1000);
2877 if (signal_pending(current))
2880 do_command(cam, CPIA_COMMAND_GetCameraStatus,
2883 if(cam->params.status.streamState != STREAM_READY) {
2890 /* grab image from camera */
2892 image_size = cam->ops->streamRead(cam->lowlevel_data,
2894 if (image_size <= 0) {
2895 DBG("streamRead failed: %d\n", image_size);
2899 rate = image_size * HZ / 1024;
2900 diff = jiffies-oldjif;
2901 cam->transfer_rate = diff==0 ? rate : rate/diff;
2902 /* diff==0 ? unlikely but possible */
2904 /* Switch flicker control back on if it got turned off */
2905 restart_flicker(cam);
2907 /* If AEC is enabled, monitor the exposure and
2908 adjust the sensor frame rate if needed */
2909 if(cam->params.exposure.expMode == 2)
2910 monitor_exposure(cam);
2912 /* camera idle now so dispatch queued commands */
2913 dispatch_commands(cam);
2915 /* Update our knowledge of the camera state */
2916 do_command(cam, CPIA_COMMAND_GetColourBalance, 0, 0, 0, 0);
2917 do_command(cam, CPIA_COMMAND_GetExposure, 0, 0, 0, 0);
2918 do_command(cam, CPIA_COMMAND_ReadMCPorts, 0, 0, 0, 0);
2920 /* decompress and convert image to by copying it from
2921 * raw_image to decompressed_frame
2926 cam->image_size = parse_picture(cam, image_size);
2927 if (cam->image_size <= 0) {
2928 DBG("parse_picture failed %d\n", cam->image_size);
2929 if(cam->params.compression.mode !=
2930 CPIA_COMPRESSION_NONE) {
2931 /* Compression may not work right if we
2932 had a bad frame, get the next one
2934 cam->first_frame = 1;
2935 do_command(cam, CPIA_COMMAND_SetGrabMode,
2936 CPIA_GRAB_SINGLE, 0, 0, 0);
2937 /* FIXME: Trial & error - need up to 70ms for
2938 the grab mode change to complete ? */
2939 current->state = TASK_INTERRUPTIBLE;
2940 schedule_timeout(70*HZ / 1000);
2941 if (signal_pending(current))
2949 /* FIXME: this only works for double buffering */
2950 if (cam->frame[cam->curframe].state == FRAME_READY) {
2951 memcpy(cam->frame[cam->curframe].data,
2952 cam->decompressed_frame.data,
2953 cam->decompressed_frame.count);
2954 cam->frame[cam->curframe].state = FRAME_DONE;
2956 cam->decompressed_frame.state = FRAME_DONE;
2958 if (cam->first_frame) {
2959 cam->first_frame = 0;
2960 do_command(cam, CPIA_COMMAND_SetCompression,
2961 cam->params.compression.mode,
2962 cam->params.compression.decimation, 0, 0);
2964 /* Switch from single-grab to continuous grab */
2965 do_command(cam, CPIA_COMMAND_SetGrabMode,
2966 CPIA_GRAB_CONTINUOUS, 0, 0, 0);
2973 static int capture_frame(struct cam_data *cam, struct video_mmap *vm)
2975 if (!cam->frame_buf) {
2976 /* we do lazy allocation */
2978 if ((err = allocate_frame_buf(cam)))
2982 cam->curframe = vm->frame;
2983 cam->frame[cam->curframe].state = FRAME_READY;
2984 return fetch_frame(cam);
2987 static int goto_high_power(struct cam_data *cam)
2989 if (do_command(cam, CPIA_COMMAND_GotoHiPower, 0, 0, 0, 0))
2991 current->state = TASK_INTERRUPTIBLE;
2992 schedule_timeout(40*HZ/1000); /* windows driver does it too */
2993 if(signal_pending(current))
2995 if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0))
2997 if (cam->params.status.systemState == HI_POWER_STATE) {
2998 DBG("camera now in HIGH power state\n");
3005 static int goto_low_power(struct cam_data *cam)
3007 if (do_command(cam, CPIA_COMMAND_GotoLoPower, 0, 0, 0, 0))
3009 if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0))
3011 if (cam->params.status.systemState == LO_POWER_STATE) {
3012 DBG("camera now in LOW power state\n");
3019 static void save_camera_state(struct cam_data *cam)
3021 if(!(cam->cmd_queue & COMMAND_SETCOLOURBALANCE))
3022 do_command(cam, CPIA_COMMAND_GetColourBalance, 0, 0, 0, 0);
3023 if(!(cam->cmd_queue & COMMAND_SETEXPOSURE))
3024 do_command(cam, CPIA_COMMAND_GetExposure, 0, 0, 0, 0);
3026 DBG("%d/%d/%d/%d/%d/%d/%d/%d\n",
3027 cam->params.exposure.gain,
3028 cam->params.exposure.fineExp,
3029 cam->params.exposure.coarseExpLo,
3030 cam->params.exposure.coarseExpHi,
3031 cam->params.exposure.redComp,
3032 cam->params.exposure.green1Comp,
3033 cam->params.exposure.green2Comp,
3034 cam->params.exposure.blueComp);
3036 cam->params.colourBalance.redGain,
3037 cam->params.colourBalance.greenGain,
3038 cam->params.colourBalance.blueGain);
3041 static int set_camera_state(struct cam_data *cam)
3043 cam->cmd_queue = COMMAND_SETCOMPRESSION |
3044 COMMAND_SETCOMPRESSIONTARGET |
3045 COMMAND_SETCOLOURPARAMS |
3047 COMMAND_SETYUVTHRESH |
3048 COMMAND_SETECPTIMING |
3049 COMMAND_SETCOMPRESSIONPARAMS |
3050 COMMAND_SETEXPOSURE |
3051 COMMAND_SETCOLOURBALANCE |
3052 COMMAND_SETSENSORFPS |
3054 COMMAND_SETFLICKERCTRL |
3055 COMMAND_SETVLOFFSET;
3057 do_command(cam, CPIA_COMMAND_SetGrabMode, CPIA_GRAB_SINGLE,0,0,0);
3058 dispatch_commands(cam);
3060 /* Wait 6 frames for the sensor to get all settings and
3061 AEC/ACB to settle */
3062 current->state = TASK_INTERRUPTIBLE;
3063 schedule_timeout((6*(cam->params.sensorFps.baserate ? 33 : 40) *
3064 (1 << cam->params.sensorFps.divisor) + 10) *
3067 if(signal_pending(current))
3070 save_camera_state(cam);
3075 static void get_version_information(struct cam_data *cam)
3077 /* GetCPIAVersion */
3078 do_command(cam, CPIA_COMMAND_GetCPIAVersion, 0, 0, 0, 0);
3081 do_command(cam, CPIA_COMMAND_GetPnPID, 0, 0, 0, 0);
3084 /* initialize camera */
3085 static int reset_camera(struct cam_data *cam)
3088 /* Start the camera in low power mode */
3089 if (goto_low_power(cam)) {
3090 if (cam->params.status.systemState != WARM_BOOT_STATE)
3093 /* FIXME: this is just dirty trial and error */
3094 err = goto_high_power(cam);
3097 do_command(cam, CPIA_COMMAND_DiscardFrame, 0, 0, 0, 0);
3098 if (goto_low_power(cam))
3102 /* procedure described in developer's guide p3-28 */
3104 /* Check the firmware version. */
3105 cam->params.version.firmwareVersion = 0;
3106 get_version_information(cam);
3107 if (cam->params.version.firmwareVersion != 1)
3110 /* A bug in firmware 1-02 limits gainMode to 2 */
3111 if(cam->params.version.firmwareRevision <= 2 &&
3112 cam->params.exposure.gainMode > 2) {
3113 cam->params.exposure.gainMode = 2;
3116 /* set QX3 detected flag */
3117 cam->params.qx3.qx3_detected = (cam->params.pnpID.vendor == 0x0813 &&
3118 cam->params.pnpID.product == 0x0001);
3120 /* The fatal error checking should be done after
3121 * the camera powers up (developer's guide p 3-38) */
3123 /* Set streamState before transition to high power to avoid bug
3124 * in firmware 1-02 */
3125 do_command(cam, CPIA_COMMAND_ModifyCameraStatus, STREAMSTATE, 0,
3126 STREAM_NOT_READY, 0);
3129 err = goto_high_power(cam);
3133 /* Check the camera status */
3134 if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0))
3137 if (cam->params.status.fatalError) {
3138 DBG("fatal_error: %#04x\n",
3139 cam->params.status.fatalError);
3140 DBG("vp_status: %#04x\n",
3141 cam->params.status.vpStatus);
3142 if (cam->params.status.fatalError & ~(COM_FLAG|CPIA_FLAG)) {
3143 /* Fatal error in camera */
3145 } else if (cam->params.status.fatalError & (COM_FLAG|CPIA_FLAG)) {
3146 /* Firmware 1-02 may do this for parallel port cameras,
3147 * just clear the flags (developer's guide p 3-38) */
3148 do_command(cam, CPIA_COMMAND_ModifyCameraStatus,
3149 FATALERROR, ~(COM_FLAG|CPIA_FLAG), 0, 0);
3153 /* Check the camera status again */
3154 if (cam->params.status.fatalError) {
3155 if (cam->params.status.fatalError)
3159 /* VPVersion can't be retrieved before the camera is in HiPower,
3160 * so get it here instead of in get_version_information. */
3161 do_command(cam, CPIA_COMMAND_GetVPVersion, 0, 0, 0, 0);
3163 /* set camera to a known state */
3164 return set_camera_state(cam);
3167 static void put_cam(struct cpia_camera_ops* ops)
3170 module_put(ops->owner);
3173 /* ------------------------- V4L interface --------------------- */
3174 static int cpia_open(struct inode *inode, struct file *file)
3176 struct video_device *dev = video_devdata(file);
3177 struct cam_data *cam = dev->priv;
3181 DBG("Internal error, cam_data not found!\n");
3185 if (cam->open_count > 0) {
3186 DBG("Camera already open\n");
3190 if (!try_module_get(cam->ops->owner))
3193 down(&cam->busy_lock);
3195 if (!cam->raw_image) {
3196 cam->raw_image = rvmalloc(CPIA_MAX_IMAGE_SIZE);
3197 if (!cam->raw_image)
3201 if (!cam->decompressed_frame.data) {
3202 cam->decompressed_frame.data = rvmalloc(CPIA_MAX_FRAME_SIZE);
3203 if (!cam->decompressed_frame.data)
3209 if (cam->ops->open(cam->lowlevel_data))
3212 /* reset the camera */
3213 if ((err = reset_camera(cam)) != 0) {
3214 cam->ops->close(cam->lowlevel_data);
3219 if(signal_pending(current))
3222 /* Set ownership of /proc/cpia/videoX to current user */
3224 cam->proc_entry->uid = current->uid;
3226 /* set mark for loading first frame uncompressed */
3227 cam->first_frame = 1;
3229 /* init it to something */
3230 cam->mmap_kludge = 0;
3233 file->private_data = dev;
3234 up(&cam->busy_lock);
3238 if (cam->decompressed_frame.data) {
3239 rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE);
3240 cam->decompressed_frame.data = NULL;
3242 if (cam->raw_image) {
3243 rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
3244 cam->raw_image = NULL;
3246 up(&cam->busy_lock);
3251 static int cpia_close(struct inode *inode, struct file *file)
3253 struct video_device *dev = file->private_data;
3254 struct cam_data *cam = dev->priv;
3257 /* Return ownership of /proc/cpia/videoX to root */
3259 cam->proc_entry->uid = 0;
3261 /* save camera state for later open (developers guide ch 3.5.3) */
3262 save_camera_state(cam);
3265 goto_low_power(cam);
3267 /* Update the camera status */
3268 do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0);
3270 /* cleanup internal state stuff */
3271 free_frames(cam->frame);
3274 cam->ops->close(cam->lowlevel_data);
3279 if (--cam->open_count == 0) {
3280 /* clean up capture-buffers */
3281 if (cam->raw_image) {
3282 rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
3283 cam->raw_image = NULL;
3286 if (cam->decompressed_frame.data) {
3287 rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE);
3288 cam->decompressed_frame.data = NULL;
3292 free_frame_buf(cam);
3297 file->private_data = NULL;
3302 static ssize_t cpia_read(struct file *file, char __user *buf,
3303 size_t count, loff_t *ppos)
3305 struct video_device *dev = file->private_data;
3306 struct cam_data *cam = dev->priv;
3309 /* make this _really_ smp and multithread-safe */
3310 if (down_interruptible(&cam->busy_lock))
3315 up(&cam->busy_lock);
3321 up(&cam->busy_lock);
3327 up(&cam->busy_lock);
3332 cam->decompressed_frame.state = FRAME_READY;
3334 if((err = fetch_frame(cam)) != 0) {
3335 DBG("ERROR from fetch_frame: %d\n", err);
3336 up(&cam->busy_lock);
3339 cam->decompressed_frame.state = FRAME_UNUSED;
3341 /* copy data to user space */
3342 if (cam->decompressed_frame.count > count) {
3343 DBG("count wrong: %d, %lu\n", cam->decompressed_frame.count,
3344 (unsigned long) count);
3345 up(&cam->busy_lock);
3348 if (copy_to_user(buf, cam->decompressed_frame.data,
3349 cam->decompressed_frame.count)) {
3350 DBG("copy_to_user failed\n");
3351 up(&cam->busy_lock);
3355 up(&cam->busy_lock);
3356 return cam->decompressed_frame.count;
3359 static int cpia_do_ioctl(struct inode *inode, struct file *file,
3360 unsigned int ioctlnr, void *arg)
3362 struct video_device *dev = file->private_data;
3363 struct cam_data *cam = dev->priv;
3366 if (!cam || !cam->ops)
3369 /* make this _really_ smp-safe */
3370 if (down_interruptible(&cam->busy_lock))
3373 //DBG("cpia_ioctl: %u\n", ioctlnr);
3376 /* query capabilites */
3379 struct video_capability *b = arg;
3381 DBG("VIDIOCGCAP\n");
3382 strcpy(b->name, "CPiA Camera");
3383 b->type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE;
3386 b->maxwidth = 352; /* VIDEOSIZE_CIF */
3388 b->minwidth = 48; /* VIDEOSIZE_48_48 */
3393 /* get/set video source - we are a camera and nothing else */
3396 struct video_channel *v = arg;
3398 DBG("VIDIOCGCHAN\n");
3399 if (v->channel != 0) {
3405 strcpy(v->name, "Camera");
3408 v->type = VIDEO_TYPE_CAMERA;
3415 struct video_channel *v = arg;
3417 DBG("VIDIOCSCHAN\n");
3418 if (v->channel != 0)
3423 /* image properties */
3426 struct video_picture *pic = arg;
3427 DBG("VIDIOCGPICT\n");
3434 struct video_picture *vp = arg;
3436 DBG("VIDIOCSPICT\n");
3438 /* check validity */
3439 DBG("palette: %d\n", vp->palette);
3440 DBG("depth: %d\n", vp->depth);
3441 if (!valid_mode(vp->palette, vp->depth)) {
3446 down(&cam->param_lock);
3447 /* brightness, colour, contrast need no check 0-65535 */
3449 /* update cam->params.colourParams */
3450 cam->params.colourParams.brightness = vp->brightness*100/65535;
3451 cam->params.colourParams.contrast = vp->contrast*100/65535;
3452 cam->params.colourParams.saturation = vp->colour*100/65535;
3453 /* contrast is in steps of 8, so round */
3454 cam->params.colourParams.contrast =
3455 ((cam->params.colourParams.contrast + 3) / 8) * 8;
3456 if (cam->params.version.firmwareVersion == 1 &&
3457 cam->params.version.firmwareRevision == 2 &&
3458 cam->params.colourParams.contrast > 80) {
3459 /* 1-02 firmware limits contrast to 80 */
3460 cam->params.colourParams.contrast = 80;
3463 /* Adjust flicker control if necessary */
3464 if(cam->params.flickerControl.allowableOverExposure < 0)
3465 cam->params.flickerControl.allowableOverExposure =
3466 -find_over_exposure(cam->params.colourParams.brightness);
3467 if(cam->params.flickerControl.flickerMode != 0)
3468 cam->cmd_queue |= COMMAND_SETFLICKERCTRL;
3471 /* queue command to update camera */
3472 cam->cmd_queue |= COMMAND_SETCOLOURPARAMS;
3473 up(&cam->param_lock);
3474 DBG("VIDIOCSPICT: %d / %d // %d / %d / %d / %d\n",
3475 vp->depth, vp->palette, vp->brightness, vp->hue, vp->colour,
3480 /* get/set capture window */
3483 struct video_window *vw = arg;
3484 DBG("VIDIOCGWIN\n");
3492 /* copy_from_user, check validity, copy to internal structure */
3493 struct video_window *vw = arg;
3494 DBG("VIDIOCSWIN\n");
3496 if (vw->clipcount != 0) { /* clipping not supported */
3500 if (vw->clips != NULL) { /* clipping not supported */
3505 /* we set the video window to something smaller or equal to what
3506 * is requested by the user???
3508 down(&cam->param_lock);
3509 if (vw->width != cam->vw.width || vw->height != cam->vw.height) {
3510 int video_size = match_videosize(vw->width, vw->height);
3512 if (video_size < 0) {
3514 up(&cam->param_lock);
3517 cam->video_size = video_size;
3519 /* video size is changing, reset the subcapture area */
3520 memset(&cam->vc, 0, sizeof(cam->vc));
3523 DBG("%d / %d\n", cam->vw.width, cam->vw.height);
3524 cam->cmd_queue |= COMMAND_SETFORMAT;
3527 up(&cam->param_lock);
3529 /* setformat ignored by camera during streaming,
3530 * so stop/dispatch/start */
3531 if (cam->cmd_queue & COMMAND_SETFORMAT) {
3533 dispatch_commands(cam);
3535 DBG("%d/%d:%d\n", cam->video_size,
3536 cam->vw.width, cam->vw.height);
3540 /* mmap interface */
3543 struct video_mbuf *vm = arg;
3546 DBG("VIDIOCGMBUF\n");
3547 memset(vm, 0, sizeof(*vm));
3548 vm->size = CPIA_MAX_FRAME_SIZE*FRAME_NUM;
3549 vm->frames = FRAME_NUM;
3550 for (i = 0; i < FRAME_NUM; i++)
3551 vm->offsets[i] = CPIA_MAX_FRAME_SIZE * i;
3555 case VIDIOCMCAPTURE:
3557 struct video_mmap *vm = arg;
3560 DBG("VIDIOCMCAPTURE: %d / %d / %dx%d\n", vm->format, vm->frame,
3561 vm->width, vm->height);
3562 if (vm->frame<0||vm->frame>=FRAME_NUM) {
3567 /* set video format */
3568 cam->vp.palette = vm->format;
3569 switch(vm->format) {
3570 case VIDEO_PALETTE_GREY:
3573 case VIDEO_PALETTE_RGB555:
3574 case VIDEO_PALETTE_RGB565:
3575 case VIDEO_PALETTE_YUV422:
3576 case VIDEO_PALETTE_YUYV:
3577 case VIDEO_PALETTE_UYVY:
3580 case VIDEO_PALETTE_RGB24:
3583 case VIDEO_PALETTE_RGB32:
3593 /* set video size */
3594 video_size = match_videosize(vm->width, vm->height);
3595 if (video_size < 0) {
3599 if (video_size != cam->video_size) {
3600 cam->video_size = video_size;
3602 /* video size is changing, reset the subcapture area */
3603 memset(&cam->vc, 0, sizeof(cam->vc));
3606 cam->cmd_queue |= COMMAND_SETFORMAT;
3607 dispatch_commands(cam);
3609 /* according to v4l-spec we must start streaming here */
3610 cam->mmap_kludge = 1;
3611 retval = capture_frame(cam, vm);
3620 //DBG("VIDIOCSYNC: %d\n", *frame);
3622 if (*frame<0 || *frame >= FRAME_NUM) {
3627 switch (cam->frame[*frame].state) {
3630 case FRAME_GRABBING:
3631 DBG("sync to unused frame %d\n", *frame);
3636 cam->frame[*frame].state = FRAME_UNUSED;
3637 //DBG("VIDIOCSYNC: %d synced\n", *frame);
3640 if (retval == -EINTR) {
3641 /* FIXME - xawtv does not handle this nice */
3647 case VIDIOCGCAPTURE:
3649 struct video_capture *vc = arg;
3651 DBG("VIDIOCGCAPTURE\n");
3658 case VIDIOCSCAPTURE:
3660 struct video_capture *vc = arg;
3662 DBG("VIDIOCSCAPTURE\n");
3664 if (vc->decimation != 0) { /* How should this be used? */
3668 if (vc->flags != 0) { /* Even/odd grab not supported */
3673 /* Clip to the resolution we can set for the ROI
3674 (every 8 columns and 4 rows) */
3675 vc->x = vc->x & ~(__u32)7;
3676 vc->y = vc->y & ~(__u32)3;
3677 vc->width = vc->width & ~(__u32)7;
3678 vc->height = vc->height & ~(__u32)3;
3680 if(vc->width == 0 || vc->height == 0 ||
3681 vc->x + vc->width > cam->vw.width ||
3682 vc->y + vc->height > cam->vw.height) {
3687 DBG("%d,%d/%dx%d\n", vc->x,vc->y,vc->width, vc->height);
3689 down(&cam->param_lock);
3693 cam->vc.width = vc->width;
3694 cam->vc.height = vc->height;
3697 cam->cmd_queue |= COMMAND_SETFORMAT;
3699 up(&cam->param_lock);
3701 /* setformat ignored by camera during streaming,
3702 * so stop/dispatch/start */
3703 dispatch_commands(cam);
3709 struct video_unit *vu = arg;
3711 DBG("VIDIOCGUNIT\n");
3713 vu->video = cam->vdev.minor;
3714 vu->vbi = VIDEO_NO_UNIT;
3715 vu->radio = VIDEO_NO_UNIT;
3716 vu->audio = VIDEO_NO_UNIT;
3717 vu->teletext = VIDEO_NO_UNIT;
3723 /* pointless to implement overlay with this camera */
3728 /* tuner interface - we have none */
3733 /* audio interface - we have none */
3739 retval = -ENOIOCTLCMD;
3743 up(&cam->busy_lock);
3747 static int cpia_ioctl(struct inode *inode, struct file *file,
3748 unsigned int cmd, unsigned long arg)
3750 return video_usercopy(inode, file, cmd, arg, cpia_do_ioctl);
3755 static int cpia_mmap(struct file *file, struct vm_area_struct *vma)
3757 struct video_device *dev = file->private_data;
3758 unsigned long start = vma->vm_start;
3759 unsigned long size = vma->vm_end - vma->vm_start;
3760 unsigned long page, pos;
3761 struct cam_data *cam = dev->priv;
3764 if (!cam || !cam->ops)
3767 DBG("cpia_mmap: %ld\n", size);
3769 if (size > FRAME_NUM*CPIA_MAX_FRAME_SIZE)
3772 if (!cam || !cam->ops)
3775 /* make this _really_ smp-safe */
3776 if (down_interruptible(&cam->busy_lock))
3779 if (!cam->frame_buf) { /* we do lazy allocation */
3780 if ((retval = allocate_frame_buf(cam))) {
3781 up(&cam->busy_lock);
3786 pos = (unsigned long)(cam->frame_buf);
3788 page = kvirt_to_pa(pos);
3789 if (remap_page_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
3790 up(&cam->busy_lock);
3795 if (size > PAGE_SIZE)
3801 DBG("cpia_mmap: %ld\n", size);
3802 up(&cam->busy_lock);
3807 static struct file_operations cpia_fops = {
3808 .owner = THIS_MODULE,
3810 .release = cpia_close,
3813 .ioctl = cpia_ioctl,
3814 .llseek = no_llseek,
3817 static struct video_device cpia_template = {
3818 .owner = THIS_MODULE,
3819 .name = "CPiA Camera",
3820 .type = VID_TYPE_CAPTURE,
3821 .hardware = VID_HARDWARE_CPIA,
3825 /* initialise cam_data structure */
3826 static void reset_camera_struct(struct cam_data *cam)
3828 /* The following parameter values are the defaults from
3829 * "Software Developer's Guide for CPiA Cameras". Any changes
3830 * to the defaults are noted in comments. */
3831 cam->params.colourParams.brightness = 50;
3832 cam->params.colourParams.contrast = 48;
3833 cam->params.colourParams.saturation = 50;
3834 cam->params.exposure.gainMode = 4;
3835 cam->params.exposure.expMode = 2; /* AEC */
3836 cam->params.exposure.compMode = 1;
3837 cam->params.exposure.centreWeight = 1;
3838 cam->params.exposure.gain = 0;
3839 cam->params.exposure.fineExp = 0;
3840 cam->params.exposure.coarseExpLo = 185;
3841 cam->params.exposure.coarseExpHi = 0;
3842 cam->params.exposure.redComp = COMP_RED;
3843 cam->params.exposure.green1Comp = COMP_GREEN1;
3844 cam->params.exposure.green2Comp = COMP_GREEN2;
3845 cam->params.exposure.blueComp = COMP_BLUE;
3846 cam->params.colourBalance.balanceMode = 2; /* ACB */
3847 cam->params.colourBalance.redGain = 32;
3848 cam->params.colourBalance.greenGain = 6;
3849 cam->params.colourBalance.blueGain = 92;
3850 cam->params.apcor.gain1 = 0x18;
3851 cam->params.apcor.gain2 = 0x16;
3852 cam->params.apcor.gain4 = 0x24;
3853 cam->params.apcor.gain8 = 0x34;
3854 cam->params.flickerControl.flickerMode = 0;
3855 cam->params.flickerControl.disabled = 1;
3857 cam->params.flickerControl.coarseJump =
3858 flicker_jumps[cam->mainsFreq]
3859 [cam->params.sensorFps.baserate]
3860 [cam->params.sensorFps.divisor];
3861 cam->params.flickerControl.allowableOverExposure =
3862 -find_over_exposure(cam->params.colourParams.brightness);
3863 cam->params.vlOffset.gain1 = 20;
3864 cam->params.vlOffset.gain2 = 24;
3865 cam->params.vlOffset.gain4 = 26;
3866 cam->params.vlOffset.gain8 = 26;
3867 cam->params.compressionParams.hysteresis = 3;
3868 cam->params.compressionParams.threshMax = 11;
3869 cam->params.compressionParams.smallStep = 1;
3870 cam->params.compressionParams.largeStep = 3;
3871 cam->params.compressionParams.decimationHysteresis = 2;
3872 cam->params.compressionParams.frDiffStepThresh = 5;
3873 cam->params.compressionParams.qDiffStepThresh = 3;
3874 cam->params.compressionParams.decimationThreshMod = 2;
3875 /* End of default values from Software Developer's Guide */
3877 cam->transfer_rate = 0;
3878 cam->exposure_status = EXPOSURE_NORMAL;
3880 /* Set Sensor FPS to 15fps. This seems better than 30fps
3881 * for indoor lighting. */
3882 cam->params.sensorFps.divisor = 1;
3883 cam->params.sensorFps.baserate = 1;
3885 cam->params.yuvThreshold.yThreshold = 6; /* From windows driver */
3886 cam->params.yuvThreshold.uvThreshold = 6; /* From windows driver */
3888 cam->params.format.subSample = SUBSAMPLE_422;
3889 cam->params.format.yuvOrder = YUVORDER_YUYV;
3891 cam->params.compression.mode = CPIA_COMPRESSION_AUTO;
3892 cam->params.compressionTarget.frTargeting =
3893 CPIA_COMPRESSION_TARGET_QUALITY;
3894 cam->params.compressionTarget.targetFR = 15; /* From windows driver */
3895 cam->params.compressionTarget.targetQ = 5; /* From windows driver */
3897 cam->params.qx3.qx3_detected = 0;
3898 cam->params.qx3.toplight = 0;
3899 cam->params.qx3.bottomlight = 0;
3900 cam->params.qx3.button = 0;
3901 cam->params.qx3.cradled = 0;
3903 cam->video_size = VIDEOSIZE_CIF;
3905 cam->vp.colour = 32768; /* 50% */
3906 cam->vp.hue = 32768; /* 50% */
3907 cam->vp.brightness = 32768; /* 50% */
3908 cam->vp.contrast = 32768; /* 50% */
3909 cam->vp.whiteness = 0; /* not used -> grayscale only */
3910 cam->vp.depth = 24; /* to be set by user */
3911 cam->vp.palette = VIDEO_PALETTE_RGB24; /* to be set by user */
3921 cam->vw.chromakey = 0;
3923 cam->vw.clipcount = 0;
3924 cam->vw.clips = NULL;
3926 cam->cmd_queue = COMMAND_NONE;
3927 cam->first_frame = 1;
3932 /* initialize cam_data structure */
3933 static void init_camera_struct(struct cam_data *cam,
3934 struct cpia_camera_ops *ops )
3938 /* Default everything to 0 */
3939 memset(cam, 0, sizeof(struct cam_data));
3942 init_MUTEX(&cam->param_lock);
3943 init_MUTEX(&cam->busy_lock);
3945 reset_camera_struct(cam);
3947 cam->proc_entry = NULL;
3949 memcpy(&cam->vdev, &cpia_template, sizeof(cpia_template));
3950 cam->vdev.priv = cam;
3953 for (i = 0; i < FRAME_NUM; i++) {
3954 cam->frame[i].width = 0;
3955 cam->frame[i].height = 0;
3956 cam->frame[i].state = FRAME_UNUSED;
3957 cam->frame[i].data = NULL;
3959 cam->decompressed_frame.width = 0;
3960 cam->decompressed_frame.height = 0;
3961 cam->decompressed_frame.state = FRAME_UNUSED;
3962 cam->decompressed_frame.data = NULL;
3965 struct cam_data *cpia_register_camera(struct cpia_camera_ops *ops, void *lowlevel)
3967 struct cam_data *camera;
3969 if ((camera = kmalloc(sizeof(struct cam_data), GFP_KERNEL)) == NULL)
3973 init_camera_struct( camera, ops );
3974 camera->lowlevel_data = lowlevel;
3976 /* register v4l device */
3977 if (video_register_device(&camera->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
3979 printk(KERN_DEBUG "video_register_device failed\n");
3983 /* get version information from camera: open/reset/close */
3986 if (camera->ops->open(camera->lowlevel_data))
3989 /* reset the camera */
3990 if (reset_camera(camera) != 0) {
3991 camera->ops->close(camera->lowlevel_data);
3996 camera->ops->close(camera->lowlevel_data);
3998 #ifdef CONFIG_PROC_FS
3999 create_proc_cpia_cam(camera);
4002 printk(KERN_INFO " CPiA Version: %d.%02d (%d.%d)\n",
4003 camera->params.version.firmwareVersion,
4004 camera->params.version.firmwareRevision,
4005 camera->params.version.vcVersion,
4006 camera->params.version.vcRevision);
4007 printk(KERN_INFO " CPiA PnP-ID: %04x:%04x:%04x\n",
4008 camera->params.pnpID.vendor,
4009 camera->params.pnpID.product,
4010 camera->params.pnpID.deviceRevision);
4011 printk(KERN_INFO " VP-Version: %d.%d %04x\n",
4012 camera->params.vpVersion.vpVersion,
4013 camera->params.vpVersion.vpRevision,
4014 camera->params.vpVersion.cameraHeadID);
4019 void cpia_unregister_camera(struct cam_data *cam)
4021 DBG("unregistering video\n");
4022 video_unregister_device(&cam->vdev);
4023 if (cam->open_count) {
4025 DBG("camera open -- setting ops to NULL\n");
4029 #ifdef CONFIG_PROC_FS
4030 DBG("destroying /proc/cpia/video%d\n", cam->vdev.minor);
4031 destroy_proc_cpia_cam(cam);
4033 if (!cam->open_count) {
4034 DBG("freeing camera\n");
4039 static int __init cpia_init(void)
4041 printk(KERN_INFO "%s v%d.%d.%d\n", ABOUT,
4042 CPIA_MAJ_VER, CPIA_MIN_VER, CPIA_PATCH_VER);
4043 #ifdef CONFIG_PROC_FS
4048 #ifdef CONFIG_VIDEO_CPIA_PP_MODULE
4049 request_module("cpia_pp");
4052 #ifdef CONFIG_VIDEO_CPIA_USB_MODULE
4053 request_module("cpia_usb");
4055 #endif /* CONFIG_KMOD */
4057 #ifdef CONFIG_VIDEO_CPIA_PP
4060 #ifdef CONFIG_VIDEO_CPIA_USB
4066 static void __exit cpia_exit(void)
4068 #ifdef CONFIG_PROC_FS
4069 proc_cpia_destroy();
4073 module_init(cpia_init);
4074 module_exit(cpia_exit);
4076 /* Exported symbols for modules. */
4078 EXPORT_SYMBOL(cpia_register_camera);
4079 EXPORT_SYMBOL(cpia_unregister_camera);