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, jerdfelt@valinux.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@mindspring.com> & Peter Pregler <Peter_Pregler@email.com> & Johannes Erdfelt <jerdfelt@valinux.com>");
60 MODULE_DESCRIPTION("V4L-driver for Vision CPiA based cameras");
61 MODULE_SUPPORTED_DEVICE("video");
64 #define ABOUT "V4L-Driver for Vision CPiA based cameras"
66 #ifndef VID_HARDWARE_CPIA
67 #define VID_HARDWARE_CPIA 24 /* FIXME -> from linux/videodev.h */
70 #define CPIA_MODULE_CPIA (0<<5)
71 #define CPIA_MODULE_SYSTEM (1<<5)
72 #define CPIA_MODULE_VP_CTRL (5<<5)
73 #define CPIA_MODULE_CAPTURE (6<<5)
74 #define CPIA_MODULE_DEBUG (7<<5)
76 #define INPUT (DATA_IN << 8)
77 #define OUTPUT (DATA_OUT << 8)
79 #define CPIA_COMMAND_GetCPIAVersion (INPUT | CPIA_MODULE_CPIA | 1)
80 #define CPIA_COMMAND_GetPnPID (INPUT | CPIA_MODULE_CPIA | 2)
81 #define CPIA_COMMAND_GetCameraStatus (INPUT | CPIA_MODULE_CPIA | 3)
82 #define CPIA_COMMAND_GotoHiPower (OUTPUT | CPIA_MODULE_CPIA | 4)
83 #define CPIA_COMMAND_GotoLoPower (OUTPUT | CPIA_MODULE_CPIA | 5)
84 #define CPIA_COMMAND_GotoSuspend (OUTPUT | CPIA_MODULE_CPIA | 7)
85 #define CPIA_COMMAND_GotoPassThrough (OUTPUT | CPIA_MODULE_CPIA | 8)
86 #define CPIA_COMMAND_ModifyCameraStatus (OUTPUT | CPIA_MODULE_CPIA | 10)
88 #define CPIA_COMMAND_ReadVCRegs (INPUT | CPIA_MODULE_SYSTEM | 1)
89 #define CPIA_COMMAND_WriteVCReg (OUTPUT | CPIA_MODULE_SYSTEM | 2)
90 #define CPIA_COMMAND_ReadMCPorts (INPUT | CPIA_MODULE_SYSTEM | 3)
91 #define CPIA_COMMAND_WriteMCPort (OUTPUT | CPIA_MODULE_SYSTEM | 4)
92 #define CPIA_COMMAND_SetBaudRate (OUTPUT | CPIA_MODULE_SYSTEM | 5)
93 #define CPIA_COMMAND_SetECPTiming (OUTPUT | CPIA_MODULE_SYSTEM | 6)
94 #define CPIA_COMMAND_ReadIDATA (INPUT | CPIA_MODULE_SYSTEM | 7)
95 #define CPIA_COMMAND_WriteIDATA (OUTPUT | CPIA_MODULE_SYSTEM | 8)
96 #define CPIA_COMMAND_GenericCall (OUTPUT | CPIA_MODULE_SYSTEM | 9)
97 #define CPIA_COMMAND_I2CStart (OUTPUT | CPIA_MODULE_SYSTEM | 10)
98 #define CPIA_COMMAND_I2CStop (OUTPUT | CPIA_MODULE_SYSTEM | 11)
99 #define CPIA_COMMAND_I2CWrite (OUTPUT | CPIA_MODULE_SYSTEM | 12)
100 #define CPIA_COMMAND_I2CRead (INPUT | CPIA_MODULE_SYSTEM | 13)
102 #define CPIA_COMMAND_GetVPVersion (INPUT | CPIA_MODULE_VP_CTRL | 1)
103 #define CPIA_COMMAND_SetColourParams (OUTPUT | CPIA_MODULE_VP_CTRL | 3)
104 #define CPIA_COMMAND_SetExposure (OUTPUT | CPIA_MODULE_VP_CTRL | 4)
105 #define CPIA_COMMAND_SetColourBalance (OUTPUT | CPIA_MODULE_VP_CTRL | 6)
106 #define CPIA_COMMAND_SetSensorFPS (OUTPUT | CPIA_MODULE_VP_CTRL | 7)
107 #define CPIA_COMMAND_SetVPDefaults (OUTPUT | CPIA_MODULE_VP_CTRL | 8)
108 #define CPIA_COMMAND_SetApcor (OUTPUT | CPIA_MODULE_VP_CTRL | 9)
109 #define CPIA_COMMAND_SetFlickerCtrl (OUTPUT | CPIA_MODULE_VP_CTRL | 10)
110 #define CPIA_COMMAND_SetVLOffset (OUTPUT | CPIA_MODULE_VP_CTRL | 11)
111 #define CPIA_COMMAND_GetColourParams (INPUT | CPIA_MODULE_VP_CTRL | 16)
112 #define CPIA_COMMAND_GetColourBalance (INPUT | CPIA_MODULE_VP_CTRL | 17)
113 #define CPIA_COMMAND_GetExposure (INPUT | CPIA_MODULE_VP_CTRL | 18)
114 #define CPIA_COMMAND_SetSensorMatrix (OUTPUT | CPIA_MODULE_VP_CTRL | 19)
115 #define CPIA_COMMAND_ColourBars (OUTPUT | CPIA_MODULE_VP_CTRL | 25)
116 #define CPIA_COMMAND_ReadVPRegs (INPUT | CPIA_MODULE_VP_CTRL | 30)
117 #define CPIA_COMMAND_WriteVPReg (OUTPUT | CPIA_MODULE_VP_CTRL | 31)
119 #define CPIA_COMMAND_GrabFrame (OUTPUT | CPIA_MODULE_CAPTURE | 1)
120 #define CPIA_COMMAND_UploadFrame (OUTPUT | CPIA_MODULE_CAPTURE | 2)
121 #define CPIA_COMMAND_SetGrabMode (OUTPUT | CPIA_MODULE_CAPTURE | 3)
122 #define CPIA_COMMAND_InitStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 4)
123 #define CPIA_COMMAND_FiniStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 5)
124 #define CPIA_COMMAND_StartStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 6)
125 #define CPIA_COMMAND_EndStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 7)
126 #define CPIA_COMMAND_SetFormat (OUTPUT | CPIA_MODULE_CAPTURE | 8)
127 #define CPIA_COMMAND_SetROI (OUTPUT | CPIA_MODULE_CAPTURE | 9)
128 #define CPIA_COMMAND_SetCompression (OUTPUT | CPIA_MODULE_CAPTURE | 10)
129 #define CPIA_COMMAND_SetCompressionTarget (OUTPUT | CPIA_MODULE_CAPTURE | 11)
130 #define CPIA_COMMAND_SetYUVThresh (OUTPUT | CPIA_MODULE_CAPTURE | 12)
131 #define CPIA_COMMAND_SetCompressionParams (OUTPUT | CPIA_MODULE_CAPTURE | 13)
132 #define CPIA_COMMAND_DiscardFrame (OUTPUT | CPIA_MODULE_CAPTURE | 14)
134 #define CPIA_COMMAND_OutputRS232 (OUTPUT | CPIA_MODULE_DEBUG | 1)
135 #define CPIA_COMMAND_AbortProcess (OUTPUT | CPIA_MODULE_DEBUG | 4)
136 #define CPIA_COMMAND_SetDramPage (OUTPUT | CPIA_MODULE_DEBUG | 5)
137 #define CPIA_COMMAND_StartDramUpload (OUTPUT | CPIA_MODULE_DEBUG | 6)
138 #define CPIA_COMMAND_StartDummyDtream (OUTPUT | CPIA_MODULE_DEBUG | 8)
139 #define CPIA_COMMAND_AbortStream (OUTPUT | CPIA_MODULE_DEBUG | 9)
140 #define CPIA_COMMAND_DownloadDRAM (OUTPUT | CPIA_MODULE_DEBUG | 10)
143 FRAME_READY, /* Ready to grab into */
144 FRAME_GRABBING, /* In the process of being grabbed into */
145 FRAME_DONE, /* Finished grabbing, but not been synced yet */
146 FRAME_UNUSED, /* Unused (no MCAPTURE) */
149 #define COMMAND_NONE 0x0000
150 #define COMMAND_SETCOMPRESSION 0x0001
151 #define COMMAND_SETCOMPRESSIONTARGET 0x0002
152 #define COMMAND_SETCOLOURPARAMS 0x0004
153 #define COMMAND_SETFORMAT 0x0008
154 #define COMMAND_PAUSE 0x0010
155 #define COMMAND_RESUME 0x0020
156 #define COMMAND_SETYUVTHRESH 0x0040
157 #define COMMAND_SETECPTIMING 0x0080
158 #define COMMAND_SETCOMPRESSIONPARAMS 0x0100
159 #define COMMAND_SETEXPOSURE 0x0200
160 #define COMMAND_SETCOLOURBALANCE 0x0400
161 #define COMMAND_SETSENSORFPS 0x0800
162 #define COMMAND_SETAPCOR 0x1000
163 #define COMMAND_SETFLICKERCTRL 0x2000
164 #define COMMAND_SETVLOFFSET 0x4000
166 /* Developer's Guide Table 5 p 3-34
167 * indexed by [mains][sensorFps.baserate][sensorFps.divisor]*/
168 static u8 flicker_jumps[2][2][4] =
169 { { { 76, 38, 19, 9 }, { 92, 46, 23, 11 } },
170 { { 64, 32, 16, 8 }, { 76, 38, 19, 9} }
173 /* forward declaration of local function */
174 static void reset_camera_struct(struct cam_data *cam);
176 /**********************************************************************
180 * This is a shameless copy from the USB-cpia driver (linux kernel
181 * version 2.3.29 or so, I have no idea what this code actually does ;).
182 * Actually it seems to be a copy of a shameless copy of the bttv-driver.
183 * Or that is a copy of a shameless copy of ... (To the powers: is there
184 * no generic kernel-function to do this sort of stuff?)
186 * Yes, it was a shameless copy from the bttv-driver. IIRC, Alan says
187 * there will be one, but apparentely not yet - jerdfelt
189 **********************************************************************/
191 /* Given PGD from the address space's page table, return the kernel
192 * virtual mapping of the physical memory mapped at ADR.
194 static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr)
196 unsigned long ret = 0UL;
200 if (!pgd_none(*pgd)) {
201 pmd = pmd_offset(pgd, adr);
202 if (!pmd_none(*pmd)) {
203 ptep = pte_offset(pmd, adr);
205 if (pte_present(pte)) {
206 ret = (unsigned long) page_address(pte_page(pte));
207 ret |= (adr & (PAGE_SIZE-1));
214 /* Here we want the physical address of the memory.
215 * This is used when initializing the contents of the
216 * area and marking the pages as reserved.
218 static inline unsigned long kvirt_to_pa(unsigned long adr)
220 unsigned long va, kva, ret;
222 va = VMALLOC_VMADDR(adr);
223 kva = uvirt_to_kva(pgd_offset_k(va), va);
228 static void *rvmalloc(unsigned long size)
231 unsigned long adr, page;
233 /* Round it off to PAGE_SIZE */
234 size += (PAGE_SIZE - 1);
235 size &= ~(PAGE_SIZE - 1);
237 mem = vmalloc_32(size);
241 memset(mem, 0, size); /* Clear the ram out, no junk to the user */
242 adr = (unsigned long) mem;
244 page = kvirt_to_pa(adr);
245 mem_map_reserve(virt_to_page(__va(page)));
247 if (size > PAGE_SIZE)
256 static void rvfree(void *mem, unsigned long size)
258 unsigned long adr, page;
263 size += (PAGE_SIZE - 1);
264 size &= ~(PAGE_SIZE - 1);
266 adr = (unsigned long) mem;
268 page = kvirt_to_pa(adr);
269 mem_map_unreserve(virt_to_page(__va(page)));
271 if (size > PAGE_SIZE)
279 /**********************************************************************
283 **********************************************************************/
284 #ifdef CONFIG_PROC_FS
285 static struct proc_dir_entry *cpia_proc_root=NULL;
287 static int cpia_read_proc(char *page, char **start, off_t off,
288 int count, int *eof, void *data)
292 struct cam_data *cam = data;
295 /* IMPORTANT: This output MUST be kept under PAGE_SIZE
296 * or we need to get more sophisticated. */
298 out += sprintf(out, "read-only\n-----------------------\n");
299 out += sprintf(out, "V4L Driver version: %d.%d.%d\n",
300 CPIA_MAJ_VER, CPIA_MIN_VER, CPIA_PATCH_VER);
301 out += sprintf(out, "CPIA Version: %d.%02d (%d.%d)\n",
302 cam->params.version.firmwareVersion,
303 cam->params.version.firmwareRevision,
304 cam->params.version.vcVersion,
305 cam->params.version.vcRevision);
306 out += sprintf(out, "CPIA PnP-ID: %04x:%04x:%04x\n",
307 cam->params.pnpID.vendor, cam->params.pnpID.product,
308 cam->params.pnpID.deviceRevision);
309 out += sprintf(out, "VP-Version: %d.%d %04x\n",
310 cam->params.vpVersion.vpVersion,
311 cam->params.vpVersion.vpRevision,
312 cam->params.vpVersion.cameraHeadID);
314 out += sprintf(out, "system_state: %#04x\n",
315 cam->params.status.systemState);
316 out += sprintf(out, "grab_state: %#04x\n",
317 cam->params.status.grabState);
318 out += sprintf(out, "stream_state: %#04x\n",
319 cam->params.status.streamState);
320 out += sprintf(out, "fatal_error: %#04x\n",
321 cam->params.status.fatalError);
322 out += sprintf(out, "cmd_error: %#04x\n",
323 cam->params.status.cmdError);
324 out += sprintf(out, "debug_flags: %#04x\n",
325 cam->params.status.debugFlags);
326 out += sprintf(out, "vp_status: %#04x\n",
327 cam->params.status.vpStatus);
328 out += sprintf(out, "error_code: %#04x\n",
329 cam->params.status.errorCode);
330 out += sprintf(out, "video_size: %s\n",
331 cam->params.format.videoSize == VIDEOSIZE_CIF ?
333 out += sprintf(out, "sub_sample: %s\n",
334 cam->params.format.subSample == SUBSAMPLE_420 ?
336 out += sprintf(out, "yuv_order: %s\n",
337 cam->params.format.yuvOrder == YUVORDER_YUYV ?
339 out += sprintf(out, "roi: (%3d, %3d) to (%3d, %3d)\n",
340 cam->params.roi.colStart*8,
341 cam->params.roi.rowStart*4,
342 cam->params.roi.colEnd*8,
343 cam->params.roi.rowEnd*4);
344 out += sprintf(out, "actual_fps: %3d\n", cam->fps);
345 out += sprintf(out, "transfer_rate: %4dkB/s\n",
348 out += sprintf(out, "\nread-write\n");
349 out += sprintf(out, "----------------------- current min"
350 " max default comment\n");
351 out += sprintf(out, "brightness: %8d %8d %8d %8d\n",
352 cam->params.colourParams.brightness, 0, 100, 50);
353 if (cam->params.version.firmwareVersion == 1 &&
354 cam->params.version.firmwareRevision == 2)
355 /* 1-02 firmware limits contrast to 80 */
360 out += sprintf(out, "contrast: %8d %8d %8d %8d"
362 cam->params.colourParams.contrast, 0, tmp, 48);
363 out += sprintf(out, "saturation: %8d %8d %8d %8d\n",
364 cam->params.colourParams.saturation, 0, 100, 50);
365 tmp = (25000+5000*cam->params.sensorFps.baserate)/
366 (1<<cam->params.sensorFps.divisor);
367 out += sprintf(out, "sensor_fps: %4d.%03d %8d %8d %8d\n",
368 tmp/1000, tmp%1000, 3, 30, 15);
369 out += sprintf(out, "stream_start_line: %8d %8d %8d %8d\n",
370 2*cam->params.streamStartLine, 0,
371 cam->params.format.videoSize == VIDEOSIZE_CIF ? 288:144,
372 cam->params.format.videoSize == VIDEOSIZE_CIF ? 240:120);
373 out += sprintf(out, "ecp_timing: %8s %8s %8s %8s\n",
374 cam->params.ecpTiming ? "slow" : "normal", "slow",
377 if (cam->params.colourBalance.balanceModeIsAuto) {
378 sprintf(tmpstr, "auto");
380 sprintf(tmpstr, "manual");
382 out += sprintf(out, "color_balance_mode: %8s %8s %8s"
383 " %8s\n", tmpstr, "manual", "auto", "auto");
384 out += sprintf(out, "red_gain: %8d %8d %8d %8d\n",
385 cam->params.colourBalance.redGain, 0, 212, 32);
386 out += sprintf(out, "green_gain: %8d %8d %8d %8d\n",
387 cam->params.colourBalance.greenGain, 0, 212, 6);
388 out += sprintf(out, "blue_gain: %8d %8d %8d %8d\n",
389 cam->params.colourBalance.blueGain, 0, 212, 92);
391 if (cam->params.version.firmwareVersion == 1 &&
392 cam->params.version.firmwareRevision == 2)
393 /* 1-02 firmware limits gain to 2 */
394 sprintf(tmpstr, "%8d %8d", 1, 2);
396 sprintf(tmpstr, "1,2,4,8");
398 if (cam->params.exposure.gainMode == 0)
399 out += sprintf(out, "max_gain: unknown %18s"
400 " %8d\n", tmpstr, 2);
402 out += sprintf(out, "max_gain: %8d %18s %8d\n",
403 1<<(cam->params.exposure.gainMode-1), tmpstr, 2);
405 switch(cam->params.exposure.expMode) {
408 sprintf(tmpstr, "manual");
411 sprintf(tmpstr, "auto");
414 sprintf(tmpstr, "unknown");
417 out += sprintf(out, "exposure_mode: %8s %8s %8s"
418 " %8s\n", tmpstr, "manual", "auto", "auto");
419 out += sprintf(out, "centre_weight: %8s %8s %8s %8s\n",
420 (2-cam->params.exposure.centreWeight) ? "on" : "off",
422 out += sprintf(out, "gain: %8d %8d max_gain %8d 1,2,4,8 possible\n",
423 1<<cam->params.exposure.gain, 1, 1);
424 if (cam->params.version.firmwareVersion == 1 &&
425 cam->params.version.firmwareRevision == 2)
426 /* 1-02 firmware limits fineExp to 127 */
431 out += sprintf(out, "fine_exp: %8d %8d %8d %8d\n",
432 cam->params.exposure.fineExp*2, 0, tmp, 0);
433 if (cam->params.version.firmwareVersion == 1 &&
434 cam->params.version.firmwareRevision == 2)
435 /* 1-02 firmware limits coarseExpHi to 0 */
440 out += sprintf(out, "coarse_exp: %8d %8d %8d"
441 " %8d\n", cam->params.exposure.coarseExpLo+
442 256*cam->params.exposure.coarseExpHi, 0, tmp, 185);
443 out += sprintf(out, "red_comp: %8d %8d %8d %8d\n",
444 cam->params.exposure.redComp, 220, 255, 220);
445 out += sprintf(out, "green1_comp: %8d %8d %8d %8d\n",
446 cam->params.exposure.green1Comp, 214, 255, 214);
447 out += sprintf(out, "green2_comp: %8d %8d %8d %8d\n",
448 cam->params.exposure.green2Comp, 214, 255, 214);
449 out += sprintf(out, "blue_comp: %8d %8d %8d %8d\n",
450 cam->params.exposure.blueComp, 230, 255, 230);
452 out += sprintf(out, "apcor_gain1: %#8x %#8x %#8x %#8x\n",
453 cam->params.apcor.gain1, 0, 0xff, 0x1c);
454 out += sprintf(out, "apcor_gain2: %#8x %#8x %#8x %#8x\n",
455 cam->params.apcor.gain2, 0, 0xff, 0x1a);
456 out += sprintf(out, "apcor_gain4: %#8x %#8x %#8x %#8x\n",
457 cam->params.apcor.gain4, 0, 0xff, 0x2d);
458 out += sprintf(out, "apcor_gain8: %#8x %#8x %#8x %#8x\n",
459 cam->params.apcor.gain8, 0, 0xff, 0x2a);
460 out += sprintf(out, "vl_offset_gain1: %8d %8d %8d %8d\n",
461 cam->params.vlOffset.gain1, 0, 255, 24);
462 out += sprintf(out, "vl_offset_gain2: %8d %8d %8d %8d\n",
463 cam->params.vlOffset.gain2, 0, 255, 28);
464 out += sprintf(out, "vl_offset_gain4: %8d %8d %8d %8d\n",
465 cam->params.vlOffset.gain4, 0, 255, 30);
466 out += sprintf(out, "vl_offset_gain8: %8d %8d %8d %8d\n",
467 cam->params.vlOffset.gain8, 0, 255, 30);
468 out += sprintf(out, "flicker_control: %8s %8s %8s %8s\n",
469 cam->params.flickerControl.flickerMode ? "on" : "off",
471 out += sprintf(out, "mains_frequency: %8d %8d %8d %8d"
473 cam->mainsFreq ? 60 : 50, 50, 60, 50);
474 out += sprintf(out, "allowable_overexposure: %8d %8d %8d %8d\n",
475 cam->params.flickerControl.allowableOverExposure, 0,
477 out += sprintf(out, "compression_mode: ");
478 switch(cam->params.compression.mode) {
479 case CPIA_COMPRESSION_NONE:
480 out += sprintf(out, "%8s", "none");
482 case CPIA_COMPRESSION_AUTO:
483 out += sprintf(out, "%8s", "auto");
485 case CPIA_COMPRESSION_MANUAL:
486 out += sprintf(out, "%8s", "manual");
489 out += sprintf(out, "%8s", "unknown");
492 out += sprintf(out, " none,auto,manual auto\n");
493 out += sprintf(out, "decimation_enable: %8s %8s %8s %8s\n",
494 cam->params.compression.decimation ==
495 DECIMATION_ENAB ? "on":"off", "off", "off",
497 out += sprintf(out, "compression_target: %9s %9s %9s %9s\n",
498 cam->params.compressionTarget.frTargeting ==
499 CPIA_COMPRESSION_TARGET_FRAMERATE ?
500 "framerate":"quality",
501 "framerate", "quality", "quality");
502 out += sprintf(out, "target_framerate: %8d %8d %8d %8d\n",
503 cam->params.compressionTarget.targetFR, 0, 30, 7);
504 out += sprintf(out, "target_quality: %8d %8d %8d %8d\n",
505 cam->params.compressionTarget.targetQ, 0, 255, 10);
506 out += sprintf(out, "y_threshold: %8d %8d %8d %8d\n",
507 cam->params.yuvThreshold.yThreshold, 0, 31, 15);
508 out += sprintf(out, "uv_threshold: %8d %8d %8d %8d\n",
509 cam->params.yuvThreshold.uvThreshold, 0, 31, 15);
510 out += sprintf(out, "hysteresis: %8d %8d %8d %8d\n",
511 cam->params.compressionParams.hysteresis, 0, 255, 3);
512 out += sprintf(out, "threshold_max: %8d %8d %8d %8d\n",
513 cam->params.compressionParams.threshMax, 0, 255, 11);
514 out += sprintf(out, "small_step: %8d %8d %8d %8d\n",
515 cam->params.compressionParams.smallStep, 0, 255, 1);
516 out += sprintf(out, "large_step: %8d %8d %8d %8d\n",
517 cam->params.compressionParams.largeStep, 0, 255, 3);
518 out += sprintf(out, "decimation_hysteresis: %8d %8d %8d %8d\n",
519 cam->params.compressionParams.decimationHysteresis,
521 out += sprintf(out, "fr_diff_step_thresh: %8d %8d %8d %8d\n",
522 cam->params.compressionParams.frDiffStepThresh,
524 out += sprintf(out, "q_diff_step_thresh: %8d %8d %8d %8d\n",
525 cam->params.compressionParams.qDiffStepThresh,
527 out += sprintf(out, "decimation_thresh_mod: %8d %8d %8d %8d\n",
528 cam->params.compressionParams.decimationThreshMod,
535 if (len <= 0) return 0;
543 static int cpia_write_proc(struct file *file, const char *buffer,
544 unsigned long count, void *data)
548 struct cam_data *cam = data;
549 struct cam_params new_params;
550 int retval, find_colon;
553 u32 command_flags = 0;
556 if (down_interruptible(&cam->param_lock))
560 * Skip over leading whitespace
562 while (count && isspace(*buffer)) {
567 memcpy(&new_params, &cam->params, sizeof(struct cam_params));
568 new_mains = cam->mainsFreq;
572 int _len = strlen(x), _ret, _colon_found; \
573 _ret = (_len <= count && strncmp(buffer, x, _len) == 0); \
579 while (count && (*buffer == ' ' || *buffer == '\t' || \
580 (!_colon_found && *buffer == ':'))) { \
581 if (*buffer == ':') \
586 if (!count || !_colon_found) \
593 #define FIRMWARE_VERSION(x,y) (new_params.version.firmwareVersion == (x) && \
594 new_params.version.firmwareRevision == (y))
598 unsigned long int _ret; \
599 _ret = simple_strtoul(buffer, &_p, 0); \
603 count -= _p - buffer; \
610 while (count && !retval) {
612 if (MATCH("brightness")) {
618 new_params.colourParams.brightness = val;
622 command_flags |= COMMAND_SETCOLOURPARAMS;
623 } else if (MATCH("contrast")) {
629 /* contrast is in steps of 8, so round*/
630 val = ((val + 3) / 8) * 8;
631 /* 1-02 firmware limits contrast to 80*/
632 if (FIRMWARE_VERSION(1,2) && val > 80)
635 new_params.colourParams.contrast = val;
639 command_flags |= COMMAND_SETCOLOURPARAMS;
640 } else if (MATCH("saturation")) {
646 new_params.colourParams.saturation = val;
650 command_flags |= COMMAND_SETCOLOURPARAMS;
651 } else if (MATCH("sensor_fps")) {
656 /* find values so that sensorFPS is minimized,
661 new_params.sensorFps.divisor = 0;
662 new_params.sensorFps.baserate = 1;
663 } else if (val > 15) {
664 new_params.sensorFps.divisor = 0;
665 new_params.sensorFps.baserate = 0;
666 } else if (val > 12) {
667 new_params.sensorFps.divisor = 1;
668 new_params.sensorFps.baserate = 1;
669 } else if (val > 7) {
670 new_params.sensorFps.divisor = 1;
671 new_params.sensorFps.baserate = 0;
672 } else if (val > 6) {
673 new_params.sensorFps.divisor = 2;
674 new_params.sensorFps.baserate = 1;
675 } else if (val > 3) {
676 new_params.sensorFps.divisor = 2;
677 new_params.sensorFps.baserate = 0;
679 new_params.sensorFps.divisor = 3;
680 /* Either base rate would work here */
681 new_params.sensorFps.baserate = 1;
683 new_params.flickerControl.coarseJump =
684 flicker_jumps[new_mains]
685 [new_params.sensorFps.baserate]
686 [new_params.sensorFps.divisor];
687 if (new_params.flickerControl.flickerMode)
688 command_flags |= COMMAND_SETFLICKERCTRL;
690 command_flags |= COMMAND_SETSENSORFPS;
691 } else if (MATCH("stream_start_line")) {
698 if (new_params.format.videoSize == VIDEOSIZE_QCIF)
701 new_params.streamStartLine = val/2;
705 } else if (MATCH("ecp_timing")) {
706 if (!retval && MATCH("normal"))
707 new_params.ecpTiming = 0;
708 else if (!retval && MATCH("slow"))
709 new_params.ecpTiming = 1;
713 command_flags |= COMMAND_SETECPTIMING;
714 } else if (MATCH("color_balance_mode")) {
715 if (!retval && MATCH("manual"))
716 new_params.colourBalance.balanceModeIsAuto = 0;
717 else if (!retval && MATCH("auto"))
718 new_params.colourBalance.balanceModeIsAuto = 1;
722 command_flags |= COMMAND_SETCOLOURBALANCE;
723 } else if (MATCH("red_gain")) {
729 new_params.colourBalance.redGain = val;
733 command_flags |= COMMAND_SETCOLOURBALANCE;
734 } else if (MATCH("green_gain")) {
740 new_params.colourBalance.greenGain = val;
744 command_flags |= COMMAND_SETCOLOURBALANCE;
745 } else if (MATCH("blue_gain")) {
751 new_params.colourBalance.blueGain = val;
755 command_flags |= COMMAND_SETCOLOURBALANCE;
756 } else if (MATCH("max_gain")) {
761 /* 1-02 firmware limits gain to 2 */
762 if (FIRMWARE_VERSION(1,2) && val > 2)
766 new_params.exposure.gainMode = 1;
769 new_params.exposure.gainMode = 2;
772 new_params.exposure.gainMode = 3;
775 new_params.exposure.gainMode = 4;
782 command_flags |= COMMAND_SETEXPOSURE;
783 } else if (MATCH("exposure_mode")) {
784 if (!retval && MATCH("auto"))
785 new_params.exposure.expMode = 2;
786 else if (!retval && MATCH("manual")) {
787 if (new_params.exposure.expMode == 2)
788 new_params.exposure.expMode = 3;
789 new_params.flickerControl.flickerMode = 0;
790 command_flags |= COMMAND_SETFLICKERCTRL;
794 command_flags |= COMMAND_SETEXPOSURE;
795 } else if (MATCH("centre_weight")) {
796 if (!retval && MATCH("on"))
797 new_params.exposure.centreWeight = 1;
798 else if (!retval && MATCH("off"))
799 new_params.exposure.centreWeight = 2;
803 command_flags |= COMMAND_SETEXPOSURE;
804 } else if (MATCH("gain")) {
811 new_params.exposure.gain = 0;
812 new_params.exposure.expMode = 1;
813 new_params.flickerControl.flickerMode = 0;
814 command_flags |= COMMAND_SETFLICKERCTRL;
817 new_params.exposure.gain = 1;
818 new_params.exposure.expMode = 1;
819 new_params.flickerControl.flickerMode = 0;
820 command_flags |= COMMAND_SETFLICKERCTRL;
823 new_params.exposure.gain = 2;
824 new_params.exposure.expMode = 1;
825 new_params.flickerControl.flickerMode = 0;
826 command_flags |= COMMAND_SETFLICKERCTRL;
829 new_params.exposure.gain = 3;
830 new_params.exposure.expMode = 1;
831 new_params.flickerControl.flickerMode = 0;
832 command_flags |= COMMAND_SETFLICKERCTRL;
838 command_flags |= COMMAND_SETEXPOSURE;
839 if (new_params.exposure.gain >
840 new_params.exposure.gainMode-1)
843 } else if (MATCH("fine_exp")) {
849 /* 1-02 firmware limits fineExp to 127*/
850 if (FIRMWARE_VERSION(1,2) && val > 127)
852 new_params.exposure.fineExp = val;
853 new_params.exposure.expMode = 1;
854 command_flags |= COMMAND_SETEXPOSURE;
855 new_params.flickerControl.flickerMode = 0;
856 command_flags |= COMMAND_SETFLICKERCTRL;
860 } else if (MATCH("coarse_exp")) {
866 /* 1-02 firmware limits
867 * coarseExp to 255 */
868 if (FIRMWARE_VERSION(1,2) && val > 255)
870 new_params.exposure.coarseExpLo =
872 new_params.exposure.coarseExpHi =
874 new_params.exposure.expMode = 1;
875 command_flags |= COMMAND_SETEXPOSURE;
876 new_params.flickerControl.flickerMode = 0;
877 command_flags |= COMMAND_SETFLICKERCTRL;
881 } else if (MATCH("red_comp")) {
886 if (val >= 220 && val <= 255) {
887 new_params.exposure.redComp = val;
888 command_flags |= COMMAND_SETEXPOSURE;
892 } else if (MATCH("green1_comp")) {
897 if (val >= 214 && val <= 255) {
898 new_params.exposure.green1Comp = val;
899 command_flags |= COMMAND_SETEXPOSURE;
903 } else if (MATCH("green2_comp")) {
908 if (val >= 214 && val <= 255) {
909 new_params.exposure.green2Comp = val;
910 command_flags |= COMMAND_SETEXPOSURE;
914 } else if (MATCH("blue_comp")) {
919 if (val >= 230 && val <= 255) {
920 new_params.exposure.blueComp = val;
921 command_flags |= COMMAND_SETEXPOSURE;
925 } else if (MATCH("apcor_gain1")) {
930 command_flags |= COMMAND_SETAPCOR;
932 new_params.apcor.gain1 = val;
936 } else if (MATCH("apcor_gain2")) {
941 command_flags |= COMMAND_SETAPCOR;
943 new_params.apcor.gain2 = val;
947 } else if (MATCH("apcor_gain4")) {
952 command_flags |= COMMAND_SETAPCOR;
954 new_params.apcor.gain4 = val;
958 } else if (MATCH("apcor_gain8")) {
963 command_flags |= COMMAND_SETAPCOR;
965 new_params.apcor.gain8 = val;
969 } else if (MATCH("vl_offset_gain1")) {
975 new_params.vlOffset.gain1 = val;
979 command_flags |= COMMAND_SETVLOFFSET;
980 } else if (MATCH("vl_offset_gain2")) {
986 new_params.vlOffset.gain2 = val;
990 command_flags |= COMMAND_SETVLOFFSET;
991 } else if (MATCH("vl_offset_gain4")) {
997 new_params.vlOffset.gain4 = val;
1001 command_flags |= COMMAND_SETVLOFFSET;
1002 } else if (MATCH("vl_offset_gain8")) {
1008 new_params.vlOffset.gain8 = val;
1012 command_flags |= COMMAND_SETVLOFFSET;
1013 } else if (MATCH("flicker_control")) {
1014 if (!retval && MATCH("on")) {
1015 new_params.flickerControl.flickerMode = 1;
1016 new_params.exposure.expMode = 2;
1017 command_flags |= COMMAND_SETEXPOSURE;
1018 } else if (!retval && MATCH("off"))
1019 new_params.flickerControl.flickerMode = 0;
1023 command_flags |= COMMAND_SETFLICKERCTRL;
1024 } else if (MATCH("mains_frequency")) {
1025 if (!retval && MATCH("50")) {
1027 new_params.flickerControl.coarseJump =
1028 flicker_jumps[new_mains]
1029 [new_params.sensorFps.baserate]
1030 [new_params.sensorFps.divisor];
1031 if (new_params.flickerControl.flickerMode)
1032 command_flags |= COMMAND_SETFLICKERCTRL;
1033 } else if (!retval && MATCH("60")) {
1035 new_params.flickerControl.coarseJump =
1036 flicker_jumps[new_mains]
1037 [new_params.sensorFps.baserate]
1038 [new_params.sensorFps.divisor];
1039 if (new_params.flickerControl.flickerMode)
1040 command_flags |= COMMAND_SETFLICKERCTRL;
1043 } else if (MATCH("allowable_overexposure")) {
1049 new_params.flickerControl.
1050 allowableOverExposure = val;
1051 command_flags |= COMMAND_SETFLICKERCTRL;
1055 } else if (MATCH("compression_mode")) {
1056 if (!retval && MATCH("none"))
1057 new_params.compression.mode =
1058 CPIA_COMPRESSION_NONE;
1059 else if (!retval && MATCH("auto"))
1060 new_params.compression.mode =
1061 CPIA_COMPRESSION_AUTO;
1062 else if (!retval && MATCH("manual"))
1063 new_params.compression.mode =
1064 CPIA_COMPRESSION_MANUAL;
1068 command_flags |= COMMAND_SETCOMPRESSION;
1069 } else if (MATCH("decimation_enable")) {
1070 if (!retval && MATCH("off"))
1071 new_params.compression.decimation = 0;
1075 command_flags |= COMMAND_SETCOMPRESSION;
1076 } else if (MATCH("compression_target")) {
1077 if (!retval && MATCH("quality"))
1078 new_params.compressionTarget.frTargeting =
1079 CPIA_COMPRESSION_TARGET_QUALITY;
1080 else if (!retval && MATCH("framerate"))
1081 new_params.compressionTarget.frTargeting =
1082 CPIA_COMPRESSION_TARGET_FRAMERATE;
1086 command_flags |= COMMAND_SETCOMPRESSIONTARGET;
1087 } else if (MATCH("target_framerate")) {
1092 new_params.compressionTarget.targetFR = val;
1093 command_flags |= COMMAND_SETCOMPRESSIONTARGET;
1094 } else if (MATCH("target_quality")) {
1099 new_params.compressionTarget.targetQ = val;
1101 command_flags |= COMMAND_SETCOMPRESSIONTARGET;
1102 } else if (MATCH("y_threshold")) {
1108 new_params.yuvThreshold.yThreshold = val;
1112 command_flags |= COMMAND_SETYUVTHRESH;
1113 } else if (MATCH("uv_threshold")) {
1119 new_params.yuvThreshold.uvThreshold = val;
1123 command_flags |= COMMAND_SETYUVTHRESH;
1124 } else if (MATCH("hysteresis")) {
1130 new_params.compressionParams.hysteresis = val;
1134 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1135 } else if (MATCH("threshold_max")) {
1141 new_params.compressionParams.threshMax = val;
1145 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1146 } else if (MATCH("small_step")) {
1152 new_params.compressionParams.smallStep = val;
1156 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1157 } else if (MATCH("large_step")) {
1163 new_params.compressionParams.largeStep = val;
1167 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1168 } else if (MATCH("decimation_hysteresis")) {
1174 new_params.compressionParams.decimationHysteresis = val;
1178 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1179 } else if (MATCH("fr_diff_step_thresh")) {
1185 new_params.compressionParams.frDiffStepThresh = val;
1189 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1190 } else if (MATCH("q_diff_step_thresh")) {
1196 new_params.compressionParams.qDiffStepThresh = val;
1200 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1201 } else if (MATCH("decimation_thresh_mod")) {
1207 new_params.compressionParams.decimationThreshMod = val;
1211 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1213 DBG("No match found\n");
1218 while (count && isspace(*buffer) && *buffer != '\n') {
1223 if (*buffer != '\n' && *buffer != ';')
1233 #undef FIRMWARE_VERSION
1238 if (command_flags & COMMAND_SETCOLOURPARAMS) {
1239 /* Adjust cam->vp to reflect these changes */
1240 cam->vp.brightness =
1241 new_params.colourParams.brightness*65535/100;
1243 new_params.colourParams.contrast*65535/100;
1245 new_params.colourParams.saturation*65535/100;
1248 memcpy(&cam->params, &new_params, sizeof(struct cam_params));
1249 cam->mainsFreq = new_mains;
1250 cam->cmd_queue |= command_flags;
1253 DBG("error: %d\n", retval);
1255 up(&cam->param_lock);
1261 static void create_proc_cpia_cam(struct cam_data *cam)
1264 struct proc_dir_entry *ent;
1266 if (!cpia_proc_root || !cam)
1269 sprintf(name, "video%d", cam->vdev.minor);
1271 ent = create_proc_entry(name, S_IFREG|S_IRUGO|S_IWUSR, cpia_proc_root);
1276 ent->read_proc = cpia_read_proc;
1277 ent->write_proc = cpia_write_proc;
1279 cam->proc_entry = ent;
1282 static void destroy_proc_cpia_cam(struct cam_data *cam)
1286 if (!cam || !cam->proc_entry)
1289 sprintf(name, "video%d", cam->vdev.minor);
1290 remove_proc_entry(name, cpia_proc_root);
1291 cam->proc_entry = NULL;
1294 static void proc_cpia_create(void)
1296 cpia_proc_root = create_proc_entry("cpia", S_IFDIR, 0);
1299 cpia_proc_root->owner = THIS_MODULE;
1301 LOG("Unable to initialise /proc/cpia\n");
1304 static void proc_cpia_destroy(void)
1306 remove_proc_entry("cpia", 0);
1308 #endif /* CONFIG_PROC_FS */
1310 /* ----------------------- debug functions ---------------------- */
1312 #define printstatus(cam) \
1313 DBG("%02x %02x %02x %02x %02x %02x %02x %02x\n",\
1314 cam->params.status.systemState, cam->params.status.grabState, \
1315 cam->params.status.streamState, cam->params.status.fatalError, \
1316 cam->params.status.cmdError, cam->params.status.debugFlags, \
1317 cam->params.status.vpStatus, cam->params.status.errorCode);
1319 /* ----------------------- v4l helpers -------------------------- */
1321 /* supported frame palettes and depths */
1322 static inline int valid_mode(u16 palette, u16 depth)
1324 return (palette == VIDEO_PALETTE_GREY && depth == 8) ||
1325 (palette == VIDEO_PALETTE_RGB555 && depth == 16) ||
1326 (palette == VIDEO_PALETTE_RGB565 && depth == 16) ||
1327 (palette == VIDEO_PALETTE_RGB24 && depth == 24) ||
1328 (palette == VIDEO_PALETTE_RGB32 && depth == 32) ||
1329 (palette == VIDEO_PALETTE_YUV422 && depth == 16) ||
1330 (palette == VIDEO_PALETTE_YUYV && depth == 16) ||
1331 (palette == VIDEO_PALETTE_UYVY && depth == 16);
1334 static int match_videosize( int width, int height )
1336 /* return the best match, where 'best' is as always
1337 * the largest that is not bigger than what is requested. */
1338 if (width>=352 && height>=288)
1339 return VIDEOSIZE_352_288; /* CIF */
1341 if (width>=320 && height>=240)
1342 return VIDEOSIZE_320_240; /* SIF */
1344 if (width>=288 && height>=216)
1345 return VIDEOSIZE_288_216;
1347 if (width>=256 && height>=192)
1348 return VIDEOSIZE_256_192;
1350 if (width>=224 && height>=168)
1351 return VIDEOSIZE_224_168;
1353 if (width>=192 && height>=144)
1354 return VIDEOSIZE_192_144;
1356 if (width>=176 && height>=144)
1357 return VIDEOSIZE_176_144; /* QCIF */
1359 if (width>=160 && height>=120)
1360 return VIDEOSIZE_160_120; /* QSIF */
1362 if (width>=128 && height>=96)
1363 return VIDEOSIZE_128_96;
1365 if (width>=88 && height>=72)
1366 return VIDEOSIZE_88_72;
1368 if (width>=64 && height>=48)
1369 return VIDEOSIZE_64_48;
1371 if (width>=48 && height>=48)
1372 return VIDEOSIZE_48_48;
1377 /* these are the capture sizes we support */
1378 static void set_vw_size(struct cam_data *cam)
1380 /* the col/row/start/end values are the result of simple math */
1381 /* study the SetROI-command in cpia developers guide p 2-22 */
1382 /* streamStartLine is set to the recommended value in the cpia */
1383 /* developers guide p 3-37 */
1384 switch(cam->video_size) {
1386 cam->vw.width = 352;
1387 cam->vw.height = 288;
1388 cam->params.format.videoSize=VIDEOSIZE_CIF;
1389 cam->params.roi.colStart=0;
1390 cam->params.roi.colEnd=44;
1391 cam->params.roi.rowStart=0;
1392 cam->params.roi.rowEnd=72;
1393 cam->params.streamStartLine = 120;
1396 cam->vw.width = 320;
1397 cam->vw.height = 240;
1398 cam->params.format.videoSize=VIDEOSIZE_CIF;
1399 cam->params.roi.colStart=2;
1400 cam->params.roi.colEnd=42;
1401 cam->params.roi.rowStart=6;
1402 cam->params.roi.rowEnd=66;
1403 cam->params.streamStartLine = 120;
1405 case VIDEOSIZE_288_216:
1406 cam->vw.width = 288;
1407 cam->vw.height = 216;
1408 cam->params.format.videoSize=VIDEOSIZE_CIF;
1409 cam->params.roi.colStart=4;
1410 cam->params.roi.colEnd=40;
1411 cam->params.roi.rowStart=9;
1412 cam->params.roi.rowEnd=63;
1413 cam->params.streamStartLine = 120;
1415 case VIDEOSIZE_256_192:
1416 cam->vw.width = 256;
1417 cam->vw.height = 192;
1418 cam->params.format.videoSize=VIDEOSIZE_CIF;
1419 cam->params.roi.colStart=6;
1420 cam->params.roi.colEnd=38;
1421 cam->params.roi.rowStart=12;
1422 cam->params.roi.rowEnd=60;
1423 cam->params.streamStartLine = 120;
1425 case VIDEOSIZE_224_168:
1426 cam->vw.width = 224;
1427 cam->vw.height = 168;
1428 cam->params.format.videoSize=VIDEOSIZE_CIF;
1429 cam->params.roi.colStart=8;
1430 cam->params.roi.colEnd=36;
1431 cam->params.roi.rowStart=15;
1432 cam->params.roi.rowEnd=57;
1433 cam->params.streamStartLine = 120;
1435 case VIDEOSIZE_192_144:
1436 cam->vw.width = 192;
1437 cam->vw.height = 144;
1438 cam->params.format.videoSize=VIDEOSIZE_CIF;
1439 cam->params.roi.colStart=10;
1440 cam->params.roi.colEnd=34;
1441 cam->params.roi.rowStart=18;
1442 cam->params.roi.rowEnd=54;
1443 cam->params.streamStartLine = 120;
1445 case VIDEOSIZE_QCIF:
1446 cam->vw.width = 176;
1447 cam->vw.height = 144;
1448 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1449 cam->params.roi.colStart=0;
1450 cam->params.roi.colEnd=22;
1451 cam->params.roi.rowStart=0;
1452 cam->params.roi.rowEnd=36;
1453 cam->params.streamStartLine = 60;
1455 case VIDEOSIZE_QSIF:
1456 cam->vw.width = 160;
1457 cam->vw.height = 120;
1458 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1459 cam->params.roi.colStart=1;
1460 cam->params.roi.colEnd=21;
1461 cam->params.roi.rowStart=3;
1462 cam->params.roi.rowEnd=33;
1463 cam->params.streamStartLine = 60;
1465 case VIDEOSIZE_128_96:
1466 cam->vw.width = 128;
1467 cam->vw.height = 96;
1468 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1469 cam->params.roi.colStart=3;
1470 cam->params.roi.colEnd=19;
1471 cam->params.roi.rowStart=6;
1472 cam->params.roi.rowEnd=30;
1473 cam->params.streamStartLine = 60;
1475 case VIDEOSIZE_88_72:
1477 cam->vw.height = 72;
1478 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1479 cam->params.roi.colStart=5;
1480 cam->params.roi.colEnd=16;
1481 cam->params.roi.rowStart=9;
1482 cam->params.roi.rowEnd=27;
1483 cam->params.streamStartLine = 60;
1485 case VIDEOSIZE_64_48:
1487 cam->vw.height = 48;
1488 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1489 cam->params.roi.colStart=7;
1490 cam->params.roi.colEnd=15;
1491 cam->params.roi.rowStart=12;
1492 cam->params.roi.rowEnd=24;
1493 cam->params.streamStartLine = 60;
1495 case VIDEOSIZE_48_48:
1497 cam->vw.height = 48;
1498 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1499 cam->params.roi.colStart=8;
1500 cam->params.roi.colEnd=14;
1501 cam->params.roi.rowStart=6;
1502 cam->params.roi.rowEnd=30;
1503 cam->params.streamStartLine = 60;
1506 LOG("bad videosize value: %d\n", cam->video_size);
1512 static int allocate_frame_buf(struct cam_data *cam)
1516 cam->frame_buf = rvmalloc(FRAME_NUM * CPIA_MAX_FRAME_SIZE);
1517 if (!cam->frame_buf)
1520 for (i = 0; i < FRAME_NUM; i++)
1521 cam->frame[i].data = cam->frame_buf + i * CPIA_MAX_FRAME_SIZE;
1526 static int free_frame_buf(struct cam_data *cam)
1530 rvfree(cam->frame_buf, FRAME_NUM*CPIA_MAX_FRAME_SIZE);
1532 for (i=0; i < FRAME_NUM; i++)
1533 cam->frame[i].data = NULL;
1539 static void inline free_frames(struct cpia_frame frame[FRAME_NUM])
1543 for (i=0; i < FRAME_NUM; i++)
1544 frame[i].state = FRAME_UNUSED;
1548 /**********************************************************************
1552 **********************************************************************/
1553 /* send an arbitrary command to the camera */
1554 static int do_command(struct cam_data *cam, u16 command, u8 a, u8 b, u8 c, u8 d)
1556 int retval, datasize;
1560 case CPIA_COMMAND_GetCPIAVersion:
1561 case CPIA_COMMAND_GetPnPID:
1562 case CPIA_COMMAND_GetCameraStatus:
1563 case CPIA_COMMAND_GetVPVersion:
1566 case CPIA_COMMAND_GetColourParams:
1567 case CPIA_COMMAND_GetColourBalance:
1568 case CPIA_COMMAND_GetExposure:
1569 down(&cam->param_lock);
1577 cmd[0] = command>>8;
1578 cmd[1] = command&0xff;
1586 retval = cam->ops->transferCmd(cam->lowlevel_data, cmd, data);
1588 DBG("%x - failed, retval=%d\n", command, retval);
1589 if (command == CPIA_COMMAND_GetColourParams ||
1590 command == CPIA_COMMAND_GetColourBalance ||
1591 command == CPIA_COMMAND_GetExposure)
1592 up(&cam->param_lock);
1595 case CPIA_COMMAND_GetCPIAVersion:
1596 cam->params.version.firmwareVersion = data[0];
1597 cam->params.version.firmwareRevision = data[1];
1598 cam->params.version.vcVersion = data[2];
1599 cam->params.version.vcRevision = data[3];
1601 case CPIA_COMMAND_GetPnPID:
1602 cam->params.pnpID.vendor = data[0]+(((u16)data[1])<<8);
1603 cam->params.pnpID.product = data[2]+(((u16)data[3])<<8);
1604 cam->params.pnpID.deviceRevision =
1605 data[4]+(((u16)data[5])<<8);
1607 case CPIA_COMMAND_GetCameraStatus:
1608 cam->params.status.systemState = data[0];
1609 cam->params.status.grabState = data[1];
1610 cam->params.status.streamState = data[2];
1611 cam->params.status.fatalError = data[3];
1612 cam->params.status.cmdError = data[4];
1613 cam->params.status.debugFlags = data[5];
1614 cam->params.status.vpStatus = data[6];
1615 cam->params.status.errorCode = data[7];
1617 case CPIA_COMMAND_GetVPVersion:
1618 cam->params.vpVersion.vpVersion = data[0];
1619 cam->params.vpVersion.vpRevision = data[1];
1620 cam->params.vpVersion.cameraHeadID =
1621 data[2]+(((u16)data[3])<<8);
1623 case CPIA_COMMAND_GetColourParams:
1624 cam->params.colourParams.brightness = data[0];
1625 cam->params.colourParams.contrast = data[1];
1626 cam->params.colourParams.saturation = data[2];
1627 up(&cam->param_lock);
1629 case CPIA_COMMAND_GetColourBalance:
1630 cam->params.colourBalance.redGain = data[0];
1631 cam->params.colourBalance.greenGain = data[1];
1632 cam->params.colourBalance.blueGain = data[2];
1633 up(&cam->param_lock);
1635 case CPIA_COMMAND_GetExposure:
1636 cam->params.exposure.gain = data[0];
1637 cam->params.exposure.fineExp = data[1];
1638 cam->params.exposure.coarseExpLo = data[2];
1639 cam->params.exposure.coarseExpHi = data[3];
1640 cam->params.exposure.redComp = data[4];
1641 cam->params.exposure.green1Comp = data[5];
1642 cam->params.exposure.green2Comp = data[6];
1643 cam->params.exposure.blueComp = data[7];
1644 /* If the *Comp parameters are wacko, generate
1645 * a warning, and reset them back to default
1646 * values. - rich@annexia.org
1648 if (cam->params.exposure.redComp < 220 ||
1649 cam->params.exposure.redComp > 255 ||
1650 cam->params.exposure.green1Comp < 214 ||
1651 cam->params.exposure.green1Comp > 255 ||
1652 cam->params.exposure.green2Comp < 214 ||
1653 cam->params.exposure.green2Comp > 255 ||
1654 cam->params.exposure.blueComp < 230 ||
1655 cam->params.exposure.blueComp > 255)
1657 printk (KERN_WARNING "*_comp parameters have gone AWOL (%d/%d/%d/%d) - reseting them\n",
1658 cam->params.exposure.redComp,
1659 cam->params.exposure.green1Comp,
1660 cam->params.exposure.green2Comp,
1661 cam->params.exposure.blueComp);
1662 cam->params.exposure.redComp = 220;
1663 cam->params.exposure.green1Comp = 214;
1664 cam->params.exposure.green2Comp = 214;
1665 cam->params.exposure.blueComp = 230;
1667 up(&cam->param_lock);
1676 /* send a command to the camera with an additional data transaction */
1677 static int do_command_extended(struct cam_data *cam, u16 command,
1678 u8 a, u8 b, u8 c, u8 d,
1679 u8 e, u8 f, u8 g, u8 h,
1680 u8 i, u8 j, u8 k, u8 l)
1685 cmd[0] = command>>8;
1686 cmd[1] = command&0xff;
1702 retval = cam->ops->transferCmd(cam->lowlevel_data, cmd, data);
1704 LOG("%x - failed\n", command);
1709 /**********************************************************************
1711 * Colorspace conversion
1713 **********************************************************************/
1714 #define LIMIT(x) ((((x)>0xffffff)?0xff0000:(((x)<=0xffff)?0:(x)&0xff0000))>>16)
1716 static int yuvconvert(unsigned char *yuv, unsigned char *rgb, int out_fmt,
1717 int in_uyvy, int mmap_kludge)
1719 int y, u, v, r, g, b, y1;
1722 case VIDEO_PALETTE_RGB555:
1723 case VIDEO_PALETTE_RGB565:
1724 case VIDEO_PALETTE_RGB24:
1725 case VIDEO_PALETTE_RGB32:
1728 y = (*yuv++ - 16) * 76310;
1730 y1 = (*yuv - 16) * 76310;
1732 y = (*yuv++ - 16) * 76310;
1734 y1 = (*yuv++ - 16) * 76310;
1738 g = -25690 * u + -53294 * v;
1746 /* Just to avoid compiler warnings */
1753 case VIDEO_PALETTE_RGB555:
1754 *rgb++ = ((LIMIT(g+y) & 0xf8) << 2) | (LIMIT(b+y) >> 3);
1755 *rgb++ = ((LIMIT(r+y) & 0xf8) >> 1) | (LIMIT(g+y) >> 6);
1756 *rgb++ = ((LIMIT(g+y1) & 0xf8) << 2) | (LIMIT(b+y1) >> 3);
1757 *rgb = ((LIMIT(r+y1) & 0xf8) >> 1) | (LIMIT(g+y1) >> 6);
1759 case VIDEO_PALETTE_RGB565:
1760 *rgb++ = ((LIMIT(g+y) & 0xfc) << 3) | (LIMIT(b+y) >> 3);
1761 *rgb++ = (LIMIT(r+y) & 0xf8) | (LIMIT(g+y) >> 5);
1762 *rgb++ = ((LIMIT(g+y1) & 0xfc) << 3) | (LIMIT(b+y1) >> 3);
1763 *rgb = (LIMIT(r+y1) & 0xf8) | (LIMIT(g+y1) >> 5);
1765 case VIDEO_PALETTE_RGB24:
1767 *rgb++ = LIMIT(b+y);
1768 *rgb++ = LIMIT(g+y);
1769 *rgb++ = LIMIT(r+y);
1770 *rgb++ = LIMIT(b+y1);
1771 *rgb++ = LIMIT(g+y1);
1774 *rgb++ = LIMIT(r+y);
1775 *rgb++ = LIMIT(g+y);
1776 *rgb++ = LIMIT(b+y);
1777 *rgb++ = LIMIT(r+y1);
1778 *rgb++ = LIMIT(g+y1);
1782 case VIDEO_PALETTE_RGB32:
1784 *rgb++ = LIMIT(b+y);
1785 *rgb++ = LIMIT(g+y);
1786 *rgb++ = LIMIT(r+y);
1788 *rgb++ = LIMIT(b+y1);
1789 *rgb++ = LIMIT(g+y1);
1792 *rgb++ = LIMIT(r+y);
1793 *rgb++ = LIMIT(g+y);
1794 *rgb++ = LIMIT(b+y);
1796 *rgb++ = LIMIT(r+y1);
1797 *rgb++ = LIMIT(g+y1);
1801 case VIDEO_PALETTE_GREY:
1805 case VIDEO_PALETTE_YUV422:
1806 case VIDEO_PALETTE_YUYV:
1812 case VIDEO_PALETTE_UYVY:
1819 DBG("Empty: %d\n", out_fmt);
1824 static int skipcount(int count, int fmt)
1827 case VIDEO_PALETTE_GREY:
1828 case VIDEO_PALETTE_RGB555:
1829 case VIDEO_PALETTE_RGB565:
1830 case VIDEO_PALETTE_YUV422:
1831 case VIDEO_PALETTE_YUYV:
1832 case VIDEO_PALETTE_UYVY:
1834 case VIDEO_PALETTE_RGB24:
1836 case VIDEO_PALETTE_RGB32:
1843 static int parse_picture(struct cam_data *cam, int size)
1845 u8 *obuf, *ibuf, *end_obuf;
1846 int ll, in_uyvy, compressed, origsize, out_fmt;
1848 /* make sure params don't change while we are decoding */
1849 down(&cam->param_lock);
1851 obuf = cam->decompressed_frame.data;
1852 end_obuf = obuf+CPIA_MAX_FRAME_SIZE;
1853 ibuf = cam->raw_image;
1855 out_fmt = cam->vp.palette;
1857 if ((ibuf[0] != MAGIC_0) || (ibuf[1] != MAGIC_1)) {
1858 LOG("header not found\n");
1859 up(&cam->param_lock);
1863 if ((ibuf[16] != VIDEOSIZE_QCIF) && (ibuf[16] != VIDEOSIZE_CIF)) {
1864 LOG("wrong video size\n");
1865 up(&cam->param_lock);
1869 if (ibuf[17] != SUBSAMPLE_422) {
1870 LOG("illegal subtype %d\n",ibuf[17]);
1871 up(&cam->param_lock);
1875 if (ibuf[18] != YUVORDER_YUYV && ibuf[18] != YUVORDER_UYVY) {
1876 LOG("illegal yuvorder %d\n",ibuf[18]);
1877 up(&cam->param_lock);
1880 in_uyvy = ibuf[18] == YUVORDER_UYVY;
1883 /* FIXME: ROI mismatch occurs when switching capture sizes */
1884 if ((ibuf[24] != cam->params.roi.colStart) ||
1885 (ibuf[25] != cam->params.roi.colEnd) ||
1886 (ibuf[26] != cam->params.roi.rowStart) ||
1887 (ibuf[27] != cam->params.roi.rowEnd)) {
1888 LOG("ROI mismatch\n");
1889 up(&cam->param_lock);
1894 if ((ibuf[28] != NOT_COMPRESSED) && (ibuf[28] != COMPRESSED)) {
1895 LOG("illegal compression %d\n",ibuf[28]);
1896 up(&cam->param_lock);
1899 compressed = (ibuf[28] == COMPRESSED);
1901 if (ibuf[29] != NO_DECIMATION) {
1902 LOG("decimation not supported\n");
1903 up(&cam->param_lock);
1907 cam->params.yuvThreshold.yThreshold = ibuf[30];
1908 cam->params.yuvThreshold.uvThreshold = ibuf[31];
1909 cam->params.status.systemState = ibuf[32];
1910 cam->params.status.grabState = ibuf[33];
1911 cam->params.status.streamState = ibuf[34];
1912 cam->params.status.fatalError = ibuf[35];
1913 cam->params.status.cmdError = ibuf[36];
1914 cam->params.status.debugFlags = ibuf[37];
1915 cam->params.status.vpStatus = ibuf[38];
1916 cam->params.status.errorCode = ibuf[39];
1917 cam->fps = ibuf[41];
1918 up(&cam->param_lock);
1920 ibuf += FRAME_HEADER_SIZE;
1921 size -= FRAME_HEADER_SIZE;
1922 ll = ibuf[0] | (ibuf[1] << 8);
1928 LOG("Insufficient data in buffer\n");
1933 if (!compressed || (compressed && !(*ibuf & 1))) {
1934 obuf += yuvconvert(ibuf, obuf, out_fmt,
1935 in_uyvy, cam->mmap_kludge);
1939 /*skip compressed interval from previous frame*/
1940 int skipsize = skipcount(*ibuf >> 1, out_fmt);
1942 if (obuf > end_obuf) {
1943 LOG("Insufficient data in buffer\n");
1952 LOG("EOL not found giving up after %d/%d"
1953 " bytes\n", origsize-size, origsize);
1957 ibuf++; /* skip over EOL */
1959 if ((size > 3) && (ibuf[0] == EOI) && (ibuf[1] == EOI) &&
1960 (ibuf[2] == EOI) && (ibuf[3] == EOI)) {
1966 ll = ibuf[0] | (ibuf[1] << 8);
1967 ibuf += 2; /* skip over line length */
1970 LOG("line length was not 1 but %d after %d/%d bytes\n",
1971 ll, origsize-size, origsize);
1976 cam->decompressed_frame.count = obuf-cam->decompressed_frame.data;
1978 return cam->decompressed_frame.count;
1981 /* InitStreamCap wrapper to select correct start line */
1982 static inline int init_stream_cap(struct cam_data *cam)
1984 return do_command(cam, CPIA_COMMAND_InitStreamCap,
1985 0, cam->params.streamStartLine, 0, 0);
1988 /* update various camera modes and settings */
1989 static void dispatch_commands(struct cam_data *cam)
1991 down(&cam->param_lock);
1992 if (cam->cmd_queue==COMMAND_NONE) {
1993 up(&cam->param_lock);
1996 DEB_BYTE(cam->cmd_queue);
1997 DEB_BYTE(cam->cmd_queue>>8);
1998 if (cam->cmd_queue & COMMAND_SETCOLOURPARAMS)
1999 do_command(cam, CPIA_COMMAND_SetColourParams,
2000 cam->params.colourParams.brightness,
2001 cam->params.colourParams.contrast,
2002 cam->params.colourParams.saturation, 0);
2004 if (cam->cmd_queue & COMMAND_SETCOMPRESSION)
2005 do_command(cam, CPIA_COMMAND_SetCompression,
2006 cam->params.compression.mode,
2007 cam->params.compression.decimation, 0, 0);
2009 if (cam->cmd_queue & COMMAND_SETFORMAT) {
2010 do_command(cam, CPIA_COMMAND_SetFormat,
2011 cam->params.format.videoSize,
2012 cam->params.format.subSample,
2013 cam->params.format.yuvOrder, 0);
2014 do_command(cam, CPIA_COMMAND_SetROI,
2015 cam->params.roi.colStart, cam->params.roi.colEnd,
2016 cam->params.roi.rowStart, cam->params.roi.rowEnd);
2017 cam->first_frame = 1;
2020 if (cam->cmd_queue & COMMAND_SETCOMPRESSIONTARGET)
2021 do_command(cam, CPIA_COMMAND_SetCompressionTarget,
2022 cam->params.compressionTarget.frTargeting,
2023 cam->params.compressionTarget.targetFR,
2024 cam->params.compressionTarget.targetQ, 0);
2026 if (cam->cmd_queue & COMMAND_SETYUVTHRESH)
2027 do_command(cam, CPIA_COMMAND_SetYUVThresh,
2028 cam->params.yuvThreshold.yThreshold,
2029 cam->params.yuvThreshold.uvThreshold, 0, 0);
2031 if (cam->cmd_queue & COMMAND_SETECPTIMING)
2032 do_command(cam, CPIA_COMMAND_SetECPTiming,
2033 cam->params.ecpTiming, 0, 0, 0);
2035 if (cam->cmd_queue & COMMAND_SETCOMPRESSIONPARAMS)
2036 do_command_extended(cam, CPIA_COMMAND_SetCompressionParams,
2038 cam->params.compressionParams.hysteresis,
2039 cam->params.compressionParams.threshMax,
2040 cam->params.compressionParams.smallStep,
2041 cam->params.compressionParams.largeStep,
2042 cam->params.compressionParams.decimationHysteresis,
2043 cam->params.compressionParams.frDiffStepThresh,
2044 cam->params.compressionParams.qDiffStepThresh,
2045 cam->params.compressionParams.decimationThreshMod);
2047 if (cam->cmd_queue & COMMAND_SETEXPOSURE)
2048 do_command_extended(cam, CPIA_COMMAND_SetExposure,
2049 cam->params.exposure.gainMode,
2050 cam->params.exposure.expMode,
2051 cam->params.exposure.compMode,
2052 cam->params.exposure.centreWeight,
2053 cam->params.exposure.gain,
2054 cam->params.exposure.fineExp,
2055 cam->params.exposure.coarseExpLo,
2056 cam->params.exposure.coarseExpHi,
2057 cam->params.exposure.redComp,
2058 cam->params.exposure.green1Comp,
2059 cam->params.exposure.green2Comp,
2060 cam->params.exposure.blueComp);
2062 if (cam->cmd_queue & COMMAND_SETCOLOURBALANCE) {
2063 if (cam->params.colourBalance.balanceModeIsAuto) {
2064 do_command(cam, CPIA_COMMAND_SetColourBalance,
2067 do_command(cam, CPIA_COMMAND_SetColourBalance,
2069 cam->params.colourBalance.redGain,
2070 cam->params.colourBalance.greenGain,
2071 cam->params.colourBalance.blueGain);
2072 do_command(cam, CPIA_COMMAND_SetColourBalance,
2077 if (cam->cmd_queue & COMMAND_SETSENSORFPS)
2078 do_command(cam, CPIA_COMMAND_SetSensorFPS,
2079 cam->params.sensorFps.divisor,
2080 cam->params.sensorFps.baserate, 0, 0);
2082 if (cam->cmd_queue & COMMAND_SETAPCOR)
2083 do_command(cam, CPIA_COMMAND_SetApcor,
2084 cam->params.apcor.gain1,
2085 cam->params.apcor.gain2,
2086 cam->params.apcor.gain4,
2087 cam->params.apcor.gain8);
2089 if (cam->cmd_queue & COMMAND_SETFLICKERCTRL)
2090 do_command(cam, CPIA_COMMAND_SetFlickerCtrl,
2091 cam->params.flickerControl.flickerMode,
2092 cam->params.flickerControl.coarseJump,
2093 cam->params.flickerControl.allowableOverExposure, 0);
2095 if (cam->cmd_queue & COMMAND_SETVLOFFSET)
2096 do_command(cam, CPIA_COMMAND_SetVLOffset,
2097 cam->params.vlOffset.gain1,
2098 cam->params.vlOffset.gain2,
2099 cam->params.vlOffset.gain4,
2100 cam->params.vlOffset.gain8);
2102 if (cam->cmd_queue & COMMAND_PAUSE)
2103 do_command(cam, CPIA_COMMAND_EndStreamCap, 0, 0, 0, 0);
2105 if (cam->cmd_queue & COMMAND_RESUME)
2106 init_stream_cap(cam);
2108 up(&cam->param_lock);
2109 cam->cmd_queue = COMMAND_NONE;
2113 /* kernel thread function to read image from camera */
2114 static void fetch_frame(void *data)
2116 int image_size, retry;
2117 struct cam_data *cam = (struct cam_data *)data;
2118 unsigned long oldjif, rate, diff;
2120 /* Allow up to two bad images in a row to be read and
2121 * ignored before an error is reported */
2122 for (retry = 0; retry < 3; ++retry) {
2124 DBG("retry=%d\n", retry);
2129 /* load first frame always uncompressed */
2130 if (cam->first_frame &&
2131 cam->params.compression.mode != CPIA_COMPRESSION_NONE)
2132 do_command(cam, CPIA_COMMAND_SetCompression,
2133 CPIA_COMPRESSION_NONE,
2134 NO_DECIMATION, 0, 0);
2136 /* init camera upload */
2137 if (do_command(cam, CPIA_COMMAND_SetGrabMode,
2138 CPIA_GRAB_CONTINUOUS, 0, 0, 0))
2141 if (do_command(cam, CPIA_COMMAND_GrabFrame, 0,
2142 cam->params.streamStartLine, 0, 0))
2145 if (cam->ops->wait_for_stream_ready) {
2146 /* loop until image ready */
2147 do_command(cam, CPIA_COMMAND_GetCameraStatus,0,0,0,0);
2148 while (cam->params.status.streamState != STREAM_READY) {
2149 if (current->need_resched)
2152 current->state = TASK_INTERRUPTIBLE;
2154 /* sleep for 10 ms, hopefully ;) */
2155 schedule_timeout(10*HZ/1000);
2156 if (signal_pending(current))
2159 do_command(cam, CPIA_COMMAND_GetCameraStatus,
2164 /* grab image from camera */
2165 if (current->need_resched)
2169 image_size = cam->ops->streamRead(cam->lowlevel_data,
2171 if (image_size <= 0) {
2172 DBG("streamRead failed: %d\n", image_size);
2176 rate = image_size * HZ / 1024;
2177 diff = jiffies-oldjif;
2178 cam->transfer_rate = diff==0 ? rate : rate/diff;
2179 /* diff==0 ? unlikely but possible */
2181 /* camera idle now so dispatch queued commands */
2182 dispatch_commands(cam);
2184 /* Update our knowledge of the camera state - FIXME: necessary? */
2185 do_command(cam, CPIA_COMMAND_GetColourBalance, 0, 0, 0, 0);
2186 do_command(cam, CPIA_COMMAND_GetExposure, 0, 0, 0, 0);
2188 /* decompress and convert image to by copying it from
2189 * raw_image to decompressed_frame
2191 if (current->need_resched)
2194 cam->image_size = parse_picture(cam, image_size);
2195 if (cam->image_size <= 0)
2196 DBG("parse_picture failed %d\n", cam->image_size);
2202 /* FIXME: this only works for double buffering */
2203 if (cam->frame[cam->curframe].state == FRAME_READY) {
2204 memcpy(cam->frame[cam->curframe].data,
2205 cam->decompressed_frame.data,
2206 cam->decompressed_frame.count);
2207 cam->frame[cam->curframe].state = FRAME_DONE;
2209 cam->decompressed_frame.state = FRAME_DONE;
2212 if (cam->first_frame &&
2213 cam->params.compression.mode != CPIA_COMPRESSION_NONE) {
2214 cam->first_frame = 0;
2215 cam->cmd_queue |= COMMAND_SETCOMPRESSION;
2218 if (cam->first_frame) {
2219 cam->first_frame = 0;
2220 cam->cmd_queue |= COMMAND_SETCOMPRESSION;
2221 cam->cmd_queue |= COMMAND_SETEXPOSURE;
2227 static int capture_frame(struct cam_data *cam, struct video_mmap *vm)
2231 if (!cam->frame_buf) {
2232 /* we do lazy allocation */
2233 if ((retval = allocate_frame_buf(cam)))
2237 /* FIXME: the first frame seems to be captured by the camera
2238 without regards to any initial settings, so we throw away
2239 that one, the next one is generated with our settings
2240 (exposure, color balance, ...)
2242 if (cam->first_frame) {
2243 cam->curframe = vm->frame;
2244 cam->frame[cam->curframe].state = FRAME_READY;
2246 if (cam->frame[cam->curframe].state != FRAME_DONE)
2249 cam->curframe = vm->frame;
2250 cam->frame[cam->curframe].state = FRAME_READY;
2252 if (cam->frame[cam->curframe].state != FRAME_DONE)
2258 static int goto_high_power(struct cam_data *cam)
2260 if (do_command(cam, CPIA_COMMAND_GotoHiPower, 0, 0, 0, 0))
2262 mdelay(100); /* windows driver does it too */
2263 if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0))
2265 if (cam->params.status.systemState == HI_POWER_STATE) {
2266 DBG("camera now in HIGH power state\n");
2273 static int goto_low_power(struct cam_data *cam)
2275 if (do_command(cam, CPIA_COMMAND_GotoLoPower, 0, 0, 0, 0))
2277 if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0))
2279 if (cam->params.status.systemState == LO_POWER_STATE) {
2280 DBG("camera now in LOW power state\n");
2287 static void save_camera_state(struct cam_data *cam)
2289 do_command(cam, CPIA_COMMAND_GetColourBalance, 0, 0, 0, 0);
2290 do_command(cam, CPIA_COMMAND_GetExposure, 0, 0, 0, 0);
2292 DBG("%d/%d/%d/%d/%d/%d/%d/%d\n",
2293 cam->params.exposure.gain,
2294 cam->params.exposure.fineExp,
2295 cam->params.exposure.coarseExpLo,
2296 cam->params.exposure.coarseExpHi,
2297 cam->params.exposure.redComp,
2298 cam->params.exposure.green1Comp,
2299 cam->params.exposure.green2Comp,
2300 cam->params.exposure.blueComp);
2302 cam->params.colourBalance.redGain,
2303 cam->params.colourBalance.greenGain,
2304 cam->params.colourBalance.blueGain);
2307 static void set_camera_state(struct cam_data *cam)
2309 if(cam->params.colourBalance.balanceModeIsAuto) {
2310 do_command(cam, CPIA_COMMAND_SetColourBalance,
2313 do_command(cam, CPIA_COMMAND_SetColourBalance,
2315 cam->params.colourBalance.redGain,
2316 cam->params.colourBalance.greenGain,
2317 cam->params.colourBalance.blueGain);
2318 do_command(cam, CPIA_COMMAND_SetColourBalance,
2323 do_command_extended(cam, CPIA_COMMAND_SetExposure,
2324 cam->params.exposure.gainMode, 1, 1,
2325 cam->params.exposure.centreWeight,
2326 cam->params.exposure.gain,
2327 cam->params.exposure.fineExp,
2328 cam->params.exposure.coarseExpLo,
2329 cam->params.exposure.coarseExpHi,
2330 cam->params.exposure.redComp,
2331 cam->params.exposure.green1Comp,
2332 cam->params.exposure.green2Comp,
2333 cam->params.exposure.blueComp);
2334 do_command_extended(cam, CPIA_COMMAND_SetExposure,
2336 0, 0, 0, 0, 0, 0, 0, 0);
2338 if (!cam->params.exposure.gainMode)
2339 cam->params.exposure.gainMode = 2;
2340 if (!cam->params.exposure.expMode)
2341 cam->params.exposure.expMode = 2;
2342 if (!cam->params.exposure.centreWeight)
2343 cam->params.exposure.centreWeight = 1;
2345 cam->cmd_queue = COMMAND_SETCOMPRESSION |
2346 COMMAND_SETCOMPRESSIONTARGET |
2347 COMMAND_SETCOLOURPARAMS |
2349 COMMAND_SETYUVTHRESH |
2350 COMMAND_SETECPTIMING |
2351 COMMAND_SETCOMPRESSIONPARAMS |
2353 COMMAND_SETEXPOSURE |
2355 COMMAND_SETCOLOURBALANCE |
2356 COMMAND_SETSENSORFPS |
2358 COMMAND_SETFLICKERCTRL |
2359 COMMAND_SETVLOFFSET;
2360 dispatch_commands(cam);
2361 save_camera_state(cam);
2366 static void get_version_information(struct cam_data *cam)
2368 /* GetCPIAVersion */
2369 do_command(cam, CPIA_COMMAND_GetCPIAVersion, 0, 0, 0, 0);
2372 do_command(cam, CPIA_COMMAND_GetPnPID, 0, 0, 0, 0);
2375 /* initialize camera */
2376 static int reset_camera(struct cam_data *cam)
2378 /* Start the camera in low power mode */
2379 if (goto_low_power(cam)) {
2380 if (cam->params.status.systemState != WARM_BOOT_STATE)
2383 /* FIXME: this is just dirty trial and error */
2384 reset_camera_struct(cam);
2385 goto_high_power(cam);
2386 do_command(cam, CPIA_COMMAND_DiscardFrame, 0, 0, 0, 0);
2387 if (goto_low_power(cam))
2391 /* procedure described in developer's guide p3-28 */
2393 /* Check the firmware version FIXME: should we check PNPID? */
2394 cam->params.version.firmwareVersion = 0;
2395 get_version_information(cam);
2396 if (cam->params.version.firmwareVersion != 1)
2399 /* The fatal error checking should be done after
2400 * the camera powers up (developer's guide p 3-38) */
2402 /* Set streamState before transition to high power to avoid bug
2403 * in firmware 1-02 */
2404 do_command(cam, CPIA_COMMAND_ModifyCameraStatus, STREAMSTATE, 0,
2405 STREAM_NOT_READY, 0);
2408 if (goto_high_power(cam))
2411 /* Check the camera status */
2412 if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0))
2415 if (cam->params.status.fatalError) {
2416 DBG("fatal_error: %#04x\n",
2417 cam->params.status.fatalError);
2418 DBG("vp_status: %#04x\n",
2419 cam->params.status.vpStatus);
2420 if (cam->params.status.fatalError & ~(COM_FLAG|CPIA_FLAG)) {
2421 /* Fatal error in camera */
2423 } else if (cam->params.status.fatalError & (COM_FLAG|CPIA_FLAG)) {
2424 /* Firmware 1-02 may do this for parallel port cameras,
2425 * just clear the flags (developer's guide p 3-38) */
2426 do_command(cam, CPIA_COMMAND_ModifyCameraStatus,
2427 FATALERROR, ~(COM_FLAG|CPIA_FLAG), 0, 0);
2431 /* Check the camera status again */
2432 if (cam->params.status.fatalError) {
2433 if (cam->params.status.fatalError)
2437 /* VPVersion can't be retrieved before the camera is in HiPower,
2438 * so get it here instead of in get_version_information. */
2439 do_command(cam, CPIA_COMMAND_GetVPVersion, 0, 0, 0, 0);
2441 /* set camera to a known state */
2442 set_camera_state(cam);
2447 /* ------------------------- V4L interface --------------------- */
2448 static int cpia_open(struct video_device *dev, int flags)
2451 struct cam_data *cam = dev->priv;
2454 DBG("Internal error, cam_data not found!\n");
2458 if (cam->open_count > 0) {
2459 DBG("Camera already open\n");
2463 if (!cam->raw_image) {
2464 cam->raw_image = rvmalloc(CPIA_MAX_IMAGE_SIZE);
2465 if (!cam->raw_image)
2469 if (!cam->decompressed_frame.data) {
2470 cam->decompressed_frame.data = rvmalloc(CPIA_MAX_FRAME_SIZE);
2471 if (!cam->decompressed_frame.data) {
2472 rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
2473 cam->raw_image = NULL;
2479 if (cam->ops->open(cam->lowlevel_data)) {
2480 rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE);
2481 cam->decompressed_frame.data = NULL;
2482 rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
2483 cam->raw_image = NULL;
2487 /* reset the camera */
2488 if ((i = reset_camera(cam)) != 0) {
2489 cam->ops->close(cam->lowlevel_data);
2490 rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE);
2491 cam->decompressed_frame.data = NULL;
2492 rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
2493 cam->raw_image = NULL;
2497 /* Set ownership of /proc/cpia/videoX to current user */
2499 cam->proc_entry->uid = current->uid;
2501 /* set mark for loading first frame uncompressed */
2502 cam->first_frame = 1;
2504 /* init it to something */
2505 cam->mmap_kludge = 0;
2511 static void cpia_close(struct video_device *dev)
2513 struct cam_data *cam;
2518 /* Return ownership of /proc/cpia/videoX to root */
2520 cam->proc_entry->uid = 0;
2522 /* save camera state for later open (developers guide ch 3.5.3) */
2523 save_camera_state(cam);
2526 goto_low_power(cam);
2528 /* Update the camera ststus */
2529 do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0);
2531 /* cleanup internal state stuff */
2532 free_frames(cam->frame);
2535 cam->ops->close(cam->lowlevel_data);
2538 if (--cam->open_count == 0) {
2539 /* clean up capture-buffers */
2540 if (cam->raw_image) {
2541 rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
2542 cam->raw_image = NULL;
2545 if (cam->decompressed_frame.data) {
2546 rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE);
2547 cam->decompressed_frame.data = NULL;
2551 free_frame_buf(cam);
2554 video_unregister_device(dev);
2563 static long cpia_read(struct video_device *dev, char *buf,
2564 unsigned long count, int noblock)
2566 struct cam_data *cam = dev->priv;
2568 /* make this _really_ smp and multithredi-safe */
2569 if (down_interruptible(&cam->busy_lock))
2574 up(&cam->busy_lock);
2580 up(&cam->busy_lock);
2586 up(&cam->busy_lock);
2591 cam->decompressed_frame.state = FRAME_READY;
2594 if (cam->decompressed_frame.state != FRAME_DONE) {
2595 DBG("upload failed %d/%d\n", cam->decompressed_frame.count,
2596 cam->decompressed_frame.state);
2597 up(&cam->busy_lock);
2600 cam->decompressed_frame.state = FRAME_UNUSED;
2602 /* copy data to user space */
2603 if (cam->decompressed_frame.count > count) {
2604 DBG("count wrong: %d, %lu\n", cam->decompressed_frame.count,
2606 up(&cam->busy_lock);
2609 if (copy_to_user(buf, cam->decompressed_frame.data,
2610 cam->decompressed_frame.count)) {
2611 DBG("copy_to_user failed\n");
2612 up(&cam->busy_lock);
2616 up(&cam->busy_lock);
2617 return cam->decompressed_frame.count;
2620 static int cpia_ioctl(struct video_device *dev, unsigned int ioctlnr, void *arg)
2622 struct cam_data *cam = dev->priv;
2625 if (!cam || !cam->ops)
2628 /* make this _really_ smp-safe */
2629 if (down_interruptible(&cam->busy_lock))
2632 //DBG("cpia_ioctl: %u\n", ioctlnr);
2635 /* query capabilites */
2638 struct video_capability b;
2640 DBG("VIDIOCGCAP\n");
2641 strcpy(b.name, "CPiA Camera");
2642 b.type = VID_TYPE_CAPTURE;
2645 b.maxwidth = 352; /* VIDEOSIZE_CIF */
2647 b.minwidth = 48; /* VIDEOSIZE_48_48 */
2650 if (copy_to_user(arg, &b, sizeof(b)))
2656 /* get/set video source - we are a camera and nothing else */
2659 struct video_channel v;
2661 DBG("VIDIOCGCHAN\n");
2662 if (copy_from_user(&v, arg, sizeof(v))) {
2666 if (v.channel != 0) {
2672 strcpy(v.name, "Camera");
2675 v.type = VIDEO_TYPE_CAMERA;
2678 if (copy_to_user(arg, &v, sizeof(v)))
2687 DBG("VIDIOCSCHAN\n");
2688 if (copy_from_user(&v, arg, sizeof(v)))
2691 if (retval == 0 && v != 0)
2697 /* image properties */
2699 DBG("VIDIOCGPICT\n");
2700 if (copy_to_user(arg, &cam->vp, sizeof(struct video_picture)))
2706 struct video_picture vp;
2708 DBG("VIDIOCSPICT\n");
2710 /* copy_from_user */
2711 if (copy_from_user(&vp, arg, sizeof(vp))) {
2716 /* check validity */
2717 DBG("palette: %d\n", vp.palette);
2718 DBG("depth: %d\n", vp.depth);
2719 if (!valid_mode(vp.palette, vp.depth)) {
2724 down(&cam->param_lock);
2725 /* brightness, colour, contrast need no check 0-65535 */
2726 memcpy( &cam->vp, &vp, sizeof(vp) );
2727 /* update cam->params.colourParams */
2728 cam->params.colourParams.brightness = vp.brightness*100/65535;
2729 cam->params.colourParams.contrast = vp.contrast*100/65535;
2730 cam->params.colourParams.saturation = vp.colour*100/65535;
2731 /* contrast is in steps of 8, so round */
2732 cam->params.colourParams.contrast =
2733 ((cam->params.colourParams.contrast + 3) / 8) * 8;
2734 if (cam->params.version.firmwareVersion == 1 &&
2735 cam->params.version.firmwareRevision == 2 &&
2736 cam->params.colourParams.contrast > 80) {
2737 /* 1-02 firmware limits contrast to 80 */
2738 cam->params.colourParams.contrast = 80;
2741 /* queue command to update camera */
2742 cam->cmd_queue |= COMMAND_SETCOLOURPARAMS;
2743 up(&cam->param_lock);
2744 DBG("VIDIOCSPICT: %d / %d // %d / %d / %d / %d\n",
2745 vp.depth, vp.palette, vp.brightness, vp.hue, vp.colour,
2750 /* get/set capture window */
2752 DBG("VIDIOCGWIN\n");
2754 if (copy_to_user(arg, &cam->vw, sizeof(struct video_window)))
2760 /* copy_from_user, check validity, copy to internal structure */
2761 struct video_window vw;
2762 DBG("VIDIOCSWIN\n");
2763 if (copy_from_user(&vw, arg, sizeof(vw))) {
2768 if (vw.clipcount != 0) { /* clipping not supported */
2772 if (vw.clips != NULL) { /* clipping not supported */
2777 /* we set the video window to something smaller or equal to what
2778 * is requested by the user???
2780 down(&cam->param_lock);
2781 if (vw.width != cam->vw.width || vw.height != cam->vw.height) {
2782 int video_size = match_videosize(vw.width, vw.height);
2784 if (video_size < 0) {
2786 up(&cam->param_lock);
2789 cam->video_size = video_size;
2791 DBG("%d / %d\n", cam->vw.width, cam->vw.height);
2792 cam->cmd_queue |= COMMAND_SETFORMAT;
2795 // FIXME needed??? memcpy(&cam->vw, &vw, sizeof(vw));
2796 up(&cam->param_lock);
2798 /* setformat ignored by camera during streaming,
2799 * so stop/dispatch/start */
2800 if (cam->cmd_queue & COMMAND_SETFORMAT) {
2802 dispatch_commands(cam);
2804 DBG("%d/%d:%d\n", cam->video_size,
2805 cam->vw.width, cam->vw.height);
2809 /* mmap interface */
2812 struct video_mbuf vm;
2815 DBG("VIDIOCGMBUF\n");
2816 memset(&vm, 0, sizeof(vm));
2817 vm.size = CPIA_MAX_FRAME_SIZE*FRAME_NUM;
2818 vm.frames = FRAME_NUM;
2819 for (i = 0; i < FRAME_NUM; i++)
2820 vm.offsets[i] = CPIA_MAX_FRAME_SIZE * i;
2822 if (copy_to_user((void *)arg, (void *)&vm, sizeof(vm)))
2828 case VIDIOCMCAPTURE:
2830 struct video_mmap vm;
2833 if (copy_from_user((void *)&vm, (void *)arg, sizeof(vm))) {
2838 DBG("VIDIOCMCAPTURE: %d / %d / %dx%d\n", vm.format, vm.frame,
2839 vm.width, vm.height);
2841 if (vm.frame<0||vm.frame>=FRAME_NUM) {
2846 /* set video format */
2847 cam->vp.palette = vm.format;
2849 case VIDEO_PALETTE_GREY:
2850 case VIDEO_PALETTE_RGB555:
2851 case VIDEO_PALETTE_RGB565:
2852 case VIDEO_PALETTE_YUV422:
2853 case VIDEO_PALETTE_YUYV:
2854 case VIDEO_PALETTE_UYVY:
2857 case VIDEO_PALETTE_RGB24:
2860 case VIDEO_PALETTE_RGB32:
2870 /* set video size */
2871 video_size = match_videosize(vm.width, vm.height);
2872 if (cam->video_size < 0) {
2876 if (video_size != cam->video_size) {
2877 cam->video_size = video_size;
2879 cam->cmd_queue |= COMMAND_SETFORMAT;
2880 dispatch_commands(cam);
2883 DBG("VIDIOCMCAPTURE: %d / %d/%d\n", cam->video_size,
2884 cam->vw.width, cam->vw.height);
2886 /* according to v4l-spec we must start streaming here */
2887 cam->mmap_kludge = 1;
2888 retval = capture_frame(cam, &vm);
2897 if (copy_from_user((void *)&frame, arg, sizeof(int))) {
2901 //DBG("VIDIOCSYNC: %d\n", frame);
2903 if (frame<0 || frame >= FRAME_NUM) {
2908 switch (cam->frame[frame].state) {
2911 case FRAME_GRABBING:
2912 DBG("sync to unused frame %d\n", frame);
2917 cam->frame[frame].state = FRAME_UNUSED;
2918 //DBG("VIDIOCSYNC: %d synced\n", frame);
2921 if (retval == -EINTR) {
2922 /* FIXME - xawtv does not handle this nice */
2928 /* pointless to implement overlay with this camera */
2942 /* tuner interface - we have none */
2956 /* audio interface - we have none */
2964 retval = -ENOIOCTLCMD;
2968 up(&cam->param_lock);
2969 up(&cam->busy_lock);
2974 static int cpia_mmap(struct video_device *dev, const char *adr,
2977 unsigned long start = (unsigned long)adr;
2978 unsigned long page, pos;
2979 struct cam_data *cam = dev->priv;
2982 if (!cam || !cam->ops)
2985 DBG("cpia_mmap: %ld\n", size);
2987 if (size > FRAME_NUM*CPIA_MAX_FRAME_SIZE)
2990 if (!cam || !cam->ops)
2993 /* make this _really_ smp-safe */
2994 if (down_interruptible(&cam->busy_lock))
2997 if (!cam->frame_buf) { /* we do lazy allocation */
2998 if ((retval = allocate_frame_buf(cam))) {
2999 up(&cam->busy_lock);
3004 pos = (unsigned long)(cam->frame_buf);
3006 page = kvirt_to_pa(pos);
3007 if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) {
3008 up(&cam->busy_lock);
3013 if (size > PAGE_SIZE)
3019 DBG("cpia_mmap: %ld\n", size);
3020 up(&cam->busy_lock);
3025 int cpia_video_init(struct video_device *vdev)
3027 #ifdef CONFIG_PROC_FS
3028 create_proc_cpia_cam(vdev->priv);
3033 static struct video_device cpia_template = {
3035 name: "CPiA Camera",
3036 type: VID_TYPE_CAPTURE,
3037 hardware: VID_HARDWARE_CPIA, /* FIXME */
3043 initialize: cpia_video_init,
3047 /* initialise cam_data structure */
3048 static void reset_camera_struct(struct cam_data *cam)
3050 /* The following parameter values are the defaults from
3051 * "Software Developer's Guide for CPiA Cameras". Any changes
3052 * to the defaults are noted in comments. */
3053 cam->params.colourParams.brightness = 50;
3054 cam->params.colourParams.contrast = 48;
3055 cam->params.colourParams.saturation = 50;
3056 cam->params.exposure.gainMode = 2;
3057 cam->params.exposure.expMode = 2; /* AEC */
3058 cam->params.exposure.compMode = 1;
3059 cam->params.exposure.centreWeight = 1;
3060 cam->params.exposure.gain = 0;
3061 cam->params.exposure.fineExp = 0;
3062 cam->params.exposure.coarseExpLo = 185;
3063 cam->params.exposure.coarseExpHi = 0;
3064 cam->params.exposure.redComp = 220;
3065 cam->params.exposure.green1Comp = 214;
3066 cam->params.exposure.green2Comp = 214;
3067 cam->params.exposure.blueComp = 230;
3068 cam->params.colourBalance.balanceModeIsAuto = 1;
3069 cam->params.colourBalance.redGain = 32;
3070 cam->params.colourBalance.greenGain = 6;
3071 cam->params.colourBalance.blueGain = 92;
3072 cam->params.apcor.gain1 = 0x1c;
3073 cam->params.apcor.gain2 = 0x1a;
3074 cam->params.apcor.gain4 = 0x2d;
3075 cam->params.apcor.gain8 = 0x2a;
3076 cam->params.flickerControl.flickerMode = 0;
3077 cam->params.flickerControl.coarseJump =
3078 flicker_jumps[cam->mainsFreq]
3079 [cam->params.sensorFps.baserate]
3080 [cam->params.sensorFps.divisor];
3081 cam->params.vlOffset.gain1 = 24;
3082 cam->params.vlOffset.gain2 = 28;
3083 cam->params.vlOffset.gain4 = 30;
3084 cam->params.vlOffset.gain8 = 30;
3085 cam->params.compressionParams.hysteresis = 3;
3086 cam->params.compressionParams.threshMax = 11;
3087 cam->params.compressionParams.smallStep = 1;
3088 cam->params.compressionParams.largeStep = 3;
3089 cam->params.compressionParams.decimationHysteresis = 2;
3090 cam->params.compressionParams.frDiffStepThresh = 5;
3091 cam->params.compressionParams.qDiffStepThresh = 3;
3092 cam->params.compressionParams.decimationThreshMod = 2;
3093 /* End of default values from Software Developer's Guide */
3095 cam->transfer_rate = 0;
3097 /* Set Sensor FPS to 15fps. This seems better than 30fps
3098 * for indoor lighting. */
3099 cam->params.sensorFps.divisor = 1;
3100 cam->params.sensorFps.baserate = 1;
3102 cam->params.yuvThreshold.yThreshold = 15; /* FIXME? */
3103 cam->params.yuvThreshold.uvThreshold = 15; /* FIXME? */
3105 cam->params.format.subSample = SUBSAMPLE_422;
3106 cam->params.format.yuvOrder = YUVORDER_YUYV;
3108 cam->params.compression.mode = CPIA_COMPRESSION_AUTO;
3109 cam->params.compressionTarget.frTargeting =
3110 CPIA_COMPRESSION_TARGET_QUALITY;
3111 cam->params.compressionTarget.targetFR = 7; /* FIXME? */
3112 cam->params.compressionTarget.targetQ = 10; /* FIXME? */
3114 cam->video_size = VIDEOSIZE_CIF;
3116 cam->vp.colour = 32768; /* 50% */
3117 cam->vp.hue = 32768; /* 50% */
3118 cam->vp.brightness = 32768; /* 50% */
3119 cam->vp.contrast = 32768; /* 50% */
3120 cam->vp.whiteness = 0; /* not used -> grayscale only */
3121 cam->vp.depth = 0; /* FIXME: to be set by user? */
3122 cam->vp.palette = VIDEO_PALETTE_RGB24; /* FIXME: to be set by user? */
3127 cam->vw.chromakey = 0;
3128 /* PP NOTE: my extension to use vw.flags for this, bear it! */
3130 cam->vw.clipcount = 0;
3131 cam->vw.clips = NULL;
3133 cam->cmd_queue = COMMAND_NONE;
3134 cam->first_frame = 0;
3139 /* initialize cam_data structure */
3140 static void init_camera_struct(struct cam_data *cam,
3141 struct cpia_camera_ops *ops )
3145 /* Default everything to 0 */
3146 memset(cam, 0, sizeof(struct cam_data));
3149 init_MUTEX(&cam->param_lock);
3150 init_MUTEX(&cam->busy_lock);
3152 reset_camera_struct(cam);
3154 cam->proc_entry = NULL;
3156 memcpy(&cam->vdev, &cpia_template, sizeof(cpia_template));
3157 cam->vdev.priv = cam;
3160 for (i = 0; i < FRAME_NUM; i++) {
3161 cam->frame[i].width = 0;
3162 cam->frame[i].height = 0;
3163 cam->frame[i].state = FRAME_UNUSED;
3164 cam->frame[i].data = NULL;
3166 cam->decompressed_frame.width = 0;
3167 cam->decompressed_frame.height = 0;
3168 cam->decompressed_frame.state = FRAME_UNUSED;
3169 cam->decompressed_frame.data = NULL;
3172 struct cam_data *cpia_register_camera(struct cpia_camera_ops *ops, void *lowlevel)
3174 struct cam_data *camera;
3176 /* Need a lock when adding/removing cameras. This doesn't happen
3177 * often and doesn't take very long, so grabbing the kernel lock
3180 if ((camera = kmalloc(sizeof(struct cam_data), GFP_KERNEL)) == NULL) {
3185 init_camera_struct( camera, ops );
3186 camera->lowlevel_data = lowlevel;
3188 /* register v4l device */
3189 if (video_register_device(&camera->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
3192 printk(KERN_DEBUG "video_register_device failed\n");
3196 /* get version information from camera: open/reset/close */
3199 if (camera->ops->open(camera->lowlevel_data))
3202 /* reset the camera */
3203 if (reset_camera(camera) != 0) {
3204 camera->ops->close(camera->lowlevel_data);
3209 camera->ops->close(camera->lowlevel_data);
3211 /* Eh? Feeling happy? - jerdfelt */
3213 camera->ops->open(camera->lowlevel_data);
3214 camera->ops->close(camera->lowlevel_data);
3217 printk(KERN_INFO " CPiA Version: %d.%02d (%d.%d)\n",
3218 camera->params.version.firmwareVersion,
3219 camera->params.version.firmwareRevision,
3220 camera->params.version.vcVersion,
3221 camera->params.version.vcRevision);
3222 printk(KERN_INFO " CPiA PnP-ID: %04x:%04x:%04x\n",
3223 camera->params.pnpID.vendor,
3224 camera->params.pnpID.product,
3225 camera->params.pnpID.deviceRevision);
3226 printk(KERN_INFO " VP-Version: %d.%d %04x\n",
3227 camera->params.vpVersion.vpVersion,
3228 camera->params.vpVersion.vpRevision,
3229 camera->params.vpVersion.cameraHeadID);
3234 void cpia_unregister_camera(struct cam_data *cam)
3236 if (!cam->open_count) {
3237 DBG("unregistering video\n");
3238 video_unregister_device(&cam->vdev);
3240 LOG("/dev/video%d removed while open, "
3241 "deferring video_unregister_device\n", cam->vdev.minor);
3242 DBG("camera open -- setting ops to NULL\n");
3246 #ifdef CONFIG_PROC_FS
3247 DBG("destroying /proc/cpia/video%d\n", cam->vdev.minor);
3248 destroy_proc_cpia_cam(cam);
3250 if (!cam->open_count) {
3251 DBG("freeing camera\n");
3256 /****************************************************************************
3260 ***************************************************************************/
3263 int init_module(void)
3265 printk(KERN_INFO "%s v%d.%d.%d\n", ABOUT,
3266 CPIA_MAJ_VER, CPIA_MIN_VER, CPIA_PATCH_VER);
3267 #ifdef CONFIG_PROC_FS
3271 #ifdef CONFIG_VIDEO_CPIA_PP_MODULE
3272 request_module("cpia_pp");
3274 #ifdef CONFIG_VIDEO_CPIA_USB_MODULE
3275 request_module("cpia_usb");
3281 void cleanup_module(void)
3283 #ifdef CONFIG_PROC_FS
3284 proc_cpia_destroy();
3290 int cpia_init(struct video_init *unused)
3292 printk(KERN_INFO "%s v%d.%d.%d\n", ABOUT,
3293 CPIA_MAJ_VER, CPIA_MIN_VER, CPIA_PATCH_VER);
3294 #ifdef CONFIG_PROC_FS
3298 #ifdef CONFIG_VIDEO_CPIA_PP
3302 #ifdef CONFIG_VIDEO_CPIA_PP_MODULE
3303 request_module("cpia_pp");
3306 #ifdef CONFIG_VIDEO_CPIA_USB_MODULE
3307 request_module("cpia_usb");
3309 #endif /* CONFIG_KMOD */
3310 #ifdef CONFIG_VIDEO_CPIA_USB
3316 /* Exported symbols for modules. */
3318 EXPORT_SYMBOL(cpia_register_camera);
3319 EXPORT_SYMBOL(cpia_unregister_camera);