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>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 /* #define _CPIA_DEBUG_ define for verbose debug output */
26 #include <linux/config.h>
28 #include <linux/module.h>
29 #include <linux/version.h>
30 #include <linux/init.h>
32 #include <linux/vmalloc.h>
33 #include <linux/delay.h>
34 #include <linux/slab.h>
35 #include <linux/proc_fs.h>
36 #include <linux/ctype.h>
37 #include <linux/pagemap.h>
39 #include <asm/semaphore.h>
40 #include <linux/wrapper.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_SetColourParams (OUTPUT | CPIA_MODULE_VP_CTRL | 3)
105 #define CPIA_COMMAND_SetExposure (OUTPUT | CPIA_MODULE_VP_CTRL | 4)
106 #define CPIA_COMMAND_SetColourBalance (OUTPUT | CPIA_MODULE_VP_CTRL | 6)
107 #define CPIA_COMMAND_SetSensorFPS (OUTPUT | CPIA_MODULE_VP_CTRL | 7)
108 #define CPIA_COMMAND_SetVPDefaults (OUTPUT | CPIA_MODULE_VP_CTRL | 8)
109 #define CPIA_COMMAND_SetApcor (OUTPUT | CPIA_MODULE_VP_CTRL | 9)
110 #define CPIA_COMMAND_SetFlickerCtrl (OUTPUT | CPIA_MODULE_VP_CTRL | 10)
111 #define CPIA_COMMAND_SetVLOffset (OUTPUT | CPIA_MODULE_VP_CTRL | 11)
112 #define CPIA_COMMAND_GetColourParams (INPUT | CPIA_MODULE_VP_CTRL | 16)
113 #define CPIA_COMMAND_GetColourBalance (INPUT | CPIA_MODULE_VP_CTRL | 17)
114 #define CPIA_COMMAND_GetExposure (INPUT | CPIA_MODULE_VP_CTRL | 18)
115 #define CPIA_COMMAND_SetSensorMatrix (OUTPUT | CPIA_MODULE_VP_CTRL | 19)
116 #define CPIA_COMMAND_ColourBars (OUTPUT | CPIA_MODULE_VP_CTRL | 25)
117 #define CPIA_COMMAND_ReadVPRegs (INPUT | CPIA_MODULE_VP_CTRL | 30)
118 #define CPIA_COMMAND_WriteVPReg (OUTPUT | CPIA_MODULE_VP_CTRL | 31)
120 #define CPIA_COMMAND_GrabFrame (OUTPUT | CPIA_MODULE_CAPTURE | 1)
121 #define CPIA_COMMAND_UploadFrame (OUTPUT | CPIA_MODULE_CAPTURE | 2)
122 #define CPIA_COMMAND_SetGrabMode (OUTPUT | CPIA_MODULE_CAPTURE | 3)
123 #define CPIA_COMMAND_InitStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 4)
124 #define CPIA_COMMAND_FiniStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 5)
125 #define CPIA_COMMAND_StartStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 6)
126 #define CPIA_COMMAND_EndStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 7)
127 #define CPIA_COMMAND_SetFormat (OUTPUT | CPIA_MODULE_CAPTURE | 8)
128 #define CPIA_COMMAND_SetROI (OUTPUT | CPIA_MODULE_CAPTURE | 9)
129 #define CPIA_COMMAND_SetCompression (OUTPUT | CPIA_MODULE_CAPTURE | 10)
130 #define CPIA_COMMAND_SetCompressionTarget (OUTPUT | CPIA_MODULE_CAPTURE | 11)
131 #define CPIA_COMMAND_SetYUVThresh (OUTPUT | CPIA_MODULE_CAPTURE | 12)
132 #define CPIA_COMMAND_SetCompressionParams (OUTPUT | CPIA_MODULE_CAPTURE | 13)
133 #define CPIA_COMMAND_DiscardFrame (OUTPUT | CPIA_MODULE_CAPTURE | 14)
135 #define CPIA_COMMAND_OutputRS232 (OUTPUT | CPIA_MODULE_DEBUG | 1)
136 #define CPIA_COMMAND_AbortProcess (OUTPUT | CPIA_MODULE_DEBUG | 4)
137 #define CPIA_COMMAND_SetDramPage (OUTPUT | CPIA_MODULE_DEBUG | 5)
138 #define CPIA_COMMAND_StartDramUpload (OUTPUT | CPIA_MODULE_DEBUG | 6)
139 #define CPIA_COMMAND_StartDummyDtream (OUTPUT | CPIA_MODULE_DEBUG | 8)
140 #define CPIA_COMMAND_AbortStream (OUTPUT | CPIA_MODULE_DEBUG | 9)
141 #define CPIA_COMMAND_DownloadDRAM (OUTPUT | CPIA_MODULE_DEBUG | 10)
144 FRAME_READY, /* Ready to grab into */
145 FRAME_GRABBING, /* In the process of being grabbed into */
146 FRAME_DONE, /* Finished grabbing, but not been synced yet */
147 FRAME_UNUSED, /* Unused (no MCAPTURE) */
150 #define COMMAND_NONE 0x0000
151 #define COMMAND_SETCOMPRESSION 0x0001
152 #define COMMAND_SETCOMPRESSIONTARGET 0x0002
153 #define COMMAND_SETCOLOURPARAMS 0x0004
154 #define COMMAND_SETFORMAT 0x0008
155 #define COMMAND_PAUSE 0x0010
156 #define COMMAND_RESUME 0x0020
157 #define COMMAND_SETYUVTHRESH 0x0040
158 #define COMMAND_SETECPTIMING 0x0080
159 #define COMMAND_SETCOMPRESSIONPARAMS 0x0100
160 #define COMMAND_SETEXPOSURE 0x0200
161 #define COMMAND_SETCOLOURBALANCE 0x0400
162 #define COMMAND_SETSENSORFPS 0x0800
163 #define COMMAND_SETAPCOR 0x1000
164 #define COMMAND_SETFLICKERCTRL 0x2000
165 #define COMMAND_SETVLOFFSET 0x4000
166 #define COMMAND_SETLIGHTS 0x8000
168 /* Developer's Guide Table 5 p 3-34
169 * indexed by [mains][sensorFps.baserate][sensorFps.divisor]*/
170 static u8 flicker_jumps[2][2][4] =
171 { { { 76, 38, 19, 9 }, { 92, 46, 23, 11 } },
172 { { 64, 32, 16, 8 }, { 76, 38, 19, 9} }
175 /* forward declaration of local function */
176 static void reset_camera_struct(struct cam_data *cam);
178 /**********************************************************************
182 **********************************************************************/
184 /* Here we want the physical address of the memory.
185 * This is used when initializing the contents of the area.
187 static inline unsigned long kvirt_to_pa(unsigned long adr)
189 unsigned long kva, ret;
191 kva = (unsigned long) page_address(vmalloc_to_page((void *)adr));
192 kva |= adr & (PAGE_SIZE-1); /* restore the offset */
197 static void *rvmalloc(unsigned long size)
202 size = PAGE_ALIGN(size);
203 mem = vmalloc_32(size);
207 memset(mem, 0, size); /* Clear the ram out, no junk to the user */
208 adr = (unsigned long) mem;
210 mem_map_reserve(vmalloc_to_page((void *)adr));
218 static void rvfree(void *mem, unsigned long size)
225 adr = (unsigned long) mem;
226 while ((long) size > 0) {
227 mem_map_unreserve(vmalloc_to_page((void *)adr));
234 /**********************************************************************
238 **********************************************************************/
239 #ifdef CONFIG_PROC_FS
240 static struct proc_dir_entry *cpia_proc_root=NULL;
242 static int cpia_read_proc(char *page, char **start, off_t off,
243 int count, int *eof, void *data)
247 struct cam_data *cam = data;
250 /* IMPORTANT: This output MUST be kept under PAGE_SIZE
251 * or we need to get more sophisticated. */
253 out += sprintf(out, "read-only\n-----------------------\n");
254 out += sprintf(out, "V4L Driver version: %d.%d.%d\n",
255 CPIA_MAJ_VER, CPIA_MIN_VER, CPIA_PATCH_VER);
256 out += sprintf(out, "CPIA Version: %d.%02d (%d.%d)\n",
257 cam->params.version.firmwareVersion,
258 cam->params.version.firmwareRevision,
259 cam->params.version.vcVersion,
260 cam->params.version.vcRevision);
261 out += sprintf(out, "CPIA PnP-ID: %04x:%04x:%04x\n",
262 cam->params.pnpID.vendor, cam->params.pnpID.product,
263 cam->params.pnpID.deviceRevision);
264 out += sprintf(out, "VP-Version: %d.%d %04x\n",
265 cam->params.vpVersion.vpVersion,
266 cam->params.vpVersion.vpRevision,
267 cam->params.vpVersion.cameraHeadID);
269 out += sprintf(out, "system_state: %#04x\n",
270 cam->params.status.systemState);
271 out += sprintf(out, "grab_state: %#04x\n",
272 cam->params.status.grabState);
273 out += sprintf(out, "stream_state: %#04x\n",
274 cam->params.status.streamState);
275 out += sprintf(out, "fatal_error: %#04x\n",
276 cam->params.status.fatalError);
277 out += sprintf(out, "cmd_error: %#04x\n",
278 cam->params.status.cmdError);
279 out += sprintf(out, "debug_flags: %#04x\n",
280 cam->params.status.debugFlags);
281 out += sprintf(out, "vp_status: %#04x\n",
282 cam->params.status.vpStatus);
283 out += sprintf(out, "error_code: %#04x\n",
284 cam->params.status.errorCode);
285 /* QX3 specific entries */
286 if (cam->params.qx3.qx3_detected) {
287 out += sprintf(out, "button: %4d\n",
288 cam->params.qx3.button);
289 out += sprintf(out, "cradled: %4d\n",
290 cam->params.qx3.cradled);
292 out += sprintf(out, "video_size: %s\n",
293 cam->params.format.videoSize == VIDEOSIZE_CIF ?
295 out += sprintf(out, "sub_sample: %s\n",
296 cam->params.format.subSample == SUBSAMPLE_420 ?
298 out += sprintf(out, "yuv_order: %s\n",
299 cam->params.format.yuvOrder == YUVORDER_YUYV ?
301 out += sprintf(out, "roi: (%3d, %3d) to (%3d, %3d)\n",
302 cam->params.roi.colStart*8,
303 cam->params.roi.rowStart*4,
304 cam->params.roi.colEnd*8,
305 cam->params.roi.rowEnd*4);
306 out += sprintf(out, "actual_fps: %3d\n", cam->fps);
307 out += sprintf(out, "transfer_rate: %4dkB/s\n",
310 out += sprintf(out, "\nread-write\n");
311 out += sprintf(out, "----------------------- current min"
312 " max default comment\n");
313 out += sprintf(out, "brightness: %8d %8d %8d %8d\n",
314 cam->params.colourParams.brightness, 0, 100, 50);
315 if (cam->params.version.firmwareVersion == 1 &&
316 cam->params.version.firmwareRevision == 2)
317 /* 1-02 firmware limits contrast to 80 */
322 out += sprintf(out, "contrast: %8d %8d %8d %8d"
324 cam->params.colourParams.contrast, 0, tmp, 48);
325 out += sprintf(out, "saturation: %8d %8d %8d %8d\n",
326 cam->params.colourParams.saturation, 0, 100, 50);
327 tmp = (25000+5000*cam->params.sensorFps.baserate)/
328 (1<<cam->params.sensorFps.divisor);
329 out += sprintf(out, "sensor_fps: %4d.%03d %8d %8d %8d\n",
330 tmp/1000, tmp%1000, 3, 30, 15);
331 out += sprintf(out, "stream_start_line: %8d %8d %8d %8d\n",
332 2*cam->params.streamStartLine, 0,
333 cam->params.format.videoSize == VIDEOSIZE_CIF ? 288:144,
334 cam->params.format.videoSize == VIDEOSIZE_CIF ? 240:120);
335 out += sprintf(out, "ecp_timing: %8s %8s %8s %8s\n",
336 cam->params.ecpTiming ? "slow" : "normal", "slow",
339 if (cam->params.colourBalance.balanceModeIsAuto) {
340 sprintf(tmpstr, "auto");
342 sprintf(tmpstr, "manual");
344 out += sprintf(out, "color_balance_mode: %8s %8s %8s"
345 " %8s\n", tmpstr, "manual", "auto", "auto");
346 out += sprintf(out, "red_gain: %8d %8d %8d %8d\n",
347 cam->params.colourBalance.redGain, 0, 212, 32);
348 out += sprintf(out, "green_gain: %8d %8d %8d %8d\n",
349 cam->params.colourBalance.greenGain, 0, 212, 6);
350 out += sprintf(out, "blue_gain: %8d %8d %8d %8d\n",
351 cam->params.colourBalance.blueGain, 0, 212, 92);
353 if (cam->params.version.firmwareVersion == 1 &&
354 cam->params.version.firmwareRevision == 2)
355 /* 1-02 firmware limits gain to 2 */
356 sprintf(tmpstr, "%8d %8d %8d", 1, 2, 2);
358 sprintf(tmpstr, "%8d %8d %8d", 1, 8, 2);
360 if (cam->params.exposure.gainMode == 0)
361 out += sprintf(out, "max_gain: unknown %28s"
362 " powers of 2\n", tmpstr);
364 out += sprintf(out, "max_gain: %8d %28s"
366 1<<(cam->params.exposure.gainMode-1), tmpstr);
368 switch(cam->params.exposure.expMode) {
371 sprintf(tmpstr, "manual");
374 sprintf(tmpstr, "auto");
377 sprintf(tmpstr, "unknown");
380 out += sprintf(out, "exposure_mode: %8s %8s %8s"
381 " %8s\n", tmpstr, "manual", "auto", "auto");
382 out += sprintf(out, "centre_weight: %8s %8s %8s %8s\n",
383 (2-cam->params.exposure.centreWeight) ? "on" : "off",
385 out += sprintf(out, "gain: %8d %8d max_gain %8d 1,2,4,8 possible\n",
386 1<<cam->params.exposure.gain, 1, 1);
387 if (cam->params.version.firmwareVersion == 1 &&
388 cam->params.version.firmwareRevision == 2)
389 /* 1-02 firmware limits fineExp to 127 */
394 out += sprintf(out, "fine_exp: %8d %8d %8d %8d\n",
395 cam->params.exposure.fineExp*2, 0, tmp, 0);
396 if (cam->params.version.firmwareVersion == 1 &&
397 cam->params.version.firmwareRevision == 2)
398 /* 1-02 firmware limits coarseExpHi to 0 */
403 out += sprintf(out, "coarse_exp: %8d %8d %8d"
404 " %8d\n", cam->params.exposure.coarseExpLo+
405 256*cam->params.exposure.coarseExpHi, 0, tmp, 185);
406 out += sprintf(out, "red_comp: %8d %8d %8d %8d\n",
407 cam->params.exposure.redComp, 220, 255, 220);
408 out += sprintf(out, "green1_comp: %8d %8d %8d %8d\n",
409 cam->params.exposure.green1Comp, 214, 255, 214);
410 out += sprintf(out, "green2_comp: %8d %8d %8d %8d\n",
411 cam->params.exposure.green2Comp, 214, 255, 214);
412 out += sprintf(out, "blue_comp: %8d %8d %8d %8d\n",
413 cam->params.exposure.blueComp, 230, 255, 230);
415 out += sprintf(out, "apcor_gain1: %#8x %#8x %#8x %#8x\n",
416 cam->params.apcor.gain1, 0, 0xff, 0x1c);
417 out += sprintf(out, "apcor_gain2: %#8x %#8x %#8x %#8x\n",
418 cam->params.apcor.gain2, 0, 0xff, 0x1a);
419 out += sprintf(out, "apcor_gain4: %#8x %#8x %#8x %#8x\n",
420 cam->params.apcor.gain4, 0, 0xff, 0x2d);
421 out += sprintf(out, "apcor_gain8: %#8x %#8x %#8x %#8x\n",
422 cam->params.apcor.gain8, 0, 0xff, 0x2a);
423 out += sprintf(out, "vl_offset_gain1: %8d %8d %8d %8d\n",
424 cam->params.vlOffset.gain1, 0, 255, 24);
425 out += sprintf(out, "vl_offset_gain2: %8d %8d %8d %8d\n",
426 cam->params.vlOffset.gain2, 0, 255, 28);
427 out += sprintf(out, "vl_offset_gain4: %8d %8d %8d %8d\n",
428 cam->params.vlOffset.gain4, 0, 255, 30);
429 out += sprintf(out, "vl_offset_gain8: %8d %8d %8d %8d\n",
430 cam->params.vlOffset.gain8, 0, 255, 30);
431 out += sprintf(out, "flicker_control: %8s %8s %8s %8s\n",
432 cam->params.flickerControl.flickerMode ? "on" : "off",
434 out += sprintf(out, "mains_frequency: %8d %8d %8d %8d"
436 cam->mainsFreq ? 60 : 50, 50, 60, 50);
437 out += sprintf(out, "allowable_overexposure: %8d %8d %8d %8d\n",
438 cam->params.flickerControl.allowableOverExposure, 0,
440 out += sprintf(out, "compression_mode: ");
441 switch(cam->params.compression.mode) {
442 case CPIA_COMPRESSION_NONE:
443 out += sprintf(out, "%8s", "none");
445 case CPIA_COMPRESSION_AUTO:
446 out += sprintf(out, "%8s", "auto");
448 case CPIA_COMPRESSION_MANUAL:
449 out += sprintf(out, "%8s", "manual");
452 out += sprintf(out, "%8s", "unknown");
455 out += sprintf(out, " none,auto,manual auto\n");
456 out += sprintf(out, "decimation_enable: %8s %8s %8s %8s\n",
457 cam->params.compression.decimation ==
458 DECIMATION_ENAB ? "on":"off", "off", "off",
460 out += sprintf(out, "compression_target: %9s %9s %9s %9s\n",
461 cam->params.compressionTarget.frTargeting ==
462 CPIA_COMPRESSION_TARGET_FRAMERATE ?
463 "framerate":"quality",
464 "framerate", "quality", "quality");
465 out += sprintf(out, "target_framerate: %8d %8d %8d %8d\n",
466 cam->params.compressionTarget.targetFR, 0, 30, 7);
467 out += sprintf(out, "target_quality: %8d %8d %8d %8d\n",
468 cam->params.compressionTarget.targetQ, 0, 255, 10);
469 out += sprintf(out, "y_threshold: %8d %8d %8d %8d\n",
470 cam->params.yuvThreshold.yThreshold, 0, 31, 15);
471 out += sprintf(out, "uv_threshold: %8d %8d %8d %8d\n",
472 cam->params.yuvThreshold.uvThreshold, 0, 31, 15);
473 out += sprintf(out, "hysteresis: %8d %8d %8d %8d\n",
474 cam->params.compressionParams.hysteresis, 0, 255, 3);
475 out += sprintf(out, "threshold_max: %8d %8d %8d %8d\n",
476 cam->params.compressionParams.threshMax, 0, 255, 11);
477 out += sprintf(out, "small_step: %8d %8d %8d %8d\n",
478 cam->params.compressionParams.smallStep, 0, 255, 1);
479 out += sprintf(out, "large_step: %8d %8d %8d %8d\n",
480 cam->params.compressionParams.largeStep, 0, 255, 3);
481 out += sprintf(out, "decimation_hysteresis: %8d %8d %8d %8d\n",
482 cam->params.compressionParams.decimationHysteresis,
484 out += sprintf(out, "fr_diff_step_thresh: %8d %8d %8d %8d\n",
485 cam->params.compressionParams.frDiffStepThresh,
487 out += sprintf(out, "q_diff_step_thresh: %8d %8d %8d %8d\n",
488 cam->params.compressionParams.qDiffStepThresh,
490 out += sprintf(out, "decimation_thresh_mod: %8d %8d %8d %8d\n",
491 cam->params.compressionParams.decimationThreshMod,
493 /* QX3 specific entries */
494 if (cam->params.qx3.qx3_detected) {
495 out += sprintf(out, "toplight: %8s %8s %8s %8s\n",
496 cam->params.qx3.toplight ? "on" : "off",
498 out += sprintf(out, "bottomlight: %8s %8s %8s %8s\n",
499 cam->params.qx3.bottomlight ? "on" : "off",
507 if (len <= 0) return 0;
515 static int cpia_write_proc(struct file *file, const char *buf,
516 unsigned long count, void *data)
518 struct cam_data *cam = data;
519 struct cam_params new_params;
521 int retval, find_colon;
523 unsigned long val = 0;
524 u32 command_flags = 0;
528 * This code to copy from buf to page is shamelessly copied
529 * from the comx driver
531 if (count > PAGE_SIZE) {
532 printk(KERN_ERR "count is %lu > %d!!!\n", count, (int)PAGE_SIZE);
536 if (!(page = (char *)__get_free_page(GFP_KERNEL))) return -ENOMEM;
538 if(copy_from_user(page, buf, count))
544 if (page[count-1] == '\n')
545 page[count-1] = '\0';
546 else if (count < PAGE_SIZE)
548 else if (page[count]) {
555 if (down_interruptible(&cam->param_lock))
559 * Skip over leading whitespace
561 while (count && isspace(*buffer)) {
566 memcpy(&new_params, &cam->params, sizeof(struct cam_params));
567 new_mains = cam->mainsFreq;
571 int _len = strlen(x), _ret, _colon_found; \
572 _ret = (_len <= count && strncmp(buffer, x, _len) == 0); \
578 while (count && (*buffer == ' ' || *buffer == '\t' || \
579 (!_colon_found && *buffer == ':'))) { \
580 if (*buffer == ':') \
585 if (!count || !_colon_found) \
592 #define FIRMWARE_VERSION(x,y) (new_params.version.firmwareVersion == (x) && \
593 new_params.version.firmwareRevision == (y))
597 unsigned long int _ret; \
598 _ret = simple_strtoul(buffer, &_p, 0); \
602 count -= _p - buffer; \
609 while (count && !retval) {
611 if (MATCH("brightness")) {
617 new_params.colourParams.brightness = val;
621 command_flags |= COMMAND_SETCOLOURPARAMS;
622 } else if (MATCH("contrast")) {
628 /* contrast is in steps of 8, so round*/
629 val = ((val + 3) / 8) * 8;
630 /* 1-02 firmware limits contrast to 80*/
631 if (FIRMWARE_VERSION(1,2) && val > 80)
634 new_params.colourParams.contrast = val;
638 command_flags |= COMMAND_SETCOLOURPARAMS;
639 } else if (MATCH("saturation")) {
645 new_params.colourParams.saturation = val;
649 command_flags |= COMMAND_SETCOLOURPARAMS;
650 } else if (MATCH("sensor_fps")) {
655 /* find values so that sensorFPS is minimized,
660 new_params.sensorFps.divisor = 0;
661 new_params.sensorFps.baserate = 1;
662 } else if (val > 15) {
663 new_params.sensorFps.divisor = 0;
664 new_params.sensorFps.baserate = 0;
665 } else if (val > 12) {
666 new_params.sensorFps.divisor = 1;
667 new_params.sensorFps.baserate = 1;
668 } else if (val > 7) {
669 new_params.sensorFps.divisor = 1;
670 new_params.sensorFps.baserate = 0;
671 } else if (val > 6) {
672 new_params.sensorFps.divisor = 2;
673 new_params.sensorFps.baserate = 1;
674 } else if (val > 3) {
675 new_params.sensorFps.divisor = 2;
676 new_params.sensorFps.baserate = 0;
678 new_params.sensorFps.divisor = 3;
679 /* Either base rate would work here */
680 new_params.sensorFps.baserate = 1;
682 new_params.flickerControl.coarseJump =
683 flicker_jumps[new_mains]
684 [new_params.sensorFps.baserate]
685 [new_params.sensorFps.divisor];
686 if (new_params.flickerControl.flickerMode)
687 command_flags |= COMMAND_SETFLICKERCTRL;
689 command_flags |= COMMAND_SETSENSORFPS;
690 } else if (MATCH("stream_start_line")) {
697 if (new_params.format.videoSize == VIDEOSIZE_QCIF)
700 new_params.streamStartLine = val/2;
704 } else if (MATCH("ecp_timing")) {
705 if (!retval && MATCH("normal"))
706 new_params.ecpTiming = 0;
707 else if (!retval && MATCH("slow"))
708 new_params.ecpTiming = 1;
712 command_flags |= COMMAND_SETECPTIMING;
713 } else if (MATCH("color_balance_mode")) {
714 if (!retval && MATCH("manual"))
715 new_params.colourBalance.balanceModeIsAuto = 0;
716 else if (!retval && MATCH("auto"))
717 new_params.colourBalance.balanceModeIsAuto = 1;
721 command_flags |= COMMAND_SETCOLOURBALANCE;
722 } else if (MATCH("red_gain")) {
728 new_params.colourBalance.redGain = val;
732 command_flags |= COMMAND_SETCOLOURBALANCE;
733 } else if (MATCH("green_gain")) {
739 new_params.colourBalance.greenGain = val;
743 command_flags |= COMMAND_SETCOLOURBALANCE;
744 } else if (MATCH("blue_gain")) {
750 new_params.colourBalance.blueGain = val;
754 command_flags |= COMMAND_SETCOLOURBALANCE;
755 } else if (MATCH("max_gain")) {
760 /* 1-02 firmware limits gain to 2 */
761 if (FIRMWARE_VERSION(1,2) && val > 2)
765 new_params.exposure.gainMode = 1;
768 new_params.exposure.gainMode = 2;
771 new_params.exposure.gainMode = 3;
774 new_params.exposure.gainMode = 4;
781 command_flags |= COMMAND_SETEXPOSURE;
782 } else if (MATCH("exposure_mode")) {
783 if (!retval && MATCH("auto"))
784 new_params.exposure.expMode = 2;
785 else if (!retval && MATCH("manual")) {
786 if (new_params.exposure.expMode == 2)
787 new_params.exposure.expMode = 3;
788 new_params.flickerControl.flickerMode = 0;
789 command_flags |= COMMAND_SETFLICKERCTRL;
793 command_flags |= COMMAND_SETEXPOSURE;
794 } else if (MATCH("centre_weight")) {
795 if (!retval && MATCH("on"))
796 new_params.exposure.centreWeight = 1;
797 else if (!retval && MATCH("off"))
798 new_params.exposure.centreWeight = 2;
802 command_flags |= COMMAND_SETEXPOSURE;
803 } else if (MATCH("gain")) {
810 new_params.exposure.gain = 0;
811 new_params.exposure.expMode = 1;
812 new_params.flickerControl.flickerMode = 0;
813 command_flags |= COMMAND_SETFLICKERCTRL;
816 new_params.exposure.gain = 1;
817 new_params.exposure.expMode = 1;
818 new_params.flickerControl.flickerMode = 0;
819 command_flags |= COMMAND_SETFLICKERCTRL;
822 new_params.exposure.gain = 2;
823 new_params.exposure.expMode = 1;
824 new_params.flickerControl.flickerMode = 0;
825 command_flags |= COMMAND_SETFLICKERCTRL;
828 new_params.exposure.gain = 3;
829 new_params.exposure.expMode = 1;
830 new_params.flickerControl.flickerMode = 0;
831 command_flags |= COMMAND_SETFLICKERCTRL;
837 command_flags |= COMMAND_SETEXPOSURE;
838 if (new_params.exposure.gain >
839 new_params.exposure.gainMode-1)
842 } else if (MATCH("fine_exp")) {
848 /* 1-02 firmware limits fineExp to 127*/
849 if (FIRMWARE_VERSION(1,2) && val > 127)
851 new_params.exposure.fineExp = val;
852 new_params.exposure.expMode = 1;
853 command_flags |= COMMAND_SETEXPOSURE;
854 new_params.flickerControl.flickerMode = 0;
855 command_flags |= COMMAND_SETFLICKERCTRL;
859 } else if (MATCH("coarse_exp")) {
865 /* 1-02 firmware limits
866 * coarseExp to 255 */
867 if (FIRMWARE_VERSION(1,2) && val > 255)
869 new_params.exposure.coarseExpLo =
871 new_params.exposure.coarseExpHi =
873 new_params.exposure.expMode = 1;
874 command_flags |= COMMAND_SETEXPOSURE;
875 new_params.flickerControl.flickerMode = 0;
876 command_flags |= COMMAND_SETFLICKERCTRL;
880 } else if (MATCH("red_comp")) {
885 if (val >= 220 && val <= 255) {
886 new_params.exposure.redComp = val;
887 command_flags |= COMMAND_SETEXPOSURE;
891 } else if (MATCH("green1_comp")) {
896 if (val >= 214 && val <= 255) {
897 new_params.exposure.green1Comp = val;
898 command_flags |= COMMAND_SETEXPOSURE;
902 } else if (MATCH("green2_comp")) {
907 if (val >= 214 && val <= 255) {
908 new_params.exposure.green2Comp = val;
909 command_flags |= COMMAND_SETEXPOSURE;
913 } else if (MATCH("blue_comp")) {
918 if (val >= 230 && val <= 255) {
919 new_params.exposure.blueComp = val;
920 command_flags |= COMMAND_SETEXPOSURE;
924 } else if (MATCH("apcor_gain1")) {
929 command_flags |= COMMAND_SETAPCOR;
931 new_params.apcor.gain1 = val;
935 } else if (MATCH("apcor_gain2")) {
940 command_flags |= COMMAND_SETAPCOR;
942 new_params.apcor.gain2 = val;
946 } else if (MATCH("apcor_gain4")) {
951 command_flags |= COMMAND_SETAPCOR;
953 new_params.apcor.gain4 = val;
957 } else if (MATCH("apcor_gain8")) {
962 command_flags |= COMMAND_SETAPCOR;
964 new_params.apcor.gain8 = val;
968 } else if (MATCH("vl_offset_gain1")) {
974 new_params.vlOffset.gain1 = val;
978 command_flags |= COMMAND_SETVLOFFSET;
979 } else if (MATCH("vl_offset_gain2")) {
985 new_params.vlOffset.gain2 = val;
989 command_flags |= COMMAND_SETVLOFFSET;
990 } else if (MATCH("vl_offset_gain4")) {
996 new_params.vlOffset.gain4 = val;
1000 command_flags |= COMMAND_SETVLOFFSET;
1001 } else if (MATCH("vl_offset_gain8")) {
1007 new_params.vlOffset.gain8 = val;
1011 command_flags |= COMMAND_SETVLOFFSET;
1012 } else if (MATCH("flicker_control")) {
1013 if (!retval && MATCH("on")) {
1014 new_params.flickerControl.flickerMode = 1;
1015 new_params.exposure.expMode = 2;
1016 command_flags |= COMMAND_SETEXPOSURE;
1017 } else if (!retval && MATCH("off"))
1018 new_params.flickerControl.flickerMode = 0;
1022 command_flags |= COMMAND_SETFLICKERCTRL;
1023 } else if (MATCH("mains_frequency")) {
1024 if (!retval && MATCH("50")) {
1026 new_params.flickerControl.coarseJump =
1027 flicker_jumps[new_mains]
1028 [new_params.sensorFps.baserate]
1029 [new_params.sensorFps.divisor];
1030 if (new_params.flickerControl.flickerMode)
1031 command_flags |= COMMAND_SETFLICKERCTRL;
1032 } else if (!retval && MATCH("60")) {
1034 new_params.flickerControl.coarseJump =
1035 flicker_jumps[new_mains]
1036 [new_params.sensorFps.baserate]
1037 [new_params.sensorFps.divisor];
1038 if (new_params.flickerControl.flickerMode)
1039 command_flags |= COMMAND_SETFLICKERCTRL;
1042 } else if (MATCH("allowable_overexposure")) {
1048 new_params.flickerControl.
1049 allowableOverExposure = val;
1050 command_flags |= COMMAND_SETFLICKERCTRL;
1054 } else if (MATCH("compression_mode")) {
1055 if (!retval && MATCH("none"))
1056 new_params.compression.mode =
1057 CPIA_COMPRESSION_NONE;
1058 else if (!retval && MATCH("auto"))
1059 new_params.compression.mode =
1060 CPIA_COMPRESSION_AUTO;
1061 else if (!retval && MATCH("manual"))
1062 new_params.compression.mode =
1063 CPIA_COMPRESSION_MANUAL;
1067 command_flags |= COMMAND_SETCOMPRESSION;
1068 } else if (MATCH("decimation_enable")) {
1069 if (!retval && MATCH("off"))
1070 new_params.compression.decimation = 0;
1074 command_flags |= COMMAND_SETCOMPRESSION;
1075 } else if (MATCH("compression_target")) {
1076 if (!retval && MATCH("quality"))
1077 new_params.compressionTarget.frTargeting =
1078 CPIA_COMPRESSION_TARGET_QUALITY;
1079 else if (!retval && MATCH("framerate"))
1080 new_params.compressionTarget.frTargeting =
1081 CPIA_COMPRESSION_TARGET_FRAMERATE;
1085 command_flags |= COMMAND_SETCOMPRESSIONTARGET;
1086 } else if (MATCH("target_framerate")) {
1091 new_params.compressionTarget.targetFR = val;
1092 command_flags |= COMMAND_SETCOMPRESSIONTARGET;
1093 } else if (MATCH("target_quality")) {
1098 new_params.compressionTarget.targetQ = val;
1100 command_flags |= COMMAND_SETCOMPRESSIONTARGET;
1101 } else if (MATCH("y_threshold")) {
1107 new_params.yuvThreshold.yThreshold = val;
1111 command_flags |= COMMAND_SETYUVTHRESH;
1112 } else if (MATCH("uv_threshold")) {
1118 new_params.yuvThreshold.uvThreshold = val;
1122 command_flags |= COMMAND_SETYUVTHRESH;
1123 } else if (MATCH("hysteresis")) {
1129 new_params.compressionParams.hysteresis = val;
1133 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1134 } else if (MATCH("threshold_max")) {
1140 new_params.compressionParams.threshMax = val;
1144 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1145 } else if (MATCH("small_step")) {
1151 new_params.compressionParams.smallStep = val;
1155 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1156 } else if (MATCH("large_step")) {
1162 new_params.compressionParams.largeStep = val;
1166 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1167 } else if (MATCH("decimation_hysteresis")) {
1173 new_params.compressionParams.decimationHysteresis = val;
1177 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1178 } else if (MATCH("fr_diff_step_thresh")) {
1184 new_params.compressionParams.frDiffStepThresh = val;
1188 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1189 } else if (MATCH("q_diff_step_thresh")) {
1195 new_params.compressionParams.qDiffStepThresh = val;
1199 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1200 } else if (MATCH("decimation_thresh_mod")) {
1206 new_params.compressionParams.decimationThreshMod = val;
1210 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1211 } else if (MATCH("toplight")) {
1212 if (!retval && MATCH("on"))
1213 new_params.qx3.toplight = 1;
1214 else if (!retval && MATCH("off"))
1215 new_params.qx3.toplight = 0;
1218 command_flags |= COMMAND_SETLIGHTS;
1219 } else if (MATCH("bottomlight")) {
1220 if (!retval && MATCH("on"))
1221 new_params.qx3.bottomlight = 1;
1222 else if (!retval && MATCH("off"))
1223 new_params.qx3.bottomlight = 0;
1226 command_flags |= COMMAND_SETLIGHTS;
1228 DBG("No match found\n");
1233 while (count && isspace(*buffer) && *buffer != '\n') {
1238 if (*buffer == '\0' && count != 1)
1240 else if (*buffer != '\n' && *buffer != ';' &&
1251 #undef FIRMWARE_VERSION
1256 if (command_flags & COMMAND_SETCOLOURPARAMS) {
1257 /* Adjust cam->vp to reflect these changes */
1258 cam->vp.brightness =
1259 new_params.colourParams.brightness*65535/100;
1261 new_params.colourParams.contrast*65535/100;
1263 new_params.colourParams.saturation*65535/100;
1266 memcpy(&cam->params, &new_params, sizeof(struct cam_params));
1267 cam->mainsFreq = new_mains;
1268 cam->cmd_queue |= command_flags;
1271 DBG("error: %d\n", retval);
1273 up(&cam->param_lock);
1276 free_page((unsigned long)page);
1280 static void create_proc_cpia_cam(struct cam_data *cam)
1283 struct proc_dir_entry *ent;
1285 if (!cpia_proc_root || !cam)
1288 sprintf(name, "video%d", cam->vdev.minor);
1290 ent = create_proc_entry(name, S_IFREG|S_IRUGO|S_IWUSR, cpia_proc_root);
1295 ent->read_proc = cpia_read_proc;
1296 ent->write_proc = cpia_write_proc;
1298 size of the proc entry is 3672 bytes for the standard webcam;
1299 the extra features of the QX3 microscope add 188 bytes.
1300 (we have not yet probed the camera to see which type it is).
1302 ent->size = 3672 + 188;
1303 cam->proc_entry = ent;
1306 static void destroy_proc_cpia_cam(struct cam_data *cam)
1310 if (!cam || !cam->proc_entry)
1313 sprintf(name, "video%d", cam->vdev.minor);
1314 remove_proc_entry(name, cpia_proc_root);
1315 cam->proc_entry = NULL;
1318 static void proc_cpia_create(void)
1320 cpia_proc_root = create_proc_entry("cpia", S_IFDIR, 0);
1323 cpia_proc_root->owner = THIS_MODULE;
1325 LOG("Unable to initialise /proc/cpia\n");
1328 static void proc_cpia_destroy(void)
1330 remove_proc_entry("cpia", 0);
1332 #endif /* CONFIG_PROC_FS */
1334 /* ----------------------- debug functions ---------------------- */
1336 #define printstatus(cam) \
1337 DBG("%02x %02x %02x %02x %02x %02x %02x %02x\n",\
1338 cam->params.status.systemState, cam->params.status.grabState, \
1339 cam->params.status.streamState, cam->params.status.fatalError, \
1340 cam->params.status.cmdError, cam->params.status.debugFlags, \
1341 cam->params.status.vpStatus, cam->params.status.errorCode);
1343 /* ----------------------- v4l helpers -------------------------- */
1345 /* supported frame palettes and depths */
1346 static inline int valid_mode(u16 palette, u16 depth)
1348 return (palette == VIDEO_PALETTE_GREY && depth == 8) ||
1349 (palette == VIDEO_PALETTE_RGB555 && depth == 16) ||
1350 (palette == VIDEO_PALETTE_RGB565 && depth == 16) ||
1351 (palette == VIDEO_PALETTE_RGB24 && depth == 24) ||
1352 (palette == VIDEO_PALETTE_RGB32 && depth == 32) ||
1353 (palette == VIDEO_PALETTE_YUV422 && depth == 16) ||
1354 (palette == VIDEO_PALETTE_YUYV && depth == 16) ||
1355 (palette == VIDEO_PALETTE_UYVY && depth == 16);
1358 static int match_videosize( int width, int height )
1360 /* return the best match, where 'best' is as always
1361 * the largest that is not bigger than what is requested. */
1362 if (width>=352 && height>=288)
1363 return VIDEOSIZE_352_288; /* CIF */
1365 if (width>=320 && height>=240)
1366 return VIDEOSIZE_320_240; /* SIF */
1368 if (width>=288 && height>=216)
1369 return VIDEOSIZE_288_216;
1371 if (width>=256 && height>=192)
1372 return VIDEOSIZE_256_192;
1374 if (width>=224 && height>=168)
1375 return VIDEOSIZE_224_168;
1377 if (width>=192 && height>=144)
1378 return VIDEOSIZE_192_144;
1380 if (width>=176 && height>=144)
1381 return VIDEOSIZE_176_144; /* QCIF */
1383 if (width>=160 && height>=120)
1384 return VIDEOSIZE_160_120; /* QSIF */
1386 if (width>=128 && height>=96)
1387 return VIDEOSIZE_128_96;
1389 if (width>=88 && height>=72)
1390 return VIDEOSIZE_88_72;
1392 if (width>=64 && height>=48)
1393 return VIDEOSIZE_64_48;
1395 if (width>=48 && height>=48)
1396 return VIDEOSIZE_48_48;
1401 /* these are the capture sizes we support */
1402 static void set_vw_size(struct cam_data *cam)
1404 /* the col/row/start/end values are the result of simple math */
1405 /* study the SetROI-command in cpia developers guide p 2-22 */
1406 /* streamStartLine is set to the recommended value in the cpia */
1407 /* developers guide p 3-37 */
1408 switch(cam->video_size) {
1410 cam->vw.width = 352;
1411 cam->vw.height = 288;
1412 cam->params.format.videoSize=VIDEOSIZE_CIF;
1413 cam->params.roi.colStart=0;
1414 cam->params.roi.colEnd=44;
1415 cam->params.roi.rowStart=0;
1416 cam->params.roi.rowEnd=72;
1417 cam->params.streamStartLine = 120;
1420 cam->vw.width = 320;
1421 cam->vw.height = 240;
1422 cam->params.format.videoSize=VIDEOSIZE_CIF;
1423 cam->params.roi.colStart=2;
1424 cam->params.roi.colEnd=42;
1425 cam->params.roi.rowStart=6;
1426 cam->params.roi.rowEnd=66;
1427 cam->params.streamStartLine = 120;
1429 case VIDEOSIZE_288_216:
1430 cam->vw.width = 288;
1431 cam->vw.height = 216;
1432 cam->params.format.videoSize=VIDEOSIZE_CIF;
1433 cam->params.roi.colStart=4;
1434 cam->params.roi.colEnd=40;
1435 cam->params.roi.rowStart=9;
1436 cam->params.roi.rowEnd=63;
1437 cam->params.streamStartLine = 120;
1439 case VIDEOSIZE_256_192:
1440 cam->vw.width = 256;
1441 cam->vw.height = 192;
1442 cam->params.format.videoSize=VIDEOSIZE_CIF;
1443 cam->params.roi.colStart=6;
1444 cam->params.roi.colEnd=38;
1445 cam->params.roi.rowStart=12;
1446 cam->params.roi.rowEnd=60;
1447 cam->params.streamStartLine = 120;
1449 case VIDEOSIZE_224_168:
1450 cam->vw.width = 224;
1451 cam->vw.height = 168;
1452 cam->params.format.videoSize=VIDEOSIZE_CIF;
1453 cam->params.roi.colStart=8;
1454 cam->params.roi.colEnd=36;
1455 cam->params.roi.rowStart=15;
1456 cam->params.roi.rowEnd=57;
1457 cam->params.streamStartLine = 120;
1459 case VIDEOSIZE_192_144:
1460 cam->vw.width = 192;
1461 cam->vw.height = 144;
1462 cam->params.format.videoSize=VIDEOSIZE_CIF;
1463 cam->params.roi.colStart=10;
1464 cam->params.roi.colEnd=34;
1465 cam->params.roi.rowStart=18;
1466 cam->params.roi.rowEnd=54;
1467 cam->params.streamStartLine = 120;
1469 case VIDEOSIZE_QCIF:
1470 cam->vw.width = 176;
1471 cam->vw.height = 144;
1472 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1473 cam->params.roi.colStart=0;
1474 cam->params.roi.colEnd=22;
1475 cam->params.roi.rowStart=0;
1476 cam->params.roi.rowEnd=36;
1477 cam->params.streamStartLine = 60;
1479 case VIDEOSIZE_QSIF:
1480 cam->vw.width = 160;
1481 cam->vw.height = 120;
1482 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1483 cam->params.roi.colStart=1;
1484 cam->params.roi.colEnd=21;
1485 cam->params.roi.rowStart=3;
1486 cam->params.roi.rowEnd=33;
1487 cam->params.streamStartLine = 60;
1489 case VIDEOSIZE_128_96:
1490 cam->vw.width = 128;
1491 cam->vw.height = 96;
1492 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1493 cam->params.roi.colStart=3;
1494 cam->params.roi.colEnd=19;
1495 cam->params.roi.rowStart=6;
1496 cam->params.roi.rowEnd=30;
1497 cam->params.streamStartLine = 60;
1499 case VIDEOSIZE_88_72:
1501 cam->vw.height = 72;
1502 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1503 cam->params.roi.colStart=5;
1504 cam->params.roi.colEnd=16;
1505 cam->params.roi.rowStart=9;
1506 cam->params.roi.rowEnd=27;
1507 cam->params.streamStartLine = 60;
1509 case VIDEOSIZE_64_48:
1511 cam->vw.height = 48;
1512 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1513 cam->params.roi.colStart=7;
1514 cam->params.roi.colEnd=15;
1515 cam->params.roi.rowStart=12;
1516 cam->params.roi.rowEnd=24;
1517 cam->params.streamStartLine = 60;
1519 case VIDEOSIZE_48_48:
1521 cam->vw.height = 48;
1522 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1523 cam->params.roi.colStart=8;
1524 cam->params.roi.colEnd=14;
1525 cam->params.roi.rowStart=6;
1526 cam->params.roi.rowEnd=30;
1527 cam->params.streamStartLine = 60;
1530 LOG("bad videosize value: %d\n", cam->video_size);
1536 static int allocate_frame_buf(struct cam_data *cam)
1540 cam->frame_buf = rvmalloc(FRAME_NUM * CPIA_MAX_FRAME_SIZE);
1541 if (!cam->frame_buf)
1544 for (i = 0; i < FRAME_NUM; i++)
1545 cam->frame[i].data = cam->frame_buf + i * CPIA_MAX_FRAME_SIZE;
1550 static int free_frame_buf(struct cam_data *cam)
1554 rvfree(cam->frame_buf, FRAME_NUM*CPIA_MAX_FRAME_SIZE);
1556 for (i=0; i < FRAME_NUM; i++)
1557 cam->frame[i].data = NULL;
1563 static void inline free_frames(struct cpia_frame frame[FRAME_NUM])
1567 for (i=0; i < FRAME_NUM; i++)
1568 frame[i].state = FRAME_UNUSED;
1572 /**********************************************************************
1576 **********************************************************************/
1577 /* send an arbitrary command to the camera */
1578 static int do_command(struct cam_data *cam, u16 command, u8 a, u8 b, u8 c, u8 d)
1580 int retval, datasize;
1584 case CPIA_COMMAND_GetCPIAVersion:
1585 case CPIA_COMMAND_GetPnPID:
1586 case CPIA_COMMAND_GetCameraStatus:
1587 case CPIA_COMMAND_GetVPVersion:
1590 case CPIA_COMMAND_GetColourParams:
1591 case CPIA_COMMAND_GetColourBalance:
1592 case CPIA_COMMAND_GetExposure:
1593 down(&cam->param_lock);
1596 case CPIA_COMMAND_ReadMCPorts:
1597 case CPIA_COMMAND_ReadVCRegs:
1605 cmd[0] = command>>8;
1606 cmd[1] = command&0xff;
1614 retval = cam->ops->transferCmd(cam->lowlevel_data, cmd, data);
1616 DBG("%x - failed, retval=%d\n", command, retval);
1617 if (command == CPIA_COMMAND_GetColourParams ||
1618 command == CPIA_COMMAND_GetColourBalance ||
1619 command == CPIA_COMMAND_GetExposure)
1620 up(&cam->param_lock);
1623 case CPIA_COMMAND_GetCPIAVersion:
1624 cam->params.version.firmwareVersion = data[0];
1625 cam->params.version.firmwareRevision = data[1];
1626 cam->params.version.vcVersion = data[2];
1627 cam->params.version.vcRevision = data[3];
1629 case CPIA_COMMAND_GetPnPID:
1630 cam->params.pnpID.vendor = data[0]+(((u16)data[1])<<8);
1631 cam->params.pnpID.product = data[2]+(((u16)data[3])<<8);
1632 cam->params.pnpID.deviceRevision =
1633 data[4]+(((u16)data[5])<<8);
1635 case CPIA_COMMAND_GetCameraStatus:
1636 cam->params.status.systemState = data[0];
1637 cam->params.status.grabState = data[1];
1638 cam->params.status.streamState = data[2];
1639 cam->params.status.fatalError = data[3];
1640 cam->params.status.cmdError = data[4];
1641 cam->params.status.debugFlags = data[5];
1642 cam->params.status.vpStatus = data[6];
1643 cam->params.status.errorCode = data[7];
1645 case CPIA_COMMAND_GetVPVersion:
1646 cam->params.vpVersion.vpVersion = data[0];
1647 cam->params.vpVersion.vpRevision = data[1];
1648 cam->params.vpVersion.cameraHeadID =
1649 data[2]+(((u16)data[3])<<8);
1651 case CPIA_COMMAND_GetColourParams:
1652 cam->params.colourParams.brightness = data[0];
1653 cam->params.colourParams.contrast = data[1];
1654 cam->params.colourParams.saturation = data[2];
1655 up(&cam->param_lock);
1657 case CPIA_COMMAND_GetColourBalance:
1658 cam->params.colourBalance.redGain = data[0];
1659 cam->params.colourBalance.greenGain = data[1];
1660 cam->params.colourBalance.blueGain = data[2];
1661 up(&cam->param_lock);
1663 case CPIA_COMMAND_GetExposure:
1664 cam->params.exposure.gain = data[0];
1665 cam->params.exposure.fineExp = data[1];
1666 cam->params.exposure.coarseExpLo = data[2];
1667 cam->params.exposure.coarseExpHi = data[3];
1668 cam->params.exposure.redComp = data[4];
1669 cam->params.exposure.green1Comp = data[5];
1670 cam->params.exposure.green2Comp = data[6];
1671 cam->params.exposure.blueComp = data[7];
1672 /* If the *Comp parameters are wacko, generate
1673 * a warning, and reset them back to default
1674 * values. - rich@annexia.org
1676 if (cam->params.exposure.redComp < 220 ||
1677 cam->params.exposure.redComp > 255 ||
1678 cam->params.exposure.green1Comp < 214 ||
1679 cam->params.exposure.green1Comp > 255 ||
1680 cam->params.exposure.green2Comp < 214 ||
1681 cam->params.exposure.green2Comp > 255 ||
1682 cam->params.exposure.blueComp < 230 ||
1683 cam->params.exposure.blueComp > 255)
1685 printk (KERN_WARNING "*_comp parameters have gone AWOL (%d/%d/%d/%d) - reseting them\n",
1686 cam->params.exposure.redComp,
1687 cam->params.exposure.green1Comp,
1688 cam->params.exposure.green2Comp,
1689 cam->params.exposure.blueComp);
1690 cam->params.exposure.redComp = 220;
1691 cam->params.exposure.green1Comp = 214;
1692 cam->params.exposure.green2Comp = 214;
1693 cam->params.exposure.blueComp = 230;
1695 up(&cam->param_lock);
1698 case CPIA_COMMAND_ReadMCPorts:
1699 if (!cam->params.qx3.qx3_detected)
1701 /* test button press */
1702 cam->params.qx3.button = ((data[1] & 0x02) == 0);
1703 if (cam->params.qx3.button) {
1704 /* button pressed - unlock the latch */
1705 do_command(cam,CPIA_COMMAND_WriteMCPort,3,0xDF,0xDF,0);
1706 do_command(cam,CPIA_COMMAND_WriteMCPort,3,0xFF,0xFF,0);
1709 /* test whether microscope is cradled */
1710 cam->params.qx3.cradled = ((data[2] & 0x40) == 0);
1720 /* send a command to the camera with an additional data transaction */
1721 static int do_command_extended(struct cam_data *cam, u16 command,
1722 u8 a, u8 b, u8 c, u8 d,
1723 u8 e, u8 f, u8 g, u8 h,
1724 u8 i, u8 j, u8 k, u8 l)
1729 cmd[0] = command>>8;
1730 cmd[1] = command&0xff;
1746 retval = cam->ops->transferCmd(cam->lowlevel_data, cmd, data);
1748 LOG("%x - failed\n", command);
1753 /**********************************************************************
1755 * Colorspace conversion
1757 **********************************************************************/
1758 #define LIMIT(x) ((((x)>0xffffff)?0xff0000:(((x)<=0xffff)?0:(x)&0xff0000))>>16)
1760 static int yuvconvert(unsigned char *yuv, unsigned char *rgb, int out_fmt,
1761 int in_uyvy, int mmap_kludge)
1763 int y, u, v, r, g, b, y1;
1766 case VIDEO_PALETTE_RGB555:
1767 case VIDEO_PALETTE_RGB565:
1768 case VIDEO_PALETTE_RGB24:
1769 case VIDEO_PALETTE_RGB32:
1772 y = (*yuv++ - 16) * 76310;
1774 y1 = (*yuv - 16) * 76310;
1776 y = (*yuv++ - 16) * 76310;
1778 y1 = (*yuv++ - 16) * 76310;
1782 g = -25690 * u + -53294 * v;
1790 /* Just to avoid compiler warnings */
1797 case VIDEO_PALETTE_RGB555:
1798 *rgb++ = ((LIMIT(g+y) & 0xf8) << 2) | (LIMIT(b+y) >> 3);
1799 *rgb++ = ((LIMIT(r+y) & 0xf8) >> 1) | (LIMIT(g+y) >> 6);
1800 *rgb++ = ((LIMIT(g+y1) & 0xf8) << 2) | (LIMIT(b+y1) >> 3);
1801 *rgb = ((LIMIT(r+y1) & 0xf8) >> 1) | (LIMIT(g+y1) >> 6);
1803 case VIDEO_PALETTE_RGB565:
1804 *rgb++ = ((LIMIT(g+y) & 0xfc) << 3) | (LIMIT(b+y) >> 3);
1805 *rgb++ = (LIMIT(r+y) & 0xf8) | (LIMIT(g+y) >> 5);
1806 *rgb++ = ((LIMIT(g+y1) & 0xfc) << 3) | (LIMIT(b+y1) >> 3);
1807 *rgb = (LIMIT(r+y1) & 0xf8) | (LIMIT(g+y1) >> 5);
1809 case VIDEO_PALETTE_RGB24:
1811 *rgb++ = LIMIT(b+y);
1812 *rgb++ = LIMIT(g+y);
1813 *rgb++ = LIMIT(r+y);
1814 *rgb++ = LIMIT(b+y1);
1815 *rgb++ = LIMIT(g+y1);
1818 *rgb++ = LIMIT(r+y);
1819 *rgb++ = LIMIT(g+y);
1820 *rgb++ = LIMIT(b+y);
1821 *rgb++ = LIMIT(r+y1);
1822 *rgb++ = LIMIT(g+y1);
1826 case VIDEO_PALETTE_RGB32:
1828 *rgb++ = LIMIT(b+y);
1829 *rgb++ = LIMIT(g+y);
1830 *rgb++ = LIMIT(r+y);
1832 *rgb++ = LIMIT(b+y1);
1833 *rgb++ = LIMIT(g+y1);
1836 *rgb++ = LIMIT(r+y);
1837 *rgb++ = LIMIT(g+y);
1838 *rgb++ = LIMIT(b+y);
1840 *rgb++ = LIMIT(r+y1);
1841 *rgb++ = LIMIT(g+y1);
1845 case VIDEO_PALETTE_GREY:
1849 case VIDEO_PALETTE_YUV422:
1850 case VIDEO_PALETTE_YUYV:
1856 case VIDEO_PALETTE_UYVY:
1863 DBG("Empty: %d\n", out_fmt);
1868 static int skipcount(int count, int fmt)
1871 case VIDEO_PALETTE_GREY:
1873 case VIDEO_PALETTE_RGB555:
1874 case VIDEO_PALETTE_RGB565:
1875 case VIDEO_PALETTE_YUV422:
1876 case VIDEO_PALETTE_YUYV:
1877 case VIDEO_PALETTE_UYVY:
1879 case VIDEO_PALETTE_RGB24:
1881 case VIDEO_PALETTE_RGB32:
1888 static int parse_picture(struct cam_data *cam, int size)
1890 u8 *obuf, *ibuf, *end_obuf;
1891 int ll, in_uyvy, compressed, origsize, out_fmt;
1893 /* make sure params don't change while we are decoding */
1894 down(&cam->param_lock);
1896 obuf = cam->decompressed_frame.data;
1897 end_obuf = obuf+CPIA_MAX_FRAME_SIZE;
1898 ibuf = cam->raw_image;
1900 out_fmt = cam->vp.palette;
1902 if ((ibuf[0] != MAGIC_0) || (ibuf[1] != MAGIC_1)) {
1903 LOG("header not found\n");
1904 up(&cam->param_lock);
1908 if ((ibuf[16] != VIDEOSIZE_QCIF) && (ibuf[16] != VIDEOSIZE_CIF)) {
1909 LOG("wrong video size\n");
1910 up(&cam->param_lock);
1914 if (ibuf[17] != SUBSAMPLE_422) {
1915 LOG("illegal subtype %d\n",ibuf[17]);
1916 up(&cam->param_lock);
1920 if (ibuf[18] != YUVORDER_YUYV && ibuf[18] != YUVORDER_UYVY) {
1921 LOG("illegal yuvorder %d\n",ibuf[18]);
1922 up(&cam->param_lock);
1925 in_uyvy = ibuf[18] == YUVORDER_UYVY;
1928 /* FIXME: ROI mismatch occurs when switching capture sizes */
1929 if ((ibuf[24] != cam->params.roi.colStart) ||
1930 (ibuf[25] != cam->params.roi.colEnd) ||
1931 (ibuf[26] != cam->params.roi.rowStart) ||
1932 (ibuf[27] != cam->params.roi.rowEnd)) {
1933 LOG("ROI mismatch\n");
1934 up(&cam->param_lock);
1939 if ((ibuf[28] != NOT_COMPRESSED) && (ibuf[28] != COMPRESSED)) {
1940 LOG("illegal compression %d\n",ibuf[28]);
1941 up(&cam->param_lock);
1944 compressed = (ibuf[28] == COMPRESSED);
1946 if (ibuf[29] != NO_DECIMATION) {
1947 LOG("decimation not supported\n");
1948 up(&cam->param_lock);
1952 cam->params.yuvThreshold.yThreshold = ibuf[30];
1953 cam->params.yuvThreshold.uvThreshold = ibuf[31];
1954 cam->params.status.systemState = ibuf[32];
1955 cam->params.status.grabState = ibuf[33];
1956 cam->params.status.streamState = ibuf[34];
1957 cam->params.status.fatalError = ibuf[35];
1958 cam->params.status.cmdError = ibuf[36];
1959 cam->params.status.debugFlags = ibuf[37];
1960 cam->params.status.vpStatus = ibuf[38];
1961 cam->params.status.errorCode = ibuf[39];
1962 cam->fps = ibuf[41];
1963 up(&cam->param_lock);
1965 ibuf += FRAME_HEADER_SIZE;
1966 size -= FRAME_HEADER_SIZE;
1967 ll = ibuf[0] | (ibuf[1] << 8);
1973 LOG("Insufficient data in buffer\n");
1978 if (!compressed || (compressed && !(*ibuf & 1))) {
1979 obuf += yuvconvert(ibuf, obuf, out_fmt,
1980 in_uyvy, cam->mmap_kludge);
1984 /*skip compressed interval from previous frame*/
1985 int skipsize = skipcount(*ibuf >> 1, out_fmt);
1987 if (obuf > end_obuf) {
1988 LOG("Insufficient data in buffer\n");
1997 LOG("EOL not found giving up after %d/%d"
1998 " bytes\n", origsize-size, origsize);
2002 ibuf++; /* skip over EOL */
2004 if ((size > 3) && (ibuf[0] == EOI) && (ibuf[1] == EOI) &&
2005 (ibuf[2] == EOI) && (ibuf[3] == EOI)) {
2011 ll = ibuf[0] | (ibuf[1] << 8);
2012 ibuf += 2; /* skip over line length */
2015 LOG("line length was not 1 but %d after %d/%d bytes\n",
2016 ll, origsize-size, origsize);
2021 cam->decompressed_frame.count = obuf-cam->decompressed_frame.data;
2023 return cam->decompressed_frame.count;
2026 /* InitStreamCap wrapper to select correct start line */
2027 static inline int init_stream_cap(struct cam_data *cam)
2029 return do_command(cam, CPIA_COMMAND_InitStreamCap,
2030 0, cam->params.streamStartLine, 0, 0);
2033 /* update various camera modes and settings */
2034 static void dispatch_commands(struct cam_data *cam)
2036 down(&cam->param_lock);
2037 if (cam->cmd_queue==COMMAND_NONE) {
2038 up(&cam->param_lock);
2041 DEB_BYTE(cam->cmd_queue);
2042 DEB_BYTE(cam->cmd_queue>>8);
2043 if (cam->cmd_queue & COMMAND_SETCOLOURPARAMS)
2044 do_command(cam, CPIA_COMMAND_SetColourParams,
2045 cam->params.colourParams.brightness,
2046 cam->params.colourParams.contrast,
2047 cam->params.colourParams.saturation, 0);
2049 if (cam->cmd_queue & COMMAND_SETCOMPRESSION)
2050 do_command(cam, CPIA_COMMAND_SetCompression,
2051 cam->params.compression.mode,
2052 cam->params.compression.decimation, 0, 0);
2054 if (cam->cmd_queue & COMMAND_SETFORMAT) {
2055 do_command(cam, CPIA_COMMAND_SetFormat,
2056 cam->params.format.videoSize,
2057 cam->params.format.subSample,
2058 cam->params.format.yuvOrder, 0);
2059 do_command(cam, CPIA_COMMAND_SetROI,
2060 cam->params.roi.colStart, cam->params.roi.colEnd,
2061 cam->params.roi.rowStart, cam->params.roi.rowEnd);
2062 cam->first_frame = 1;
2065 if (cam->cmd_queue & COMMAND_SETCOMPRESSIONTARGET)
2066 do_command(cam, CPIA_COMMAND_SetCompressionTarget,
2067 cam->params.compressionTarget.frTargeting,
2068 cam->params.compressionTarget.targetFR,
2069 cam->params.compressionTarget.targetQ, 0);
2071 if (cam->cmd_queue & COMMAND_SETYUVTHRESH)
2072 do_command(cam, CPIA_COMMAND_SetYUVThresh,
2073 cam->params.yuvThreshold.yThreshold,
2074 cam->params.yuvThreshold.uvThreshold, 0, 0);
2076 if (cam->cmd_queue & COMMAND_SETECPTIMING)
2077 do_command(cam, CPIA_COMMAND_SetECPTiming,
2078 cam->params.ecpTiming, 0, 0, 0);
2080 if (cam->cmd_queue & COMMAND_SETCOMPRESSIONPARAMS)
2081 do_command_extended(cam, CPIA_COMMAND_SetCompressionParams,
2083 cam->params.compressionParams.hysteresis,
2084 cam->params.compressionParams.threshMax,
2085 cam->params.compressionParams.smallStep,
2086 cam->params.compressionParams.largeStep,
2087 cam->params.compressionParams.decimationHysteresis,
2088 cam->params.compressionParams.frDiffStepThresh,
2089 cam->params.compressionParams.qDiffStepThresh,
2090 cam->params.compressionParams.decimationThreshMod);
2092 if (cam->cmd_queue & COMMAND_SETEXPOSURE)
2093 do_command_extended(cam, CPIA_COMMAND_SetExposure,
2094 cam->params.exposure.gainMode,
2095 cam->params.exposure.expMode,
2096 cam->params.exposure.compMode,
2097 cam->params.exposure.centreWeight,
2098 cam->params.exposure.gain,
2099 cam->params.exposure.fineExp,
2100 cam->params.exposure.coarseExpLo,
2101 cam->params.exposure.coarseExpHi,
2102 cam->params.exposure.redComp,
2103 cam->params.exposure.green1Comp,
2104 cam->params.exposure.green2Comp,
2105 cam->params.exposure.blueComp);
2107 if (cam->cmd_queue & COMMAND_SETCOLOURBALANCE) {
2108 if (cam->params.colourBalance.balanceModeIsAuto) {
2109 do_command(cam, CPIA_COMMAND_SetColourBalance,
2112 do_command(cam, CPIA_COMMAND_SetColourBalance,
2114 cam->params.colourBalance.redGain,
2115 cam->params.colourBalance.greenGain,
2116 cam->params.colourBalance.blueGain);
2117 do_command(cam, CPIA_COMMAND_SetColourBalance,
2122 if (cam->cmd_queue & COMMAND_SETSENSORFPS)
2123 do_command(cam, CPIA_COMMAND_SetSensorFPS,
2124 cam->params.sensorFps.divisor,
2125 cam->params.sensorFps.baserate, 0, 0);
2127 if (cam->cmd_queue & COMMAND_SETAPCOR)
2128 do_command(cam, CPIA_COMMAND_SetApcor,
2129 cam->params.apcor.gain1,
2130 cam->params.apcor.gain2,
2131 cam->params.apcor.gain4,
2132 cam->params.apcor.gain8);
2134 if (cam->cmd_queue & COMMAND_SETFLICKERCTRL)
2135 do_command(cam, CPIA_COMMAND_SetFlickerCtrl,
2136 cam->params.flickerControl.flickerMode,
2137 cam->params.flickerControl.coarseJump,
2138 cam->params.flickerControl.allowableOverExposure, 0);
2140 if (cam->cmd_queue & COMMAND_SETVLOFFSET)
2141 do_command(cam, CPIA_COMMAND_SetVLOffset,
2142 cam->params.vlOffset.gain1,
2143 cam->params.vlOffset.gain2,
2144 cam->params.vlOffset.gain4,
2145 cam->params.vlOffset.gain8);
2147 if (cam->cmd_queue & COMMAND_PAUSE)
2148 do_command(cam, CPIA_COMMAND_EndStreamCap, 0, 0, 0, 0);
2150 if (cam->cmd_queue & COMMAND_RESUME)
2151 init_stream_cap(cam);
2153 if (cam->cmd_queue & COMMAND_SETLIGHTS && cam->params.qx3.qx3_detected) {
2154 int p1 = (cam->params.qx3.bottomlight == 0) << 1;
2155 int p2 = (cam->params.qx3.toplight == 0) << 3;
2156 do_command(cam, CPIA_COMMAND_WriteVCReg, 0x90, 0x8F, 0x50, 0);
2157 do_command(cam, CPIA_COMMAND_WriteMCPort, 2, 0, (p1|p2|0xE0), 0);
2160 up(&cam->param_lock);
2161 cam->cmd_queue = COMMAND_NONE;
2165 /* kernel thread function to read image from camera */
2166 static void fetch_frame(void *data)
2168 int image_size, retry;
2169 struct cam_data *cam = (struct cam_data *)data;
2170 unsigned long oldjif, rate, diff;
2172 /* Allow up to two bad images in a row to be read and
2173 * ignored before an error is reported */
2174 for (retry = 0; retry < 3; ++retry) {
2176 DBG("retry=%d\n", retry);
2181 /* load first frame always uncompressed */
2182 if (cam->first_frame &&
2183 cam->params.compression.mode != CPIA_COMPRESSION_NONE)
2184 do_command(cam, CPIA_COMMAND_SetCompression,
2185 CPIA_COMPRESSION_NONE,
2186 NO_DECIMATION, 0, 0);
2188 /* init camera upload */
2189 if (do_command(cam, CPIA_COMMAND_SetGrabMode,
2190 CPIA_GRAB_CONTINUOUS, 0, 0, 0))
2193 if (do_command(cam, CPIA_COMMAND_GrabFrame, 0,
2194 cam->params.streamStartLine, 0, 0))
2197 if (cam->ops->wait_for_stream_ready) {
2198 /* loop until image ready */
2199 do_command(cam, CPIA_COMMAND_GetCameraStatus,0,0,0,0);
2200 while (cam->params.status.streamState != STREAM_READY) {
2201 if (current->need_resched)
2204 current->state = TASK_INTERRUPTIBLE;
2206 /* sleep for 10 ms, hopefully ;) */
2207 schedule_timeout(10*HZ/1000);
2208 if (signal_pending(current))
2211 do_command(cam, CPIA_COMMAND_GetCameraStatus,
2216 /* grab image from camera */
2217 if (current->need_resched)
2221 image_size = cam->ops->streamRead(cam->lowlevel_data,
2223 if (image_size <= 0) {
2224 DBG("streamRead failed: %d\n", image_size);
2228 rate = image_size * HZ / 1024;
2229 diff = jiffies-oldjif;
2230 cam->transfer_rate = diff==0 ? rate : rate/diff;
2231 /* diff==0 ? unlikely but possible */
2233 /* camera idle now so dispatch queued commands */
2234 dispatch_commands(cam);
2236 /* Update our knowledge of the camera state */
2237 do_command(cam, CPIA_COMMAND_GetColourBalance, 0, 0, 0, 0);
2238 do_command(cam, CPIA_COMMAND_GetExposure, 0, 0, 0, 0);
2239 do_command(cam, CPIA_COMMAND_ReadMCPorts, 0, 0, 0, 0);
2241 /* decompress and convert image to by copying it from
2242 * raw_image to decompressed_frame
2244 if (current->need_resched)
2247 cam->image_size = parse_picture(cam, image_size);
2248 if (cam->image_size <= 0)
2249 DBG("parse_picture failed %d\n", cam->image_size);
2255 /* FIXME: this only works for double buffering */
2256 if (cam->frame[cam->curframe].state == FRAME_READY) {
2257 memcpy(cam->frame[cam->curframe].data,
2258 cam->decompressed_frame.data,
2259 cam->decompressed_frame.count);
2260 cam->frame[cam->curframe].state = FRAME_DONE;
2262 cam->decompressed_frame.state = FRAME_DONE;
2265 if (cam->first_frame &&
2266 cam->params.compression.mode != CPIA_COMPRESSION_NONE) {
2267 cam->first_frame = 0;
2268 cam->cmd_queue |= COMMAND_SETCOMPRESSION;
2271 if (cam->first_frame) {
2272 cam->first_frame = 0;
2273 cam->cmd_queue |= COMMAND_SETCOMPRESSION;
2274 cam->cmd_queue |= COMMAND_SETEXPOSURE;
2280 static int capture_frame(struct cam_data *cam, struct video_mmap *vm)
2284 if (!cam->frame_buf) {
2285 /* we do lazy allocation */
2286 if ((retval = allocate_frame_buf(cam)))
2290 /* FIXME: the first frame seems to be captured by the camera
2291 without regards to any initial settings, so we throw away
2292 that one, the next one is generated with our settings
2293 (exposure, color balance, ...)
2295 if (cam->first_frame) {
2296 cam->curframe = vm->frame;
2297 cam->frame[cam->curframe].state = FRAME_READY;
2299 if (cam->frame[cam->curframe].state != FRAME_DONE)
2302 cam->curframe = vm->frame;
2303 cam->frame[cam->curframe].state = FRAME_READY;
2305 if (cam->frame[cam->curframe].state != FRAME_DONE)
2311 static int goto_high_power(struct cam_data *cam)
2313 if (do_command(cam, CPIA_COMMAND_GotoHiPower, 0, 0, 0, 0))
2315 mdelay(100); /* windows driver does it too */
2316 if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0))
2318 if (cam->params.status.systemState == HI_POWER_STATE) {
2319 DBG("camera now in HIGH power state\n");
2326 static int goto_low_power(struct cam_data *cam)
2328 if (do_command(cam, CPIA_COMMAND_GotoLoPower, 0, 0, 0, 0))
2330 if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0))
2332 if (cam->params.status.systemState == LO_POWER_STATE) {
2333 DBG("camera now in LOW power state\n");
2340 static void save_camera_state(struct cam_data *cam)
2342 do_command(cam, CPIA_COMMAND_GetColourBalance, 0, 0, 0, 0);
2343 do_command(cam, CPIA_COMMAND_GetExposure, 0, 0, 0, 0);
2345 DBG("%d/%d/%d/%d/%d/%d/%d/%d\n",
2346 cam->params.exposure.gain,
2347 cam->params.exposure.fineExp,
2348 cam->params.exposure.coarseExpLo,
2349 cam->params.exposure.coarseExpHi,
2350 cam->params.exposure.redComp,
2351 cam->params.exposure.green1Comp,
2352 cam->params.exposure.green2Comp,
2353 cam->params.exposure.blueComp);
2355 cam->params.colourBalance.redGain,
2356 cam->params.colourBalance.greenGain,
2357 cam->params.colourBalance.blueGain);
2360 static void set_camera_state(struct cam_data *cam)
2362 if(cam->params.colourBalance.balanceModeIsAuto) {
2363 do_command(cam, CPIA_COMMAND_SetColourBalance,
2366 do_command(cam, CPIA_COMMAND_SetColourBalance,
2368 cam->params.colourBalance.redGain,
2369 cam->params.colourBalance.greenGain,
2370 cam->params.colourBalance.blueGain);
2371 do_command(cam, CPIA_COMMAND_SetColourBalance,
2376 do_command_extended(cam, CPIA_COMMAND_SetExposure,
2377 cam->params.exposure.gainMode, 1, 1,
2378 cam->params.exposure.centreWeight,
2379 cam->params.exposure.gain,
2380 cam->params.exposure.fineExp,
2381 cam->params.exposure.coarseExpLo,
2382 cam->params.exposure.coarseExpHi,
2383 cam->params.exposure.redComp,
2384 cam->params.exposure.green1Comp,
2385 cam->params.exposure.green2Comp,
2386 cam->params.exposure.blueComp);
2387 do_command_extended(cam, CPIA_COMMAND_SetExposure,
2389 0, 0, 0, 0, 0, 0, 0, 0);
2391 if (!cam->params.exposure.gainMode)
2392 cam->params.exposure.gainMode = 2;
2393 if (!cam->params.exposure.expMode)
2394 cam->params.exposure.expMode = 2;
2395 if (!cam->params.exposure.centreWeight)
2396 cam->params.exposure.centreWeight = 1;
2398 cam->cmd_queue = COMMAND_SETCOMPRESSION |
2399 COMMAND_SETCOMPRESSIONTARGET |
2400 COMMAND_SETCOLOURPARAMS |
2402 COMMAND_SETYUVTHRESH |
2403 COMMAND_SETECPTIMING |
2404 COMMAND_SETCOMPRESSIONPARAMS |
2406 COMMAND_SETEXPOSURE |
2408 COMMAND_SETCOLOURBALANCE |
2409 COMMAND_SETSENSORFPS |
2411 COMMAND_SETFLICKERCTRL |
2412 COMMAND_SETVLOFFSET;
2413 dispatch_commands(cam);
2414 save_camera_state(cam);
2419 static void get_version_information(struct cam_data *cam)
2421 /* GetCPIAVersion */
2422 do_command(cam, CPIA_COMMAND_GetCPIAVersion, 0, 0, 0, 0);
2425 do_command(cam, CPIA_COMMAND_GetPnPID, 0, 0, 0, 0);
2428 /* initialize camera */
2429 static int reset_camera(struct cam_data *cam)
2431 /* Start the camera in low power mode */
2432 if (goto_low_power(cam)) {
2433 if (cam->params.status.systemState != WARM_BOOT_STATE)
2436 /* FIXME: this is just dirty trial and error */
2437 reset_camera_struct(cam);
2438 goto_high_power(cam);
2439 do_command(cam, CPIA_COMMAND_DiscardFrame, 0, 0, 0, 0);
2440 if (goto_low_power(cam))
2444 /* procedure described in developer's guide p3-28 */
2446 /* Check the firmware version FIXME: should we check PNPID? */
2447 cam->params.version.firmwareVersion = 0;
2448 get_version_information(cam);
2449 if (cam->params.version.firmwareVersion != 1)
2452 /* set QX3 detected flag */
2453 cam->params.qx3.qx3_detected = (cam->params.pnpID.vendor == 0x0813 &&
2454 cam->params.pnpID.product == 0x0001);
2456 /* The fatal error checking should be done after
2457 * the camera powers up (developer's guide p 3-38) */
2459 /* Set streamState before transition to high power to avoid bug
2460 * in firmware 1-02 */
2461 do_command(cam, CPIA_COMMAND_ModifyCameraStatus, STREAMSTATE, 0,
2462 STREAM_NOT_READY, 0);
2465 if (goto_high_power(cam))
2468 /* Check the camera status */
2469 if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0))
2472 if (cam->params.status.fatalError) {
2473 DBG("fatal_error: %#04x\n",
2474 cam->params.status.fatalError);
2475 DBG("vp_status: %#04x\n",
2476 cam->params.status.vpStatus);
2477 if (cam->params.status.fatalError & ~(COM_FLAG|CPIA_FLAG)) {
2478 /* Fatal error in camera */
2480 } else if (cam->params.status.fatalError & (COM_FLAG|CPIA_FLAG)) {
2481 /* Firmware 1-02 may do this for parallel port cameras,
2482 * just clear the flags (developer's guide p 3-38) */
2483 do_command(cam, CPIA_COMMAND_ModifyCameraStatus,
2484 FATALERROR, ~(COM_FLAG|CPIA_FLAG), 0, 0);
2488 /* Check the camera status again */
2489 if (cam->params.status.fatalError) {
2490 if (cam->params.status.fatalError)
2494 /* VPVersion can't be retrieved before the camera is in HiPower,
2495 * so get it here instead of in get_version_information. */
2496 do_command(cam, CPIA_COMMAND_GetVPVersion, 0, 0, 0, 0);
2498 /* set camera to a known state */
2499 set_camera_state(cam);
2504 /* ------------------------- V4L interface --------------------- */
2505 static int cpia_open(struct video_device *dev, int flags)
2508 struct cam_data *cam = dev->priv;
2511 DBG("Internal error, cam_data not found!\n");
2515 if (cam->open_count > 0) {
2516 DBG("Camera already open\n");
2520 if (!cam->raw_image) {
2521 cam->raw_image = rvmalloc(CPIA_MAX_IMAGE_SIZE);
2522 if (!cam->raw_image)
2526 if (!cam->decompressed_frame.data) {
2527 cam->decompressed_frame.data = rvmalloc(CPIA_MAX_FRAME_SIZE);
2528 if (!cam->decompressed_frame.data) {
2529 rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
2530 cam->raw_image = NULL;
2536 if (cam->ops->open(cam->lowlevel_data)) {
2537 rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE);
2538 cam->decompressed_frame.data = NULL;
2539 rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
2540 cam->raw_image = NULL;
2544 /* reset the camera */
2545 if ((i = reset_camera(cam)) != 0) {
2546 cam->ops->close(cam->lowlevel_data);
2547 rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE);
2548 cam->decompressed_frame.data = NULL;
2549 rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
2550 cam->raw_image = NULL;
2554 /* Set ownership of /proc/cpia/videoX to current user */
2556 cam->proc_entry->uid = current->uid;
2558 /* set mark for loading first frame uncompressed */
2559 cam->first_frame = 1;
2561 /* init it to something */
2562 cam->mmap_kludge = 0;
2568 static void cpia_close(struct video_device *dev)
2570 struct cam_data *cam;
2575 /* Return ownership of /proc/cpia/videoX to root */
2577 cam->proc_entry->uid = 0;
2579 /* save camera state for later open (developers guide ch 3.5.3) */
2580 save_camera_state(cam);
2583 goto_low_power(cam);
2585 /* Update the camera status */
2586 do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0);
2588 /* cleanup internal state stuff */
2589 free_frames(cam->frame);
2592 cam->ops->close(cam->lowlevel_data);
2595 if (--cam->open_count == 0) {
2596 /* clean up capture-buffers */
2597 if (cam->raw_image) {
2598 rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
2599 cam->raw_image = NULL;
2602 if (cam->decompressed_frame.data) {
2603 rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE);
2604 cam->decompressed_frame.data = NULL;
2608 free_frame_buf(cam);
2611 video_unregister_device(dev);
2620 static long cpia_read(struct video_device *dev, char *buf,
2621 unsigned long count, int noblock)
2623 struct cam_data *cam = dev->priv;
2625 /* make this _really_ smp and multithread-safe */
2626 if (down_interruptible(&cam->busy_lock))
2631 up(&cam->busy_lock);
2637 up(&cam->busy_lock);
2643 up(&cam->busy_lock);
2648 cam->decompressed_frame.state = FRAME_READY;
2651 if (cam->decompressed_frame.state != FRAME_DONE) {
2652 DBG("upload failed %d/%d\n", cam->decompressed_frame.count,
2653 cam->decompressed_frame.state);
2654 up(&cam->busy_lock);
2657 cam->decompressed_frame.state = FRAME_UNUSED;
2659 /* copy data to user space */
2660 if (cam->decompressed_frame.count > count) {
2661 DBG("count wrong: %d, %lu\n", cam->decompressed_frame.count,
2663 up(&cam->busy_lock);
2666 if (copy_to_user(buf, cam->decompressed_frame.data,
2667 cam->decompressed_frame.count)) {
2668 DBG("copy_to_user failed\n");
2669 up(&cam->busy_lock);
2673 up(&cam->busy_lock);
2674 return cam->decompressed_frame.count;
2677 static int cpia_ioctl(struct video_device *dev, unsigned int ioctlnr, void *arg)
2679 struct cam_data *cam = dev->priv;
2682 if (!cam || !cam->ops)
2685 /* make this _really_ smp-safe */
2686 if (down_interruptible(&cam->busy_lock))
2689 //DBG("cpia_ioctl: %u\n", ioctlnr);
2692 /* query capabilites */
2695 struct video_capability b;
2697 DBG("VIDIOCGCAP\n");
2698 strcpy(b.name, "CPiA Camera");
2699 b.type = VID_TYPE_CAPTURE;
2702 b.maxwidth = 352; /* VIDEOSIZE_CIF */
2704 b.minwidth = 48; /* VIDEOSIZE_48_48 */
2707 if (copy_to_user(arg, &b, sizeof(b)))
2713 /* get/set video source - we are a camera and nothing else */
2716 struct video_channel v;
2718 DBG("VIDIOCGCHAN\n");
2719 if (copy_from_user(&v, arg, sizeof(v))) {
2723 if (v.channel != 0) {
2729 strcpy(v.name, "Camera");
2732 v.type = VIDEO_TYPE_CAMERA;
2735 if (copy_to_user(arg, &v, sizeof(v)))
2744 DBG("VIDIOCSCHAN\n");
2745 if (copy_from_user(&v, arg, sizeof(v)))
2748 if (retval == 0 && v != 0)
2754 /* image properties */
2756 DBG("VIDIOCGPICT\n");
2757 if (copy_to_user(arg, &cam->vp, sizeof(struct video_picture)))
2763 struct video_picture vp;
2765 DBG("VIDIOCSPICT\n");
2767 /* copy_from_user */
2768 if (copy_from_user(&vp, arg, sizeof(vp))) {
2773 /* check validity */
2774 DBG("palette: %d\n", vp.palette);
2775 DBG("depth: %d\n", vp.depth);
2776 if (!valid_mode(vp.palette, vp.depth)) {
2781 down(&cam->param_lock);
2782 /* brightness, colour, contrast need no check 0-65535 */
2783 memcpy( &cam->vp, &vp, sizeof(vp) );
2784 /* update cam->params.colourParams */
2785 cam->params.colourParams.brightness = vp.brightness*100/65535;
2786 cam->params.colourParams.contrast = vp.contrast*100/65535;
2787 cam->params.colourParams.saturation = vp.colour*100/65535;
2788 /* contrast is in steps of 8, so round */
2789 cam->params.colourParams.contrast =
2790 ((cam->params.colourParams.contrast + 3) / 8) * 8;
2791 if (cam->params.version.firmwareVersion == 1 &&
2792 cam->params.version.firmwareRevision == 2 &&
2793 cam->params.colourParams.contrast > 80) {
2794 /* 1-02 firmware limits contrast to 80 */
2795 cam->params.colourParams.contrast = 80;
2798 /* queue command to update camera */
2799 cam->cmd_queue |= COMMAND_SETCOLOURPARAMS;
2800 up(&cam->param_lock);
2801 DBG("VIDIOCSPICT: %d / %d // %d / %d / %d / %d\n",
2802 vp.depth, vp.palette, vp.brightness, vp.hue, vp.colour,
2807 /* get/set capture window */
2809 DBG("VIDIOCGWIN\n");
2811 if (copy_to_user(arg, &cam->vw, sizeof(struct video_window)))
2817 /* copy_from_user, check validity, copy to internal structure */
2818 struct video_window vw;
2819 DBG("VIDIOCSWIN\n");
2820 if (copy_from_user(&vw, arg, sizeof(vw))) {
2825 if (vw.clipcount != 0) { /* clipping not supported */
2829 if (vw.clips != NULL) { /* clipping not supported */
2834 /* we set the video window to something smaller or equal to what
2835 * is requested by the user???
2837 down(&cam->param_lock);
2838 if (vw.width != cam->vw.width || vw.height != cam->vw.height) {
2839 int video_size = match_videosize(vw.width, vw.height);
2841 if (video_size < 0) {
2843 up(&cam->param_lock);
2846 cam->video_size = video_size;
2848 DBG("%d / %d\n", cam->vw.width, cam->vw.height);
2849 cam->cmd_queue |= COMMAND_SETFORMAT;
2852 up(&cam->param_lock);
2854 /* setformat ignored by camera during streaming,
2855 * so stop/dispatch/start */
2856 if (cam->cmd_queue & COMMAND_SETFORMAT) {
2858 dispatch_commands(cam);
2860 DBG("%d/%d:%d\n", cam->video_size,
2861 cam->vw.width, cam->vw.height);
2865 /* mmap interface */
2868 struct video_mbuf vm;
2871 DBG("VIDIOCGMBUF\n");
2872 memset(&vm, 0, sizeof(vm));
2873 vm.size = CPIA_MAX_FRAME_SIZE*FRAME_NUM;
2874 vm.frames = FRAME_NUM;
2875 for (i = 0; i < FRAME_NUM; i++)
2876 vm.offsets[i] = CPIA_MAX_FRAME_SIZE * i;
2878 if (copy_to_user((void *)arg, (void *)&vm, sizeof(vm)))
2884 case VIDIOCMCAPTURE:
2886 struct video_mmap vm;
2889 if (copy_from_user((void *)&vm, (void *)arg, sizeof(vm))) {
2893 DBG("VIDIOCMCAPTURE: %d / %d / %dx%d\n", vm.format, vm.frame,
2894 vm.width, vm.height);
2895 if (vm.frame<0||vm.frame>=FRAME_NUM) {
2900 /* set video format */
2901 cam->vp.palette = vm.format;
2903 case VIDEO_PALETTE_GREY:
2906 case VIDEO_PALETTE_RGB555:
2907 case VIDEO_PALETTE_RGB565:
2908 case VIDEO_PALETTE_YUV422:
2909 case VIDEO_PALETTE_YUYV:
2910 case VIDEO_PALETTE_UYVY:
2913 case VIDEO_PALETTE_RGB24:
2916 case VIDEO_PALETTE_RGB32:
2926 /* set video size */
2927 video_size = match_videosize(vm.width, vm.height);
2928 if (video_size < 0) {
2932 if (video_size != cam->video_size) {
2933 cam->video_size = video_size;
2935 cam->cmd_queue |= COMMAND_SETFORMAT;
2936 dispatch_commands(cam);
2938 /* according to v4l-spec we must start streaming here */
2939 cam->mmap_kludge = 1;
2940 retval = capture_frame(cam, &vm);
2949 if (copy_from_user((void *)&frame, arg, sizeof(int))) {
2953 //DBG("VIDIOCSYNC: %d\n", frame);
2955 if (frame<0 || frame >= FRAME_NUM) {
2960 switch (cam->frame[frame].state) {
2963 case FRAME_GRABBING:
2964 DBG("sync to unused frame %d\n", frame);
2969 cam->frame[frame].state = FRAME_UNUSED;
2970 //DBG("VIDIOCSYNC: %d synced\n", frame);
2973 if (retval == -EINTR) {
2974 /* FIXME - xawtv does not handle this nice */
2980 /* pointless to implement overlay with this camera */
2994 /* tuner interface - we have none */
3008 /* audio interface - we have none */
3016 retval = -ENOIOCTLCMD;
3020 up(&cam->param_lock);
3021 up(&cam->busy_lock);
3026 static int cpia_mmap(struct video_device *dev, const char *adr,
3029 unsigned long start = (unsigned long)adr;
3030 unsigned long page, pos;
3031 struct cam_data *cam = dev->priv;
3034 if (!cam || !cam->ops)
3037 DBG("cpia_mmap: %ld\n", size);
3039 if (size > FRAME_NUM*CPIA_MAX_FRAME_SIZE)
3042 if (!cam || !cam->ops)
3045 /* make this _really_ smp-safe */
3046 if (down_interruptible(&cam->busy_lock))
3049 if (!cam->frame_buf) { /* we do lazy allocation */
3050 if ((retval = allocate_frame_buf(cam))) {
3051 up(&cam->busy_lock);
3056 pos = (unsigned long)(cam->frame_buf);
3058 page = kvirt_to_pa(pos);
3059 if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) {
3060 up(&cam->busy_lock);
3065 if (size > PAGE_SIZE)
3071 DBG("cpia_mmap: %ld\n", size);
3072 up(&cam->busy_lock);
3077 int cpia_video_init(struct video_device *vdev)
3079 #ifdef CONFIG_PROC_FS
3080 create_proc_cpia_cam(vdev->priv);
3085 static struct video_device cpia_template = {
3087 name: "CPiA Camera",
3088 type: VID_TYPE_CAPTURE,
3089 hardware: VID_HARDWARE_CPIA,
3095 initialize: cpia_video_init,
3099 /* initialise cam_data structure */
3100 static void reset_camera_struct(struct cam_data *cam)
3102 /* The following parameter values are the defaults from
3103 * "Software Developer's Guide for CPiA Cameras". Any changes
3104 * to the defaults are noted in comments. */
3105 cam->params.colourParams.brightness = 50;
3106 cam->params.colourParams.contrast = 48;
3107 cam->params.colourParams.saturation = 50;
3108 cam->params.exposure.gainMode = 2;
3109 cam->params.exposure.expMode = 2; /* AEC */
3110 cam->params.exposure.compMode = 1;
3111 cam->params.exposure.centreWeight = 1;
3112 cam->params.exposure.gain = 0;
3113 cam->params.exposure.fineExp = 0;
3114 cam->params.exposure.coarseExpLo = 185;
3115 cam->params.exposure.coarseExpHi = 0;
3116 cam->params.exposure.redComp = 220;
3117 cam->params.exposure.green1Comp = 214;
3118 cam->params.exposure.green2Comp = 214;
3119 cam->params.exposure.blueComp = 230;
3120 cam->params.colourBalance.balanceModeIsAuto = 1;
3121 cam->params.colourBalance.redGain = 32;
3122 cam->params.colourBalance.greenGain = 6;
3123 cam->params.colourBalance.blueGain = 92;
3124 cam->params.apcor.gain1 = 0x1c;
3125 cam->params.apcor.gain2 = 0x1a;
3126 cam->params.apcor.gain4 = 0x2d;
3127 cam->params.apcor.gain8 = 0x2a;
3128 cam->params.flickerControl.flickerMode = 0;
3129 cam->params.flickerControl.coarseJump =
3130 flicker_jumps[cam->mainsFreq]
3131 [cam->params.sensorFps.baserate]
3132 [cam->params.sensorFps.divisor];
3133 cam->params.vlOffset.gain1 = 24;
3134 cam->params.vlOffset.gain2 = 28;
3135 cam->params.vlOffset.gain4 = 30;
3136 cam->params.vlOffset.gain8 = 30;
3137 cam->params.compressionParams.hysteresis = 3;
3138 cam->params.compressionParams.threshMax = 11;
3139 cam->params.compressionParams.smallStep = 1;
3140 cam->params.compressionParams.largeStep = 3;
3141 cam->params.compressionParams.decimationHysteresis = 2;
3142 cam->params.compressionParams.frDiffStepThresh = 5;
3143 cam->params.compressionParams.qDiffStepThresh = 3;
3144 cam->params.compressionParams.decimationThreshMod = 2;
3145 /* End of default values from Software Developer's Guide */
3147 cam->transfer_rate = 0;
3149 /* Set Sensor FPS to 15fps. This seems better than 30fps
3150 * for indoor lighting. */
3151 cam->params.sensorFps.divisor = 1;
3152 cam->params.sensorFps.baserate = 1;
3154 cam->params.yuvThreshold.yThreshold = 6; /* From windows driver */
3155 cam->params.yuvThreshold.uvThreshold = 6; /* From windows driver */
3157 cam->params.format.subSample = SUBSAMPLE_422;
3158 cam->params.format.yuvOrder = YUVORDER_YUYV;
3160 cam->params.compression.mode = CPIA_COMPRESSION_AUTO;
3161 cam->params.compressionTarget.frTargeting =
3162 CPIA_COMPRESSION_TARGET_QUALITY;
3163 cam->params.compressionTarget.targetFR = 15; /* From windows driver */
3164 cam->params.compressionTarget.targetQ = 5; /* From windows driver */
3166 cam->params.qx3.qx3_detected = 0;
3167 cam->params.qx3.toplight = 0;
3168 cam->params.qx3.bottomlight = 0;
3169 cam->params.qx3.button = 0;
3170 cam->params.qx3.cradled = 0;
3172 cam->video_size = VIDEOSIZE_CIF;
3174 cam->vp.colour = 32768; /* 50% */
3175 cam->vp.hue = 32768; /* 50% */
3176 cam->vp.brightness = 32768; /* 50% */
3177 cam->vp.contrast = 32768; /* 50% */
3178 cam->vp.whiteness = 0; /* not used -> grayscale only */
3179 cam->vp.depth = 24; /* to be set by user */
3180 cam->vp.palette = VIDEO_PALETTE_RGB24; /* to be set by user */
3185 cam->vw.chromakey = 0;
3186 /* PP NOTE: my extension to use vw.flags for this, bear it! */
3188 cam->vw.clipcount = 0;
3189 cam->vw.clips = NULL;
3191 cam->cmd_queue = COMMAND_NONE;
3192 cam->first_frame = 0;
3197 /* initialize cam_data structure */
3198 static void init_camera_struct(struct cam_data *cam,
3199 struct cpia_camera_ops *ops )
3203 /* Default everything to 0 */
3204 memset(cam, 0, sizeof(struct cam_data));
3207 init_MUTEX(&cam->param_lock);
3208 init_MUTEX(&cam->busy_lock);
3210 reset_camera_struct(cam);
3212 cam->proc_entry = NULL;
3214 memcpy(&cam->vdev, &cpia_template, sizeof(cpia_template));
3215 cam->vdev.priv = cam;
3218 for (i = 0; i < FRAME_NUM; i++) {
3219 cam->frame[i].width = 0;
3220 cam->frame[i].height = 0;
3221 cam->frame[i].state = FRAME_UNUSED;
3222 cam->frame[i].data = NULL;
3224 cam->decompressed_frame.width = 0;
3225 cam->decompressed_frame.height = 0;
3226 cam->decompressed_frame.state = FRAME_UNUSED;
3227 cam->decompressed_frame.data = NULL;
3230 struct cam_data *cpia_register_camera(struct cpia_camera_ops *ops, void *lowlevel)
3232 struct cam_data *camera;
3234 /* Need a lock when adding/removing cameras. This doesn't happen
3235 * often and doesn't take very long, so grabbing the kernel lock
3238 if ((camera = kmalloc(sizeof(struct cam_data), GFP_KERNEL)) == NULL) {
3243 init_camera_struct( camera, ops );
3244 camera->lowlevel_data = lowlevel;
3246 /* register v4l device */
3247 if (video_register_device(&camera->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
3250 printk(KERN_DEBUG "video_register_device failed\n");
3254 /* get version information from camera: open/reset/close */
3257 if (camera->ops->open(camera->lowlevel_data))
3260 /* reset the camera */
3261 if (reset_camera(camera) != 0) {
3262 camera->ops->close(camera->lowlevel_data);
3267 camera->ops->close(camera->lowlevel_data);
3269 printk(KERN_INFO " CPiA Version: %d.%02d (%d.%d)\n",
3270 camera->params.version.firmwareVersion,
3271 camera->params.version.firmwareRevision,
3272 camera->params.version.vcVersion,
3273 camera->params.version.vcRevision);
3274 printk(KERN_INFO " CPiA PnP-ID: %04x:%04x:%04x\n",
3275 camera->params.pnpID.vendor,
3276 camera->params.pnpID.product,
3277 camera->params.pnpID.deviceRevision);
3278 printk(KERN_INFO " VP-Version: %d.%d %04x\n",
3279 camera->params.vpVersion.vpVersion,
3280 camera->params.vpVersion.vpRevision,
3281 camera->params.vpVersion.cameraHeadID);
3286 void cpia_unregister_camera(struct cam_data *cam)
3288 if (!cam->open_count) {
3289 DBG("unregistering video\n");
3290 video_unregister_device(&cam->vdev);
3292 LOG("/dev/video%d removed while open, "
3293 "deferring video_unregister_device\n", cam->vdev.minor);
3294 DBG("camera open -- setting ops to NULL\n");
3298 #ifdef CONFIG_PROC_FS
3299 DBG("destroying /proc/cpia/video%d\n", cam->vdev.minor);
3300 destroy_proc_cpia_cam(cam);
3302 if (!cam->open_count) {
3303 DBG("freeing camera\n");
3308 static int __init cpia_init(void)
3310 printk(KERN_INFO "%s v%d.%d.%d\n", ABOUT,
3311 CPIA_MAJ_VER, CPIA_MIN_VER, CPIA_PATCH_VER);
3312 #ifdef CONFIG_PROC_FS
3316 #ifdef CONFIG_VIDEO_CPIA_PP
3320 #ifdef CONFIG_VIDEO_CPIA_PP_MODULE
3321 request_module("cpia_pp");
3324 #ifdef CONFIG_VIDEO_CPIA_USB_MODULE
3325 request_module("cpia_usb");
3327 #endif /* CONFIG_KMOD */
3328 #ifdef CONFIG_VIDEO_CPIA_USB
3334 static void __exit cpia_exit(void)
3336 #ifdef CONFIG_PROC_FS
3337 proc_cpia_destroy();
3341 module_init(cpia_init);
3342 module_exit(cpia_exit);
3344 /* Exported symbols for modules. */
3346 EXPORT_SYMBOL(cpia_register_camera);
3347 EXPORT_SYMBOL(cpia_unregister_camera);