Linux 2.4.0-test7-pre7
[davej-history.git] / drivers / media / video / cpia.c
blobd7d007f01aa48da4dce6eee6f85dbc4c7b5e6c03
1 /*
2 * cpia CPiA driver
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>
31 #include <linux/fs.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>
38 #include <asm/io.h>
39 #include <asm/semaphore.h>
40 #include <linux/wrapper.h>
42 #ifdef CONFIG_KMOD
43 #include <linux/kmod.h>
44 #endif
46 #include "cpia.h"
48 #ifdef CONFIG_VIDEO_CPIA_PP
49 extern int cpia_pp_init(void);
50 #endif
51 #ifdef CONFIG_VIDEO_CPIA_USB
52 extern int cpia_usb_init(void);
53 #endif
55 #ifdef MODULE
56 MODULE_AUTHOR("Scott J. Bertin <sbertin@mindspring.com> & Peter Pregler <Peter_Pregler@email.com> & Johannes Erdfelt <jerdfelt@valinux.com>");
57 MODULE_DESCRIPTION("V4L-driver for Vision CPiA based cameras");
58 MODULE_SUPPORTED_DEVICE("video");
59 #endif
61 #define ABOUT "V4L-Driver for Vision CPiA based cameras"
63 #ifndef VID_HARDWARE_CPIA
64 #define VID_HARDWARE_CPIA 24 /* FIXME -> from linux/videodev.h */
65 #endif
67 #define CPIA_MODULE_CPIA (0<<5)
68 #define CPIA_MODULE_SYSTEM (1<<5)
69 #define CPIA_MODULE_VP_CTRL (5<<5)
70 #define CPIA_MODULE_CAPTURE (6<<5)
71 #define CPIA_MODULE_DEBUG (7<<5)
73 #define INPUT (DATA_IN << 8)
74 #define OUTPUT (DATA_OUT << 8)
76 #define CPIA_COMMAND_GetCPIAVersion (INPUT | CPIA_MODULE_CPIA | 1)
77 #define CPIA_COMMAND_GetPnPID (INPUT | CPIA_MODULE_CPIA | 2)
78 #define CPIA_COMMAND_GetCameraStatus (INPUT | CPIA_MODULE_CPIA | 3)
79 #define CPIA_COMMAND_GotoHiPower (OUTPUT | CPIA_MODULE_CPIA | 4)
80 #define CPIA_COMMAND_GotoLoPower (OUTPUT | CPIA_MODULE_CPIA | 5)
81 #define CPIA_COMMAND_GotoSuspend (OUTPUT | CPIA_MODULE_CPIA | 7)
82 #define CPIA_COMMAND_GotoPassThrough (OUTPUT | CPIA_MODULE_CPIA | 8)
83 #define CPIA_COMMAND_ModifyCameraStatus (OUTPUT | CPIA_MODULE_CPIA | 10)
85 #define CPIA_COMMAND_ReadVCRegs (INPUT | CPIA_MODULE_SYSTEM | 1)
86 #define CPIA_COMMAND_WriteVCReg (OUTPUT | CPIA_MODULE_SYSTEM | 2)
87 #define CPIA_COMMAND_ReadMCPorts (INPUT | CPIA_MODULE_SYSTEM | 3)
88 #define CPIA_COMMAND_WriteMCPort (OUTPUT | CPIA_MODULE_SYSTEM | 4)
89 #define CPIA_COMMAND_SetBaudRate (OUTPUT | CPIA_MODULE_SYSTEM | 5)
90 #define CPIA_COMMAND_SetECPTiming (OUTPUT | CPIA_MODULE_SYSTEM | 6)
91 #define CPIA_COMMAND_ReadIDATA (INPUT | CPIA_MODULE_SYSTEM | 7)
92 #define CPIA_COMMAND_WriteIDATA (OUTPUT | CPIA_MODULE_SYSTEM | 8)
93 #define CPIA_COMMAND_GenericCall (OUTPUT | CPIA_MODULE_SYSTEM | 9)
94 #define CPIA_COMMAND_I2CStart (OUTPUT | CPIA_MODULE_SYSTEM | 10)
95 #define CPIA_COMMAND_I2CStop (OUTPUT | CPIA_MODULE_SYSTEM | 11)
96 #define CPIA_COMMAND_I2CWrite (OUTPUT | CPIA_MODULE_SYSTEM | 12)
97 #define CPIA_COMMAND_I2CRead (INPUT | CPIA_MODULE_SYSTEM | 13)
99 #define CPIA_COMMAND_GetVPVersion (INPUT | CPIA_MODULE_VP_CTRL | 1)
100 #define CPIA_COMMAND_SetColourParams (OUTPUT | CPIA_MODULE_VP_CTRL | 3)
101 #define CPIA_COMMAND_SetExposure (OUTPUT | CPIA_MODULE_VP_CTRL | 4)
102 #define CPIA_COMMAND_SetColourBalance (OUTPUT | CPIA_MODULE_VP_CTRL | 6)
103 #define CPIA_COMMAND_SetSensorFPS (OUTPUT | CPIA_MODULE_VP_CTRL | 7)
104 #define CPIA_COMMAND_SetVPDefaults (OUTPUT | CPIA_MODULE_VP_CTRL | 8)
105 #define CPIA_COMMAND_SetApcor (OUTPUT | CPIA_MODULE_VP_CTRL | 9)
106 #define CPIA_COMMAND_SetFlickerCtrl (OUTPUT | CPIA_MODULE_VP_CTRL | 10)
107 #define CPIA_COMMAND_SetVLOffset (OUTPUT | CPIA_MODULE_VP_CTRL | 11)
108 #define CPIA_COMMAND_GetColourParams (INPUT | CPIA_MODULE_VP_CTRL | 16)
109 #define CPIA_COMMAND_GetColourBalance (INPUT | CPIA_MODULE_VP_CTRL | 17)
110 #define CPIA_COMMAND_GetExposure (INPUT | CPIA_MODULE_VP_CTRL | 18)
111 #define CPIA_COMMAND_SetSensorMatrix (OUTPUT | CPIA_MODULE_VP_CTRL | 19)
112 #define CPIA_COMMAND_ColourBars (OUTPUT | CPIA_MODULE_VP_CTRL | 25)
113 #define CPIA_COMMAND_ReadVPRegs (INPUT | CPIA_MODULE_VP_CTRL | 30)
114 #define CPIA_COMMAND_WriteVPReg (OUTPUT | CPIA_MODULE_VP_CTRL | 31)
116 #define CPIA_COMMAND_GrabFrame (OUTPUT | CPIA_MODULE_CAPTURE | 1)
117 #define CPIA_COMMAND_UploadFrame (OUTPUT | CPIA_MODULE_CAPTURE | 2)
118 #define CPIA_COMMAND_SetGrabMode (OUTPUT | CPIA_MODULE_CAPTURE | 3)
119 #define CPIA_COMMAND_InitStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 4)
120 #define CPIA_COMMAND_FiniStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 5)
121 #define CPIA_COMMAND_StartStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 6)
122 #define CPIA_COMMAND_EndStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 7)
123 #define CPIA_COMMAND_SetFormat (OUTPUT | CPIA_MODULE_CAPTURE | 8)
124 #define CPIA_COMMAND_SetROI (OUTPUT | CPIA_MODULE_CAPTURE | 9)
125 #define CPIA_COMMAND_SetCompression (OUTPUT | CPIA_MODULE_CAPTURE | 10)
126 #define CPIA_COMMAND_SetCompressionTarget (OUTPUT | CPIA_MODULE_CAPTURE | 11)
127 #define CPIA_COMMAND_SetYUVThresh (OUTPUT | CPIA_MODULE_CAPTURE | 12)
128 #define CPIA_COMMAND_SetCompressionParams (OUTPUT | CPIA_MODULE_CAPTURE | 13)
129 #define CPIA_COMMAND_DiscardFrame (OUTPUT | CPIA_MODULE_CAPTURE | 14)
131 #define CPIA_COMMAND_OutputRS232 (OUTPUT | CPIA_MODULE_DEBUG | 1)
132 #define CPIA_COMMAND_AbortProcess (OUTPUT | CPIA_MODULE_DEBUG | 4)
133 #define CPIA_COMMAND_SetDramPage (OUTPUT | CPIA_MODULE_DEBUG | 5)
134 #define CPIA_COMMAND_StartDramUpload (OUTPUT | CPIA_MODULE_DEBUG | 6)
135 #define CPIA_COMMAND_StartDummyDtream (OUTPUT | CPIA_MODULE_DEBUG | 8)
136 #define CPIA_COMMAND_AbortStream (OUTPUT | CPIA_MODULE_DEBUG | 9)
137 #define CPIA_COMMAND_DownloadDRAM (OUTPUT | CPIA_MODULE_DEBUG | 10)
139 enum {
140 FRAME_READY, /* Ready to grab into */
141 FRAME_GRABBING, /* In the process of being grabbed into */
142 FRAME_DONE, /* Finished grabbing, but not been synced yet */
143 FRAME_UNUSED, /* Unused (no MCAPTURE) */
146 #define COMMAND_NONE 0x0000
147 #define COMMAND_SETCOMPRESSION 0x0001
148 #define COMMAND_SETCOMPRESSIONTARGET 0x0002
149 #define COMMAND_SETCOLOURPARAMS 0x0004
150 #define COMMAND_SETFORMAT 0x0008
151 #define COMMAND_PAUSE 0x0010
152 #define COMMAND_RESUME 0x0020
153 #define COMMAND_SETYUVTHRESH 0x0040
154 #define COMMAND_SETECPTIMING 0x0080
155 #define COMMAND_SETCOMPRESSIONPARAMS 0x0100
156 #define COMMAND_SETEXPOSURE 0x0200
157 #define COMMAND_SETCOLOURBALANCE 0x0400
158 #define COMMAND_SETSENSORFPS 0x0800
159 #define COMMAND_SETAPCOR 0x1000
160 #define COMMAND_SETFLICKERCTRL 0x2000
161 #define COMMAND_SETVLOFFSET 0x4000
163 /* Developer's Guide Table 5 p 3-34
164 * indexed by [mains][sensorFps.baserate][sensorFps.divisor]*/
165 static u8 flicker_jumps[2][2][4] =
166 { { { 76, 38, 19, 9 }, { 92, 46, 23, 11 } },
167 { { 64, 32, 16, 8 }, { 76, 38, 19, 9} }
170 /* forward declaration of local function */
171 static void reset_camera_struct(struct cam_data *cam);
173 /**********************************************************************
175 * Memory management
177 * This is a shameless copy from the USB-cpia driver (linux kernel
178 * version 2.3.29 or so, I have no idea what this code actually does ;).
179 * Actually it seems to be a copy of a shameless copy of the bttv-driver.
180 * Or that is a copy of a shameless copy of ... (To the powers: is there
181 * no generic kernel-function to do this sort of stuff?)
183 * Yes, it was a shameless copy from the bttv-driver. IIRC, Alan says
184 * there will be one, but apparentely not yet - jerdfelt
186 **********************************************************************/
188 /* Given PGD from the address space's page table, return the kernel
189 * virtual mapping of the physical memory mapped at ADR.
191 static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr)
193 unsigned long ret = 0UL;
194 pmd_t *pmd;
195 pte_t *ptep, pte;
197 if (!pgd_none(*pgd)) {
198 pmd = pmd_offset(pgd, adr);
199 if (!pmd_none(*pmd)) {
200 ptep = pte_offset(pmd, adr);
201 pte = *ptep;
202 if (pte_present(pte)) {
203 ret = (unsigned long) page_address(pte_page(pte));
204 ret |= (adr & (PAGE_SIZE-1));
208 return ret;
211 /* Here we want the physical address of the memory.
212 * This is used when initializing the contents of the
213 * area and marking the pages as reserved.
215 static inline unsigned long kvirt_to_pa(unsigned long adr)
217 unsigned long va, kva, ret;
219 va = VMALLOC_VMADDR(adr);
220 kva = uvirt_to_kva(pgd_offset_k(va), va);
221 ret = __pa(kva);
222 return ret;
225 static void *rvmalloc(unsigned long size)
227 void *mem;
228 unsigned long adr, page;
230 /* Round it off to PAGE_SIZE */
231 size += (PAGE_SIZE - 1);
232 size &= ~(PAGE_SIZE - 1);
234 mem = vmalloc_32(size);
235 if (!mem)
236 return NULL;
238 memset(mem, 0, size); /* Clear the ram out, no junk to the user */
239 adr = (unsigned long) mem;
240 while (size > 0) {
241 page = kvirt_to_pa(adr);
242 mem_map_reserve(virt_to_page(__va(page)));
243 adr += PAGE_SIZE;
244 if (size > PAGE_SIZE)
245 size -= PAGE_SIZE;
246 else
247 size = 0;
250 return mem;
253 static void rvfree(void *mem, unsigned long size)
255 unsigned long adr, page;
257 if (!mem)
258 return;
260 size += (PAGE_SIZE - 1);
261 size &= ~(PAGE_SIZE - 1);
263 adr = (unsigned long) mem;
264 while (size > 0) {
265 page = kvirt_to_pa(adr);
266 mem_map_unreserve(virt_to_page(__va(page)));
267 adr += PAGE_SIZE;
268 if (size > PAGE_SIZE)
269 size -= PAGE_SIZE;
270 else
271 size = 0;
273 vfree(mem);
276 /**********************************************************************
278 * /proc interface
280 **********************************************************************/
281 #ifdef CONFIG_PROC_FS
282 static struct proc_dir_entry *cpia_proc_root=NULL;
284 static int cpia_read_proc(char *page, char **start, off_t off,
285 int count, int *eof, void *data)
287 char *out = page;
288 int len, tmp;
289 struct cam_data *cam = data;
290 char tmpstr[20];
292 /* IMPORTANT: This output MUST be kept under PAGE_SIZE
293 * or we need to get more sophisticated. */
295 out += sprintf(out, "read-only\n-----------------------\n");
296 out += sprintf(out, "V4L Driver version: %d.%d.%d\n",
297 CPIA_MAJ_VER, CPIA_MIN_VER, CPIA_PATCH_VER);
298 out += sprintf(out, "CPIA Version: %d.%02d (%d.%d)\n",
299 cam->params.version.firmwareVersion,
300 cam->params.version.firmwareRevision,
301 cam->params.version.vcVersion,
302 cam->params.version.vcRevision);
303 out += sprintf(out, "CPIA PnP-ID: %04x:%04x:%04x\n",
304 cam->params.pnpID.vendor, cam->params.pnpID.product,
305 cam->params.pnpID.deviceRevision);
306 out += sprintf(out, "VP-Version: %d.%d %04x\n",
307 cam->params.vpVersion.vpVersion,
308 cam->params.vpVersion.vpRevision,
309 cam->params.vpVersion.cameraHeadID);
311 out += sprintf(out, "system_state: %#04x\n",
312 cam->params.status.systemState);
313 out += sprintf(out, "grab_state: %#04x\n",
314 cam->params.status.grabState);
315 out += sprintf(out, "stream_state: %#04x\n",
316 cam->params.status.streamState);
317 out += sprintf(out, "fatal_error: %#04x\n",
318 cam->params.status.fatalError);
319 out += sprintf(out, "cmd_error: %#04x\n",
320 cam->params.status.cmdError);
321 out += sprintf(out, "debug_flags: %#04x\n",
322 cam->params.status.debugFlags);
323 out += sprintf(out, "vp_status: %#04x\n",
324 cam->params.status.vpStatus);
325 out += sprintf(out, "error_code: %#04x\n",
326 cam->params.status.errorCode);
327 out += sprintf(out, "video_size: %s\n",
328 cam->params.format.videoSize == VIDEOSIZE_CIF ?
329 "CIF " : "QCIF");
330 out += sprintf(out, "sub_sample: %s\n",
331 cam->params.format.subSample == SUBSAMPLE_420 ?
332 "420" : "422");
333 out += sprintf(out, "yuv_order: %s\n",
334 cam->params.format.yuvOrder == YUVORDER_YUYV ?
335 "YUYV" : "UYVY");
336 out += sprintf(out, "roi: (%3d, %3d) to (%3d, %3d)\n",
337 cam->params.roi.colStart*8,
338 cam->params.roi.rowStart*4,
339 cam->params.roi.colEnd*8,
340 cam->params.roi.rowEnd*4);
341 out += sprintf(out, "actual_fps: %3d\n", cam->fps);
342 out += sprintf(out, "transfer_rate: %4dkB/s\n",
343 cam->transfer_rate);
345 out += sprintf(out, "\nread-write\n");
346 out += sprintf(out, "----------------------- current min"
347 " max default comment\n");
348 out += sprintf(out, "brightness: %8d %8d %8d %8d\n",
349 cam->params.colourParams.brightness, 0, 100, 50);
350 if (cam->params.version.firmwareVersion == 1 &&
351 cam->params.version.firmwareRevision == 2)
352 /* 1-02 firmware limits contrast to 80 */
353 tmp = 80;
354 else
355 tmp = 96;
357 out += sprintf(out, "contrast: %8d %8d %8d %8d"
358 " steps of 8\n",
359 cam->params.colourParams.contrast, 0, tmp, 48);
360 out += sprintf(out, "saturation: %8d %8d %8d %8d\n",
361 cam->params.colourParams.saturation, 0, 100, 50);
362 tmp = (25000+5000*cam->params.sensorFps.baserate)/
363 (1<<cam->params.sensorFps.divisor);
364 out += sprintf(out, "sensor_fps: %4d.%03d %8d %8d %8d\n",
365 tmp/1000, tmp%1000, 3, 30, 15);
366 out += sprintf(out, "stream_start_line: %8d %8d %8d %8d\n",
367 2*cam->params.streamStartLine, 0,
368 cam->params.format.videoSize == VIDEOSIZE_CIF ? 288:144,
369 cam->params.format.videoSize == VIDEOSIZE_CIF ? 240:120);
370 out += sprintf(out, "ecp_timing: %8s %8s %8s %8s\n",
371 cam->params.ecpTiming ? "slow" : "normal", "slow",
372 "normal", "normal");
374 if (cam->params.colourBalance.balanceModeIsAuto) {
375 sprintf(tmpstr, "auto");
376 } else {
377 sprintf(tmpstr, "manual");
379 out += sprintf(out, "color_balance_mode: %8s %8s %8s"
380 " %8s\n", tmpstr, "manual", "auto", "auto");
381 out += sprintf(out, "red_gain: %8d %8d %8d %8d\n",
382 cam->params.colourBalance.redGain, 0, 212, 32);
383 out += sprintf(out, "green_gain: %8d %8d %8d %8d\n",
384 cam->params.colourBalance.greenGain, 0, 212, 6);
385 out += sprintf(out, "blue_gain: %8d %8d %8d %8d\n",
386 cam->params.colourBalance.blueGain, 0, 212, 92);
388 if (cam->params.version.firmwareVersion == 1 &&
389 cam->params.version.firmwareRevision == 2)
390 /* 1-02 firmware limits gain to 2 */
391 sprintf(tmpstr, "%8d %8d", 1, 2);
392 else
393 sprintf(tmpstr, "1,2,4,8");
395 if (cam->params.exposure.gainMode == 0)
396 out += sprintf(out, "max_gain: unknown %18s"
397 " %8d\n", tmpstr, 2);
398 else
399 out += sprintf(out, "max_gain: %8d %18s %8d\n",
400 1<<(cam->params.exposure.gainMode-1), tmpstr, 2);
402 switch(cam->params.exposure.expMode) {
403 case 1:
404 case 3:
405 sprintf(tmpstr, "manual");
406 break;
407 case 2:
408 sprintf(tmpstr, "auto");
409 break;
410 default:
411 sprintf(tmpstr, "unknown");
412 break;
414 out += sprintf(out, "exposure_mode: %8s %8s %8s"
415 " %8s\n", tmpstr, "manual", "auto", "auto");
416 out += sprintf(out, "centre_weight: %8s %8s %8s %8s\n",
417 (2-cam->params.exposure.centreWeight) ? "on" : "off",
418 "off", "on", "on");
419 out += sprintf(out, "gain: %8d %8d max_gain %8d 1,2,4,8 possible\n",
420 1<<cam->params.exposure.gain, 1, 1);
421 if (cam->params.version.firmwareVersion == 1 &&
422 cam->params.version.firmwareRevision == 2)
423 /* 1-02 firmware limits fineExp to 127 */
424 tmp = 255;
425 else
426 tmp = 511;
428 out += sprintf(out, "fine_exp: %8d %8d %8d %8d\n",
429 cam->params.exposure.fineExp*2, 0, tmp, 0);
430 if (cam->params.version.firmwareVersion == 1 &&
431 cam->params.version.firmwareRevision == 2)
432 /* 1-02 firmware limits coarseExpHi to 0 */
433 tmp = 255;
434 else
435 tmp = 65535;
437 out += sprintf(out, "coarse_exp: %8d %8d %8d"
438 " %8d\n", cam->params.exposure.coarseExpLo+
439 256*cam->params.exposure.coarseExpHi, 0, tmp, 185);
440 out += sprintf(out, "red_comp: %8d %8d %8d %8d\n",
441 cam->params.exposure.redComp, 220, 255, 220);
442 out += sprintf(out, "green1_comp: %8d %8d %8d %8d\n",
443 cam->params.exposure.green1Comp, 214, 255, 214);
444 out += sprintf(out, "green2_comp: %8d %8d %8d %8d\n",
445 cam->params.exposure.green2Comp, 214, 255, 214);
446 out += sprintf(out, "blue_comp: %8d %8d %8d %8d\n",
447 cam->params.exposure.blueComp, 230, 255, 230);
449 out += sprintf(out, "apcor_gain1: %#8x %#8x %#8x %#8x\n",
450 cam->params.apcor.gain1, 0, 0xff, 0x1c);
451 out += sprintf(out, "apcor_gain2: %#8x %#8x %#8x %#8x\n",
452 cam->params.apcor.gain2, 0, 0xff, 0x1a);
453 out += sprintf(out, "apcor_gain4: %#8x %#8x %#8x %#8x\n",
454 cam->params.apcor.gain4, 0, 0xff, 0x2d);
455 out += sprintf(out, "apcor_gain8: %#8x %#8x %#8x %#8x\n",
456 cam->params.apcor.gain8, 0, 0xff, 0x2a);
457 out += sprintf(out, "vl_offset_gain1: %8d %8d %8d %8d\n",
458 cam->params.vlOffset.gain1, 0, 255, 24);
459 out += sprintf(out, "vl_offset_gain2: %8d %8d %8d %8d\n",
460 cam->params.vlOffset.gain2, 0, 255, 28);
461 out += sprintf(out, "vl_offset_gain4: %8d %8d %8d %8d\n",
462 cam->params.vlOffset.gain4, 0, 255, 30);
463 out += sprintf(out, "vl_offset_gain8: %8d %8d %8d %8d\n",
464 cam->params.vlOffset.gain8, 0, 255, 30);
465 out += sprintf(out, "flicker_control: %8s %8s %8s %8s\n",
466 cam->params.flickerControl.flickerMode ? "on" : "off",
467 "off", "on", "off");
468 out += sprintf(out, "mains_frequency: %8d %8d %8d %8d"
469 " only 50/60\n",
470 cam->mainsFreq ? 60 : 50, 50, 60, 50);
471 out += sprintf(out, "allowable_overexposure: %8d %8d %8d %8d\n",
472 cam->params.flickerControl.allowableOverExposure, 0,
473 255, 0);
474 out += sprintf(out, "compression_mode: ");
475 switch(cam->params.compression.mode) {
476 case CPIA_COMPRESSION_NONE:
477 out += sprintf(out, "%8s", "none");
478 break;
479 case CPIA_COMPRESSION_AUTO:
480 out += sprintf(out, "%8s", "auto");
481 break;
482 case CPIA_COMPRESSION_MANUAL:
483 out += sprintf(out, "%8s", "manual");
484 break;
485 default:
486 out += sprintf(out, "%8s", "unknown");
487 break;
489 out += sprintf(out, " none,auto,manual auto\n");
490 out += sprintf(out, "decimation_enable: %8s %8s %8s %8s\n",
491 cam->params.compression.decimation ==
492 DECIMATION_ENAB ? "on":"off", "off", "off",
493 "off");
494 out += sprintf(out, "compression_target: %9s %9s %9s %9s\n",
495 cam->params.compressionTarget.frTargeting ==
496 CPIA_COMPRESSION_TARGET_FRAMERATE ?
497 "framerate":"quality",
498 "framerate", "quality", "quality");
499 out += sprintf(out, "target_framerate: %8d %8d %8d %8d\n",
500 cam->params.compressionTarget.targetFR, 0, 30, 7);
501 out += sprintf(out, "target_quality: %8d %8d %8d %8d\n",
502 cam->params.compressionTarget.targetQ, 0, 255, 10);
503 out += sprintf(out, "y_threshold: %8d %8d %8d %8d\n",
504 cam->params.yuvThreshold.yThreshold, 0, 31, 15);
505 out += sprintf(out, "uv_threshold: %8d %8d %8d %8d\n",
506 cam->params.yuvThreshold.uvThreshold, 0, 31, 15);
507 out += sprintf(out, "hysteresis: %8d %8d %8d %8d\n",
508 cam->params.compressionParams.hysteresis, 0, 255, 3);
509 out += sprintf(out, "threshold_max: %8d %8d %8d %8d\n",
510 cam->params.compressionParams.threshMax, 0, 255, 11);
511 out += sprintf(out, "small_step: %8d %8d %8d %8d\n",
512 cam->params.compressionParams.smallStep, 0, 255, 1);
513 out += sprintf(out, "large_step: %8d %8d %8d %8d\n",
514 cam->params.compressionParams.largeStep, 0, 255, 3);
515 out += sprintf(out, "decimation_hysteresis: %8d %8d %8d %8d\n",
516 cam->params.compressionParams.decimationHysteresis,
517 0, 255, 2);
518 out += sprintf(out, "fr_diff_step_thresh: %8d %8d %8d %8d\n",
519 cam->params.compressionParams.frDiffStepThresh,
520 0, 255, 5);
521 out += sprintf(out, "q_diff_step_thresh: %8d %8d %8d %8d\n",
522 cam->params.compressionParams.qDiffStepThresh,
523 0, 255, 3);
524 out += sprintf(out, "decimation_thresh_mod: %8d %8d %8d %8d\n",
525 cam->params.compressionParams.decimationThreshMod,
526 0, 255, 2);
528 len = out - page;
529 len -= off;
530 if (len < count) {
531 *eof = 1;
532 if (len <= 0) return 0;
533 } else
534 len = count;
536 *start = page + off;
537 return len;
540 static int cpia_write_proc(struct file *file, const char *buffer,
541 unsigned long count, void *data)
543 struct cam_data *cam = data;
544 struct cam_params new_params;
545 int retval, find_colon;
546 int size = count;
547 unsigned long val;
548 u32 command_flags = 0;
549 u8 new_mains;
551 if (down_interruptible(&cam->param_lock))
552 return -ERESTARTSYS;
555 * Skip over leading whitespace
557 while (count && isspace(*buffer)) {
558 --count;
559 ++buffer;
562 memcpy(&new_params, &cam->params, sizeof(struct cam_params));
563 new_mains = cam->mainsFreq;
565 #define MATCH(x) \
566 ({ \
567 int _len = strlen(x), _ret, _colon_found; \
568 _ret = (_len <= count && strncmp(buffer, x, _len) == 0); \
569 if (_ret) { \
570 buffer += _len; \
571 count -= _len; \
572 if (find_colon) { \
573 _colon_found = 0; \
574 while (count && (*buffer == ' ' || *buffer == '\t' || \
575 (!_colon_found && *buffer == ':'))) { \
576 if (*buffer == ':') \
577 _colon_found = 1; \
578 --count; \
579 ++buffer; \
581 if (!count || !_colon_found) \
582 retval = -EINVAL; \
583 find_colon = 0; \
586 _ret; \
588 #define FIRMWARE_VERSION(x,y) (new_params.version.firmwareVersion == (x) && \
589 new_params.version.firmwareRevision == (y))
590 #define VALUE \
591 ({ \
592 char *_p; \
593 unsigned long int _ret; \
594 _ret = simple_strtoul(buffer, &_p, 0); \
595 if (_p == buffer) \
596 retval = -EINVAL; \
597 else { \
598 count -= _p - buffer; \
599 buffer = _p; \
601 _ret; \
604 retval = 0;
605 while (count && !retval) {
606 find_colon = 1;
607 if (MATCH("brightness")) {
608 if (!retval)
609 val = VALUE;
611 if (!retval) {
612 if (val <= 100)
613 new_params.colourParams.brightness = val;
614 else
615 retval = -EINVAL;
617 command_flags |= COMMAND_SETCOLOURPARAMS;
618 } else if (MATCH("contrast")) {
619 if (!retval)
620 val = VALUE;
622 if (!retval) {
623 if (val <= 100) {
624 /* contrast is in steps of 8, so round*/
625 val = ((val + 3) / 8) * 8;
626 /* 1-02 firmware limits contrast to 80*/
627 if (FIRMWARE_VERSION(1,2) && val > 80)
628 val = 80;
630 new_params.colourParams.contrast = val;
631 } else
632 retval = -EINVAL;
634 command_flags |= COMMAND_SETCOLOURPARAMS;
635 } else if (MATCH("saturation")) {
636 if (!retval)
637 val = VALUE;
639 if (!retval) {
640 if (val <= 100)
641 new_params.colourParams.saturation = val;
642 else
643 retval = -EINVAL;
645 command_flags |= COMMAND_SETCOLOURPARAMS;
646 } else if (MATCH("sensor_fps")) {
647 if (!retval)
648 val = VALUE;
650 if (!retval) {
651 /* find values so that sensorFPS is minimized,
652 * but >= val */
653 if (val > 30)
654 retval = -EINVAL;
655 else if (val > 25) {
656 new_params.sensorFps.divisor = 0;
657 new_params.sensorFps.baserate = 1;
658 } else if (val > 15) {
659 new_params.sensorFps.divisor = 0;
660 new_params.sensorFps.baserate = 0;
661 } else if (val > 12) {
662 new_params.sensorFps.divisor = 1;
663 new_params.sensorFps.baserate = 1;
664 } else if (val > 7) {
665 new_params.sensorFps.divisor = 1;
666 new_params.sensorFps.baserate = 0;
667 } else if (val > 6) {
668 new_params.sensorFps.divisor = 2;
669 new_params.sensorFps.baserate = 1;
670 } else if (val > 3) {
671 new_params.sensorFps.divisor = 2;
672 new_params.sensorFps.baserate = 0;
673 } else {
674 new_params.sensorFps.divisor = 3;
675 /* Either base rate would work here */
676 new_params.sensorFps.baserate = 1;
678 new_params.flickerControl.coarseJump =
679 flicker_jumps[new_mains]
680 [new_params.sensorFps.baserate]
681 [new_params.sensorFps.divisor];
682 if (new_params.flickerControl.flickerMode)
683 command_flags |= COMMAND_SETFLICKERCTRL;
685 command_flags |= COMMAND_SETSENSORFPS;
686 } else if (MATCH("stream_start_line")) {
687 if (!retval)
688 val = VALUE;
690 if (!retval) {
691 int max_line = 288;
693 if (new_params.format.videoSize == VIDEOSIZE_QCIF)
694 max_line = 144;
695 if (val <= max_line)
696 new_params.streamStartLine = val/2;
697 else
698 retval = -EINVAL;
700 } else if (MATCH("ecp_timing")) {
701 if (!retval && MATCH("normal"))
702 new_params.ecpTiming = 0;
703 else if (!retval && MATCH("slow"))
704 new_params.ecpTiming = 1;
705 else
706 retval = -EINVAL;
708 command_flags |= COMMAND_SETECPTIMING;
709 } else if (MATCH("color_balance_mode")) {
710 if (!retval && MATCH("manual"))
711 new_params.colourBalance.balanceModeIsAuto = 0;
712 else if (!retval && MATCH("auto"))
713 new_params.colourBalance.balanceModeIsAuto = 1;
714 else
715 retval = -EINVAL;
717 command_flags |= COMMAND_SETCOLOURBALANCE;
718 } else if (MATCH("red_gain")) {
719 if (!retval)
720 val = VALUE;
722 if (!retval) {
723 if (val <= 212)
724 new_params.colourBalance.redGain = val;
725 else
726 retval = -EINVAL;
728 command_flags |= COMMAND_SETCOLOURBALANCE;
729 } else if (MATCH("green_gain")) {
730 if (!retval)
731 val = VALUE;
733 if (!retval) {
734 if (val <= 212)
735 new_params.colourBalance.greenGain = val;
736 else
737 retval = -EINVAL;
739 command_flags |= COMMAND_SETCOLOURBALANCE;
740 } else if (MATCH("blue_gain")) {
741 if (!retval)
742 val = VALUE;
744 if (!retval) {
745 if (val <= 212)
746 new_params.colourBalance.blueGain = val;
747 else
748 retval = -EINVAL;
750 command_flags |= COMMAND_SETCOLOURBALANCE;
751 } else if (MATCH("max_gain")) {
752 if (!retval)
753 val = VALUE;
755 if (!retval) {
756 /* 1-02 firmware limits gain to 2 */
757 if (FIRMWARE_VERSION(1,2) && val > 2)
758 val = 2;
759 switch(val) {
760 case 1:
761 new_params.exposure.gainMode = 1;
762 break;
763 case 2:
764 new_params.exposure.gainMode = 2;
765 break;
766 case 4:
767 new_params.exposure.gainMode = 3;
768 break;
769 case 8:
770 new_params.exposure.gainMode = 4;
771 break;
772 default:
773 retval = -EINVAL;
774 break;
777 command_flags |= COMMAND_SETEXPOSURE;
778 } else if (MATCH("exposure_mode")) {
779 if (!retval && MATCH("auto"))
780 new_params.exposure.expMode = 2;
781 else if (!retval && MATCH("manual")) {
782 if (new_params.exposure.expMode == 2)
783 new_params.exposure.expMode = 3;
784 new_params.flickerControl.flickerMode = 0;
785 command_flags |= COMMAND_SETFLICKERCTRL;
786 } else
787 retval = -EINVAL;
789 command_flags |= COMMAND_SETEXPOSURE;
790 } else if (MATCH("centre_weight")) {
791 if (!retval && MATCH("on"))
792 new_params.exposure.centreWeight = 1;
793 else if (!retval && MATCH("off"))
794 new_params.exposure.centreWeight = 2;
795 else
796 retval = -EINVAL;
798 command_flags |= COMMAND_SETEXPOSURE;
799 } else if (MATCH("gain")) {
800 if (!retval)
801 val = VALUE;
803 if (!retval) {
804 switch(val) {
805 case 1:
806 new_params.exposure.gain = 0;
807 new_params.exposure.expMode = 1;
808 new_params.flickerControl.flickerMode = 0;
809 command_flags |= COMMAND_SETFLICKERCTRL;
810 break;
811 case 2:
812 new_params.exposure.gain = 1;
813 new_params.exposure.expMode = 1;
814 new_params.flickerControl.flickerMode = 0;
815 command_flags |= COMMAND_SETFLICKERCTRL;
816 break;
817 case 4:
818 new_params.exposure.gain = 2;
819 new_params.exposure.expMode = 1;
820 new_params.flickerControl.flickerMode = 0;
821 command_flags |= COMMAND_SETFLICKERCTRL;
822 break;
823 case 8:
824 new_params.exposure.gain = 3;
825 new_params.exposure.expMode = 1;
826 new_params.flickerControl.flickerMode = 0;
827 command_flags |= COMMAND_SETFLICKERCTRL;
828 break;
829 default:
830 retval = -EINVAL;
831 break;
833 command_flags |= COMMAND_SETEXPOSURE;
834 if (new_params.exposure.gain >
835 new_params.exposure.gainMode-1)
836 retval = -EINVAL;
838 } else if (MATCH("fine_exp")) {
839 if (!retval)
840 val = VALUE;
842 if (!retval) {
843 if (val < 256) {
844 /* 1-02 firmware limits fineExp to 127*/
845 if (FIRMWARE_VERSION(1,2) && val > 127)
846 val = 127;
847 new_params.exposure.fineExp = val;
848 new_params.exposure.expMode = 1;
849 command_flags |= COMMAND_SETEXPOSURE;
850 new_params.flickerControl.flickerMode = 0;
851 command_flags |= COMMAND_SETFLICKERCTRL;
852 } else
853 retval = -EINVAL;
855 } else if (MATCH("coarse_exp")) {
856 if (!retval)
857 val = VALUE;
859 if (!retval) {
860 if (val < 65536) {
861 /* 1-02 firmware limits
862 * coarseExp to 255 */
863 if (FIRMWARE_VERSION(1,2) && val > 255)
864 val = 255;
865 new_params.exposure.coarseExpLo =
866 val & 0xff;
867 new_params.exposure.coarseExpHi =
868 val >> 8;
869 new_params.exposure.expMode = 1;
870 command_flags |= COMMAND_SETEXPOSURE;
871 new_params.flickerControl.flickerMode = 0;
872 command_flags |= COMMAND_SETFLICKERCTRL;
873 } else
874 retval = -EINVAL;
876 } else if (MATCH("red_comp")) {
877 if (!retval)
878 val = VALUE;
880 if (!retval) {
881 if (val >= 220 && val <= 255) {
882 new_params.exposure.redComp = val;
883 command_flags |= COMMAND_SETEXPOSURE;
884 } else
885 retval = -EINVAL;
887 } else if (MATCH("green1_comp")) {
888 if (!retval)
889 val = VALUE;
891 if (!retval) {
892 if (val >= 214 && val <= 255) {
893 new_params.exposure.green1Comp = val;
894 command_flags |= COMMAND_SETEXPOSURE;
895 } else
896 retval = -EINVAL;
898 } else if (MATCH("green2_comp")) {
899 if (!retval)
900 val = VALUE;
902 if (!retval) {
903 if (val >= 214 && val <= 255) {
904 new_params.exposure.green2Comp = val;
905 command_flags |= COMMAND_SETEXPOSURE;
906 } else
907 retval = -EINVAL;
909 } else if (MATCH("blue_comp")) {
910 if (!retval)
911 val = VALUE;
913 if (!retval) {
914 if (val >= 230 && val <= 255) {
915 new_params.exposure.blueComp = val;
916 command_flags |= COMMAND_SETEXPOSURE;
917 } else
918 retval = -EINVAL;
920 } else if (MATCH("apcor_gain1")) {
921 if (!retval)
922 val = VALUE;
924 if (!retval) {
925 command_flags |= COMMAND_SETAPCOR;
926 if (val <= 0xff)
927 new_params.apcor.gain1 = val;
928 else
929 retval = -EINVAL;
931 } else if (MATCH("apcor_gain2")) {
932 if (!retval)
933 val = VALUE;
935 if (!retval) {
936 command_flags |= COMMAND_SETAPCOR;
937 if (val <= 0xff)
938 new_params.apcor.gain2 = val;
939 else
940 retval = -EINVAL;
942 } else if (MATCH("apcor_gain4")) {
943 if (!retval)
944 val = VALUE;
946 if (!retval) {
947 command_flags |= COMMAND_SETAPCOR;
948 if (val <= 0xff)
949 new_params.apcor.gain4 = val;
950 else
951 retval = -EINVAL;
953 } else if (MATCH("apcor_gain8")) {
954 if (!retval)
955 val = VALUE;
957 if (!retval) {
958 command_flags |= COMMAND_SETAPCOR;
959 if (val <= 0xff)
960 new_params.apcor.gain8 = val;
961 else
962 retval = -EINVAL;
964 } else if (MATCH("vl_offset_gain1")) {
965 if (!retval)
966 val = VALUE;
968 if (!retval) {
969 if (val <= 0xff)
970 new_params.vlOffset.gain1 = val;
971 else
972 retval = -EINVAL;
974 command_flags |= COMMAND_SETVLOFFSET;
975 } else if (MATCH("vl_offset_gain2")) {
976 if (!retval)
977 val = VALUE;
979 if (!retval) {
980 if (val <= 0xff)
981 new_params.vlOffset.gain2 = val;
982 else
983 retval = -EINVAL;
985 command_flags |= COMMAND_SETVLOFFSET;
986 } else if (MATCH("vl_offset_gain4")) {
987 if (!retval)
988 val = VALUE;
990 if (!retval) {
991 if (val <= 0xff)
992 new_params.vlOffset.gain4 = val;
993 else
994 retval = -EINVAL;
996 command_flags |= COMMAND_SETVLOFFSET;
997 } else if (MATCH("vl_offset_gain8")) {
998 if (!retval)
999 val = VALUE;
1001 if (!retval) {
1002 if (val <= 0xff)
1003 new_params.vlOffset.gain8 = val;
1004 else
1005 retval = -EINVAL;
1007 command_flags |= COMMAND_SETVLOFFSET;
1008 } else if (MATCH("flicker_control")) {
1009 if (!retval && MATCH("on")) {
1010 new_params.flickerControl.flickerMode = 1;
1011 new_params.exposure.expMode = 2;
1012 command_flags |= COMMAND_SETEXPOSURE;
1013 } else if (!retval && MATCH("off"))
1014 new_params.flickerControl.flickerMode = 0;
1015 else
1016 retval = -EINVAL;
1018 command_flags |= COMMAND_SETFLICKERCTRL;
1019 } else if (MATCH("mains_frequency")) {
1020 if (!retval && MATCH("50")) {
1021 new_mains = 0;
1022 new_params.flickerControl.coarseJump =
1023 flicker_jumps[new_mains]
1024 [new_params.sensorFps.baserate]
1025 [new_params.sensorFps.divisor];
1026 if (new_params.flickerControl.flickerMode)
1027 command_flags |= COMMAND_SETFLICKERCTRL;
1028 } else if (!retval && MATCH("60")) {
1029 new_mains = 1;
1030 new_params.flickerControl.coarseJump =
1031 flicker_jumps[new_mains]
1032 [new_params.sensorFps.baserate]
1033 [new_params.sensorFps.divisor];
1034 if (new_params.flickerControl.flickerMode)
1035 command_flags |= COMMAND_SETFLICKERCTRL;
1036 } else
1037 retval = -EINVAL;
1038 } else if (MATCH("allowable_overexposure")) {
1039 if (!retval)
1040 val = VALUE;
1042 if (!retval) {
1043 if (val <= 0xff) {
1044 new_params.flickerControl.
1045 allowableOverExposure = val;
1046 command_flags |= COMMAND_SETFLICKERCTRL;
1047 } else
1048 retval = -EINVAL;
1050 } else if (MATCH("compression_mode")) {
1051 if (!retval && MATCH("none"))
1052 new_params.compression.mode =
1053 CPIA_COMPRESSION_NONE;
1054 else if (!retval && MATCH("auto"))
1055 new_params.compression.mode =
1056 CPIA_COMPRESSION_AUTO;
1057 else if (!retval && MATCH("manual"))
1058 new_params.compression.mode =
1059 CPIA_COMPRESSION_MANUAL;
1060 else
1061 retval = -EINVAL;
1063 command_flags |= COMMAND_SETCOMPRESSION;
1064 } else if (MATCH("decimation_enable")) {
1065 if (!retval && MATCH("off"))
1066 new_params.compression.decimation = 0;
1067 else
1068 retval = -EINVAL;
1070 command_flags |= COMMAND_SETCOMPRESSION;
1071 } else if (MATCH("compression_target")) {
1072 if (!retval && MATCH("quality"))
1073 new_params.compressionTarget.frTargeting =
1074 CPIA_COMPRESSION_TARGET_QUALITY;
1075 else if (!retval && MATCH("framerate"))
1076 new_params.compressionTarget.frTargeting =
1077 CPIA_COMPRESSION_TARGET_FRAMERATE;
1078 else
1079 retval = -EINVAL;
1081 command_flags |= COMMAND_SETCOMPRESSIONTARGET;
1082 } else if (MATCH("target_framerate")) {
1083 if (!retval)
1084 val = VALUE;
1086 if (!retval)
1087 new_params.compressionTarget.targetFR = val;
1088 command_flags |= COMMAND_SETCOMPRESSIONTARGET;
1089 } else if (MATCH("target_quality")) {
1090 if (!retval)
1091 val = VALUE;
1093 if (!retval)
1094 new_params.compressionTarget.targetQ = val;
1096 command_flags |= COMMAND_SETCOMPRESSIONTARGET;
1097 } else if (MATCH("y_threshold")) {
1098 if (!retval)
1099 val = VALUE;
1101 if (!retval) {
1102 if (val < 32)
1103 new_params.yuvThreshold.yThreshold = val;
1104 else
1105 retval = -EINVAL;
1107 command_flags |= COMMAND_SETYUVTHRESH;
1108 } else if (MATCH("uv_threshold")) {
1109 if (!retval)
1110 val = VALUE;
1112 if (!retval) {
1113 if (val < 32)
1114 new_params.yuvThreshold.uvThreshold = val;
1115 else
1116 retval = -EINVAL;
1118 command_flags |= COMMAND_SETYUVTHRESH;
1119 } else if (MATCH("hysteresis")) {
1120 if (!retval)
1121 val = VALUE;
1123 if (!retval) {
1124 if (val <= 0xff)
1125 new_params.compressionParams.hysteresis = val;
1126 else
1127 retval = -EINVAL;
1129 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1130 } else if (MATCH("threshold_max")) {
1131 if (!retval)
1132 val = VALUE;
1134 if (!retval) {
1135 if (val <= 0xff)
1136 new_params.compressionParams.threshMax = val;
1137 else
1138 retval = -EINVAL;
1140 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1141 } else if (MATCH("small_step")) {
1142 if (!retval)
1143 val = VALUE;
1145 if (!retval) {
1146 if (val <= 0xff)
1147 new_params.compressionParams.smallStep = val;
1148 else
1149 retval = -EINVAL;
1151 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1152 } else if (MATCH("large_step")) {
1153 if (!retval)
1154 val = VALUE;
1156 if (!retval) {
1157 if (val <= 0xff)
1158 new_params.compressionParams.largeStep = val;
1159 else
1160 retval = -EINVAL;
1162 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1163 } else if (MATCH("decimation_hysteresis")) {
1164 if (!retval)
1165 val = VALUE;
1167 if (!retval) {
1168 if (val <= 0xff)
1169 new_params.compressionParams.decimationHysteresis = val;
1170 else
1171 retval = -EINVAL;
1173 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1174 } else if (MATCH("fr_diff_step_thresh")) {
1175 if (!retval)
1176 val = VALUE;
1178 if (!retval) {
1179 if (val <= 0xff)
1180 new_params.compressionParams.frDiffStepThresh = val;
1181 else
1182 retval = -EINVAL;
1184 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1185 } else if (MATCH("q_diff_step_thresh")) {
1186 if (!retval)
1187 val = VALUE;
1189 if (!retval) {
1190 if (val <= 0xff)
1191 new_params.compressionParams.qDiffStepThresh = val;
1192 else
1193 retval = -EINVAL;
1195 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1196 } else if (MATCH("decimation_thresh_mod")) {
1197 if (!retval)
1198 val = VALUE;
1200 if (!retval) {
1201 if (val <= 0xff)
1202 new_params.compressionParams.decimationThreshMod = val;
1203 else
1204 retval = -EINVAL;
1206 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1207 } else {
1208 DBG("No match found\n");
1209 retval = -EINVAL;
1212 if (!retval) {
1213 while (count && isspace(*buffer) && *buffer != '\n') {
1214 --count;
1215 ++buffer;
1217 if (count) {
1218 if (*buffer != '\n' && *buffer != ';')
1219 retval = -EINVAL;
1220 else {
1221 --count;
1222 ++buffer;
1227 #undef MATCH
1228 #undef FIRMWARE_VERSION
1229 #undef VALUE
1230 #undef FIND_VALUE
1231 #undef FIND_END
1232 if (!retval) {
1233 if (command_flags & COMMAND_SETCOLOURPARAMS) {
1234 /* Adjust cam->vp to reflect these changes */
1235 cam->vp.brightness =
1236 new_params.colourParams.brightness*65535/100;
1237 cam->vp.contrast =
1238 new_params.colourParams.contrast*65535/100;
1239 cam->vp.colour =
1240 new_params.colourParams.saturation*65535/100;
1243 memcpy(&cam->params, &new_params, sizeof(struct cam_params));
1244 cam->mainsFreq = new_mains;
1245 cam->cmd_queue |= command_flags;
1246 retval = size;
1247 } else
1248 DBG("error: %d\n", retval);
1250 up(&cam->param_lock);
1252 return retval;
1255 static void create_proc_cpia_cam(struct cam_data *cam)
1257 char name[7];
1258 struct proc_dir_entry *ent;
1260 if (!cpia_proc_root || !cam)
1261 return;
1263 sprintf(name, "video%d", cam->vdev.minor);
1265 ent = create_proc_entry(name, S_IFREG|S_IRUGO|S_IWUSR, cpia_proc_root);
1266 if (!ent)
1267 return;
1269 ent->data = cam;
1270 ent->read_proc = cpia_read_proc;
1271 ent->write_proc = cpia_write_proc;
1272 ent->size = 3626;
1273 cam->proc_entry = ent;
1276 static void destroy_proc_cpia_cam(struct cam_data *cam)
1278 char name[7];
1280 if (!cam || !cam->proc_entry)
1281 return;
1283 sprintf(name, "video%d", cam->vdev.minor);
1284 remove_proc_entry(name, cpia_proc_root);
1285 cam->proc_entry = NULL;
1288 static void proc_cpia_create(void)
1290 cpia_proc_root = create_proc_entry("cpia", S_IFDIR, 0);
1292 if (cpia_proc_root)
1293 cpia_proc_root->owner = THIS_MODULE;
1294 else
1295 LOG("Unable to initialise /proc/cpia\n");
1298 static void proc_cpia_destroy(void)
1300 remove_proc_entry("cpia", 0);
1302 #endif /* CONFIG_PROC_FS */
1304 /* ----------------------- debug functions ---------------------- */
1306 #define printstatus(cam) \
1307 DBG("%02x %02x %02x %02x %02x %02x %02x %02x\n",\
1308 cam->params.status.systemState, cam->params.status.grabState, \
1309 cam->params.status.streamState, cam->params.status.fatalError, \
1310 cam->params.status.cmdError, cam->params.status.debugFlags, \
1311 cam->params.status.vpStatus, cam->params.status.errorCode);
1313 /* ----------------------- v4l helpers -------------------------- */
1315 /* supported frame palettes and depths */
1316 static inline int valid_mode(u16 palette, u16 depth)
1318 return (palette == VIDEO_PALETTE_GREY && depth == 8) ||
1319 (palette == VIDEO_PALETTE_RGB555 && depth == 16) ||
1320 (palette == VIDEO_PALETTE_RGB565 && depth == 16) ||
1321 (palette == VIDEO_PALETTE_RGB24 && depth == 24) ||
1322 (palette == VIDEO_PALETTE_RGB32 && depth == 32) ||
1323 (palette == VIDEO_PALETTE_YUV422 && depth == 16) ||
1324 (palette == VIDEO_PALETTE_YUYV && depth == 16) ||
1325 (palette == VIDEO_PALETTE_UYVY && depth == 16);
1328 static int match_videosize( int width, int height )
1330 /* return the best match, where 'best' is as always
1331 * the largest that is not bigger than what is requested. */
1332 if (width>=352 && height>=288)
1333 return VIDEOSIZE_352_288; /* CIF */
1335 if (width>=320 && height>=240)
1336 return VIDEOSIZE_320_240; /* SIF */
1338 if (width>=288 && height>=216)
1339 return VIDEOSIZE_288_216;
1341 if (width>=256 && height>=192)
1342 return VIDEOSIZE_256_192;
1344 if (width>=224 && height>=168)
1345 return VIDEOSIZE_224_168;
1347 if (width>=192 && height>=144)
1348 return VIDEOSIZE_192_144;
1350 if (width>=176 && height>=144)
1351 return VIDEOSIZE_176_144; /* QCIF */
1353 if (width>=160 && height>=120)
1354 return VIDEOSIZE_160_120; /* QSIF */
1356 if (width>=128 && height>=96)
1357 return VIDEOSIZE_128_96;
1359 if (width>=88 && height>=72)
1360 return VIDEOSIZE_88_72;
1362 if (width>=64 && height>=48)
1363 return VIDEOSIZE_64_48;
1365 if (width>=48 && height>=48)
1366 return VIDEOSIZE_48_48;
1368 return -1;
1371 /* these are the capture sizes we support */
1372 static void set_vw_size(struct cam_data *cam)
1374 /* the col/row/start/end values are the result of simple math */
1375 /* study the SetROI-command in cpia developers guide p 2-22 */
1376 /* streamStartLine is set to the recommended value in the cpia */
1377 /* developers guide p 3-37 */
1378 switch(cam->video_size) {
1379 case VIDEOSIZE_CIF:
1380 cam->vw.width = 352;
1381 cam->vw.height = 288;
1382 cam->params.format.videoSize=VIDEOSIZE_CIF;
1383 cam->params.roi.colStart=0;
1384 cam->params.roi.colEnd=44;
1385 cam->params.roi.rowStart=0;
1386 cam->params.roi.rowEnd=72;
1387 cam->params.streamStartLine = 120;
1388 break;
1389 case VIDEOSIZE_SIF:
1390 cam->vw.width = 320;
1391 cam->vw.height = 240;
1392 cam->params.format.videoSize=VIDEOSIZE_CIF;
1393 cam->params.roi.colStart=2;
1394 cam->params.roi.colEnd=42;
1395 cam->params.roi.rowStart=6;
1396 cam->params.roi.rowEnd=66;
1397 cam->params.streamStartLine = 120;
1398 break;
1399 case VIDEOSIZE_288_216:
1400 cam->vw.width = 288;
1401 cam->vw.height = 216;
1402 cam->params.format.videoSize=VIDEOSIZE_CIF;
1403 cam->params.roi.colStart=4;
1404 cam->params.roi.colEnd=40;
1405 cam->params.roi.rowStart=9;
1406 cam->params.roi.rowEnd=63;
1407 cam->params.streamStartLine = 120;
1408 break;
1409 case VIDEOSIZE_256_192:
1410 cam->vw.width = 256;
1411 cam->vw.height = 192;
1412 cam->params.format.videoSize=VIDEOSIZE_CIF;
1413 cam->params.roi.colStart=6;
1414 cam->params.roi.colEnd=38;
1415 cam->params.roi.rowStart=12;
1416 cam->params.roi.rowEnd=60;
1417 cam->params.streamStartLine = 120;
1418 break;
1419 case VIDEOSIZE_224_168:
1420 cam->vw.width = 224;
1421 cam->vw.height = 168;
1422 cam->params.format.videoSize=VIDEOSIZE_CIF;
1423 cam->params.roi.colStart=8;
1424 cam->params.roi.colEnd=36;
1425 cam->params.roi.rowStart=15;
1426 cam->params.roi.rowEnd=57;
1427 cam->params.streamStartLine = 120;
1428 break;
1429 case VIDEOSIZE_192_144:
1430 cam->vw.width = 192;
1431 cam->vw.height = 144;
1432 cam->params.format.videoSize=VIDEOSIZE_CIF;
1433 cam->params.roi.colStart=10;
1434 cam->params.roi.colEnd=34;
1435 cam->params.roi.rowStart=18;
1436 cam->params.roi.rowEnd=54;
1437 cam->params.streamStartLine = 120;
1438 break;
1439 case VIDEOSIZE_QCIF:
1440 cam->vw.width = 176;
1441 cam->vw.height = 144;
1442 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1443 cam->params.roi.colStart=0;
1444 cam->params.roi.colEnd=22;
1445 cam->params.roi.rowStart=0;
1446 cam->params.roi.rowEnd=36;
1447 cam->params.streamStartLine = 60;
1448 break;
1449 case VIDEOSIZE_QSIF:
1450 cam->vw.width = 160;
1451 cam->vw.height = 120;
1452 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1453 cam->params.roi.colStart=1;
1454 cam->params.roi.colEnd=21;
1455 cam->params.roi.rowStart=3;
1456 cam->params.roi.rowEnd=33;
1457 cam->params.streamStartLine = 60;
1458 break;
1459 case VIDEOSIZE_128_96:
1460 cam->vw.width = 128;
1461 cam->vw.height = 96;
1462 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1463 cam->params.roi.colStart=3;
1464 cam->params.roi.colEnd=19;
1465 cam->params.roi.rowStart=6;
1466 cam->params.roi.rowEnd=30;
1467 cam->params.streamStartLine = 60;
1468 break;
1469 case VIDEOSIZE_88_72:
1470 cam->vw.width = 88;
1471 cam->vw.height = 72;
1472 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1473 cam->params.roi.colStart=5;
1474 cam->params.roi.colEnd=16;
1475 cam->params.roi.rowStart=9;
1476 cam->params.roi.rowEnd=27;
1477 cam->params.streamStartLine = 60;
1478 break;
1479 case VIDEOSIZE_64_48:
1480 cam->vw.width = 64;
1481 cam->vw.height = 48;
1482 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1483 cam->params.roi.colStart=7;
1484 cam->params.roi.colEnd=15;
1485 cam->params.roi.rowStart=12;
1486 cam->params.roi.rowEnd=24;
1487 cam->params.streamStartLine = 60;
1488 break;
1489 case VIDEOSIZE_48_48:
1490 cam->vw.width = 48;
1491 cam->vw.height = 48;
1492 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1493 cam->params.roi.colStart=8;
1494 cam->params.roi.colEnd=14;
1495 cam->params.roi.rowStart=6;
1496 cam->params.roi.rowEnd=30;
1497 cam->params.streamStartLine = 60;
1498 break;
1499 default:
1500 LOG("bad videosize value: %d\n", cam->video_size);
1503 return;
1506 static int allocate_frame_buf(struct cam_data *cam)
1508 int i;
1510 cam->frame_buf = rvmalloc(FRAME_NUM * CPIA_MAX_FRAME_SIZE);
1511 if (!cam->frame_buf)
1512 return -ENOBUFS;
1514 for (i = 0; i < FRAME_NUM; i++)
1515 cam->frame[i].data = cam->frame_buf + i * CPIA_MAX_FRAME_SIZE;
1517 return 0;
1520 static int free_frame_buf(struct cam_data *cam)
1522 int i;
1524 rvfree(cam->frame_buf, FRAME_NUM*CPIA_MAX_FRAME_SIZE);
1525 cam->frame_buf = 0;
1526 for (i=0; i < FRAME_NUM; i++)
1527 cam->frame[i].data = NULL;
1529 return 0;
1533 static void inline free_frames(struct cpia_frame frame[FRAME_NUM])
1535 int i;
1537 for (i=0; i < FRAME_NUM; i++)
1538 frame[i].state = FRAME_UNUSED;
1539 return;
1542 /**********************************************************************
1544 * General functions
1546 **********************************************************************/
1547 /* send an arbitrary command to the camera */
1548 static int do_command(struct cam_data *cam, u16 command, u8 a, u8 b, u8 c, u8 d)
1550 int retval, datasize;
1551 u8 cmd[8], data[8];
1553 switch(command) {
1554 case CPIA_COMMAND_GetCPIAVersion:
1555 case CPIA_COMMAND_GetPnPID:
1556 case CPIA_COMMAND_GetCameraStatus:
1557 case CPIA_COMMAND_GetVPVersion:
1558 datasize=8;
1559 break;
1560 case CPIA_COMMAND_GetColourParams:
1561 case CPIA_COMMAND_GetColourBalance:
1562 case CPIA_COMMAND_GetExposure:
1563 down(&cam->param_lock);
1564 datasize=8;
1565 break;
1566 default:
1567 datasize=0;
1568 break;
1571 cmd[0] = command>>8;
1572 cmd[1] = command&0xff;
1573 cmd[2] = a;
1574 cmd[3] = b;
1575 cmd[4] = c;
1576 cmd[5] = d;
1577 cmd[6] = datasize;
1578 cmd[7] = 0;
1580 retval = cam->ops->transferCmd(cam->lowlevel_data, cmd, data);
1581 if (retval) {
1582 DBG("%x - failed, retval=%d\n", command, retval);
1583 if (command == CPIA_COMMAND_GetColourParams ||
1584 command == CPIA_COMMAND_GetColourBalance ||
1585 command == CPIA_COMMAND_GetExposure)
1586 up(&cam->param_lock);
1587 } else {
1588 switch(command) {
1589 case CPIA_COMMAND_GetCPIAVersion:
1590 cam->params.version.firmwareVersion = data[0];
1591 cam->params.version.firmwareRevision = data[1];
1592 cam->params.version.vcVersion = data[2];
1593 cam->params.version.vcRevision = data[3];
1594 break;
1595 case CPIA_COMMAND_GetPnPID:
1596 cam->params.pnpID.vendor = data[0]+(((u16)data[1])<<8);
1597 cam->params.pnpID.product = data[2]+(((u16)data[3])<<8);
1598 cam->params.pnpID.deviceRevision =
1599 data[4]+(((u16)data[5])<<8);
1600 break;
1601 case CPIA_COMMAND_GetCameraStatus:
1602 cam->params.status.systemState = data[0];
1603 cam->params.status.grabState = data[1];
1604 cam->params.status.streamState = data[2];
1605 cam->params.status.fatalError = data[3];
1606 cam->params.status.cmdError = data[4];
1607 cam->params.status.debugFlags = data[5];
1608 cam->params.status.vpStatus = data[6];
1609 cam->params.status.errorCode = data[7];
1610 break;
1611 case CPIA_COMMAND_GetVPVersion:
1612 cam->params.vpVersion.vpVersion = data[0];
1613 cam->params.vpVersion.vpRevision = data[1];
1614 cam->params.vpVersion.cameraHeadID =
1615 data[2]+(((u16)data[3])<<8);
1616 break;
1617 case CPIA_COMMAND_GetColourParams:
1618 cam->params.colourParams.brightness = data[0];
1619 cam->params.colourParams.contrast = data[1];
1620 cam->params.colourParams.saturation = data[2];
1621 up(&cam->param_lock);
1622 break;
1623 case CPIA_COMMAND_GetColourBalance:
1624 cam->params.colourBalance.redGain = data[0];
1625 cam->params.colourBalance.greenGain = data[1];
1626 cam->params.colourBalance.blueGain = data[2];
1627 up(&cam->param_lock);
1628 break;
1629 case CPIA_COMMAND_GetExposure:
1630 cam->params.exposure.gain = data[0];
1631 cam->params.exposure.fineExp = data[1];
1632 cam->params.exposure.coarseExpLo = data[2];
1633 cam->params.exposure.coarseExpHi = data[3];
1634 cam->params.exposure.redComp = data[4];
1635 cam->params.exposure.green1Comp = data[5];
1636 cam->params.exposure.green2Comp = data[6];
1637 cam->params.exposure.blueComp = data[7];
1638 /* If the *Comp parameters are wacko, generate
1639 * a warning, and reset them back to default
1640 * values. - rich@annexia.org
1642 if (cam->params.exposure.redComp < 220 ||
1643 cam->params.exposure.redComp > 255 ||
1644 cam->params.exposure.green1Comp < 214 ||
1645 cam->params.exposure.green1Comp > 255 ||
1646 cam->params.exposure.green2Comp < 214 ||
1647 cam->params.exposure.green2Comp > 255 ||
1648 cam->params.exposure.blueComp < 230 ||
1649 cam->params.exposure.blueComp > 255)
1651 printk (KERN_WARNING "*_comp parameters have gone AWOL (%d/%d/%d/%d) - reseting them\n",
1652 cam->params.exposure.redComp,
1653 cam->params.exposure.green1Comp,
1654 cam->params.exposure.green2Comp,
1655 cam->params.exposure.blueComp);
1656 cam->params.exposure.redComp = 220;
1657 cam->params.exposure.green1Comp = 214;
1658 cam->params.exposure.green2Comp = 214;
1659 cam->params.exposure.blueComp = 230;
1661 up(&cam->param_lock);
1662 break;
1663 default:
1664 break;
1667 return retval;
1670 /* send a command to the camera with an additional data transaction */
1671 static int do_command_extended(struct cam_data *cam, u16 command,
1672 u8 a, u8 b, u8 c, u8 d,
1673 u8 e, u8 f, u8 g, u8 h,
1674 u8 i, u8 j, u8 k, u8 l)
1676 int retval;
1677 u8 cmd[8], data[8];
1679 cmd[0] = command>>8;
1680 cmd[1] = command&0xff;
1681 cmd[2] = a;
1682 cmd[3] = b;
1683 cmd[4] = c;
1684 cmd[5] = d;
1685 cmd[6] = 8;
1686 cmd[7] = 0;
1687 data[0] = e;
1688 data[1] = f;
1689 data[2] = g;
1690 data[3] = h;
1691 data[4] = i;
1692 data[5] = j;
1693 data[6] = k;
1694 data[7] = l;
1696 retval = cam->ops->transferCmd(cam->lowlevel_data, cmd, data);
1697 if (retval)
1698 LOG("%x - failed\n", command);
1700 return retval;
1703 /**********************************************************************
1705 * Colorspace conversion
1707 **********************************************************************/
1708 #define LIMIT(x) ((((x)>0xffffff)?0xff0000:(((x)<=0xffff)?0:(x)&0xff0000))>>16)
1710 static int yuvconvert(unsigned char *yuv, unsigned char *rgb, int out_fmt,
1711 int in_uyvy, int mmap_kludge)
1713 int y, u, v, r, g, b, y1;
1715 switch(out_fmt) {
1716 case VIDEO_PALETTE_RGB555:
1717 case VIDEO_PALETTE_RGB565:
1718 case VIDEO_PALETTE_RGB24:
1719 case VIDEO_PALETTE_RGB32:
1720 if (in_uyvy) {
1721 u = *yuv++ - 128;
1722 y = (*yuv++ - 16) * 76310;
1723 v = *yuv++ - 128;
1724 y1 = (*yuv - 16) * 76310;
1725 } else {
1726 y = (*yuv++ - 16) * 76310;
1727 u = *yuv++ - 128;
1728 y1 = (*yuv++ - 16) * 76310;
1729 v = *yuv - 128;
1731 r = 104635 * v;
1732 g = -25690 * u + -53294 * v;
1733 b = 132278 * u;
1734 break;
1735 default:
1736 y = *yuv++;
1737 u = *yuv++;
1738 y1 = *yuv++;
1739 v = *yuv;
1740 /* Just to avoid compiler warnings */
1741 r = 0;
1742 g = 0;
1743 b = 0;
1744 break;
1746 switch(out_fmt) {
1747 case VIDEO_PALETTE_RGB555:
1748 *rgb++ = ((LIMIT(g+y) & 0xf8) << 2) | (LIMIT(b+y) >> 3);
1749 *rgb++ = ((LIMIT(r+y) & 0xf8) >> 1) | (LIMIT(g+y) >> 6);
1750 *rgb++ = ((LIMIT(g+y1) & 0xf8) << 2) | (LIMIT(b+y1) >> 3);
1751 *rgb = ((LIMIT(r+y1) & 0xf8) >> 1) | (LIMIT(g+y1) >> 6);
1752 return 4;
1753 case VIDEO_PALETTE_RGB565:
1754 *rgb++ = ((LIMIT(g+y) & 0xfc) << 3) | (LIMIT(b+y) >> 3);
1755 *rgb++ = (LIMIT(r+y) & 0xf8) | (LIMIT(g+y) >> 5);
1756 *rgb++ = ((LIMIT(g+y1) & 0xfc) << 3) | (LIMIT(b+y1) >> 3);
1757 *rgb = (LIMIT(r+y1) & 0xf8) | (LIMIT(g+y1) >> 5);
1758 return 4;
1759 case VIDEO_PALETTE_RGB24:
1760 if (mmap_kludge) {
1761 *rgb++ = LIMIT(b+y);
1762 *rgb++ = LIMIT(g+y);
1763 *rgb++ = LIMIT(r+y);
1764 *rgb++ = LIMIT(b+y1);
1765 *rgb++ = LIMIT(g+y1);
1766 *rgb = LIMIT(r+y1);
1767 } else {
1768 *rgb++ = LIMIT(r+y);
1769 *rgb++ = LIMIT(g+y);
1770 *rgb++ = LIMIT(b+y);
1771 *rgb++ = LIMIT(r+y1);
1772 *rgb++ = LIMIT(g+y1);
1773 *rgb = LIMIT(b+y1);
1775 return 6;
1776 case VIDEO_PALETTE_RGB32:
1777 if (mmap_kludge) {
1778 *rgb++ = LIMIT(b+y);
1779 *rgb++ = LIMIT(g+y);
1780 *rgb++ = LIMIT(r+y);
1781 rgb++;
1782 *rgb++ = LIMIT(b+y1);
1783 *rgb++ = LIMIT(g+y1);
1784 *rgb = LIMIT(r+y1);
1785 } else {
1786 *rgb++ = LIMIT(r+y);
1787 *rgb++ = LIMIT(g+y);
1788 *rgb++ = LIMIT(b+y);
1789 rgb++;
1790 *rgb++ = LIMIT(r+y1);
1791 *rgb++ = LIMIT(g+y1);
1792 *rgb = LIMIT(b+y1);
1794 return 8;
1795 case VIDEO_PALETTE_GREY:
1796 *rgb++ = y;
1797 *rgb = y1;
1798 return 2;
1799 case VIDEO_PALETTE_YUV422:
1800 case VIDEO_PALETTE_YUYV:
1801 *rgb++ = y;
1802 *rgb++ = u;
1803 *rgb++ = y1;
1804 *rgb = v;
1805 return 4;
1806 case VIDEO_PALETTE_UYVY:
1807 *rgb++ = u;
1808 *rgb++ = y;
1809 *rgb++ = v;
1810 *rgb = y1;
1811 return 4;
1812 default:
1813 DBG("Empty: %d\n", out_fmt);
1814 return 0;
1818 static int skipcount(int count, int fmt)
1820 switch(fmt) {
1821 case VIDEO_PALETTE_GREY:
1822 case VIDEO_PALETTE_RGB555:
1823 case VIDEO_PALETTE_RGB565:
1824 case VIDEO_PALETTE_YUV422:
1825 case VIDEO_PALETTE_YUYV:
1826 case VIDEO_PALETTE_UYVY:
1827 return 2*count;
1828 case VIDEO_PALETTE_RGB24:
1829 return 3*count;
1830 case VIDEO_PALETTE_RGB32:
1831 return 4*count;
1832 default:
1833 return 0;
1837 static int parse_picture(struct cam_data *cam, int size)
1839 u8 *obuf, *ibuf, *end_obuf;
1840 int ll, in_uyvy, compressed, origsize, out_fmt;
1842 /* make sure params don't change while we are decoding */
1843 down(&cam->param_lock);
1845 obuf = cam->decompressed_frame.data;
1846 end_obuf = obuf+CPIA_MAX_FRAME_SIZE;
1847 ibuf = cam->raw_image;
1848 origsize = size;
1849 out_fmt = cam->vp.palette;
1851 if ((ibuf[0] != MAGIC_0) || (ibuf[1] != MAGIC_1)) {
1852 LOG("header not found\n");
1853 up(&cam->param_lock);
1854 return -1;
1857 if ((ibuf[16] != VIDEOSIZE_QCIF) && (ibuf[16] != VIDEOSIZE_CIF)) {
1858 LOG("wrong video size\n");
1859 up(&cam->param_lock);
1860 return -1;
1863 if (ibuf[17] != SUBSAMPLE_422) {
1864 LOG("illegal subtype %d\n",ibuf[17]);
1865 up(&cam->param_lock);
1866 return -1;
1869 if (ibuf[18] != YUVORDER_YUYV && ibuf[18] != YUVORDER_UYVY) {
1870 LOG("illegal yuvorder %d\n",ibuf[18]);
1871 up(&cam->param_lock);
1872 return -1;
1874 in_uyvy = ibuf[18] == YUVORDER_UYVY;
1876 #if 0
1877 /* FIXME: ROI mismatch occurs when switching capture sizes */
1878 if ((ibuf[24] != cam->params.roi.colStart) ||
1879 (ibuf[25] != cam->params.roi.colEnd) ||
1880 (ibuf[26] != cam->params.roi.rowStart) ||
1881 (ibuf[27] != cam->params.roi.rowEnd)) {
1882 LOG("ROI mismatch\n");
1883 up(&cam->param_lock);
1884 return -1;
1886 #endif
1888 if ((ibuf[28] != NOT_COMPRESSED) && (ibuf[28] != COMPRESSED)) {
1889 LOG("illegal compression %d\n",ibuf[28]);
1890 up(&cam->param_lock);
1891 return -1;
1893 compressed = (ibuf[28] == COMPRESSED);
1895 if (ibuf[29] != NO_DECIMATION) {
1896 LOG("decimation not supported\n");
1897 up(&cam->param_lock);
1898 return -1;
1901 cam->params.yuvThreshold.yThreshold = ibuf[30];
1902 cam->params.yuvThreshold.uvThreshold = ibuf[31];
1903 cam->params.status.systemState = ibuf[32];
1904 cam->params.status.grabState = ibuf[33];
1905 cam->params.status.streamState = ibuf[34];
1906 cam->params.status.fatalError = ibuf[35];
1907 cam->params.status.cmdError = ibuf[36];
1908 cam->params.status.debugFlags = ibuf[37];
1909 cam->params.status.vpStatus = ibuf[38];
1910 cam->params.status.errorCode = ibuf[39];
1911 cam->fps = ibuf[41];
1912 up(&cam->param_lock);
1914 ibuf += FRAME_HEADER_SIZE;
1915 size -= FRAME_HEADER_SIZE;
1916 ll = ibuf[0] | (ibuf[1] << 8);
1917 ibuf += 2;
1919 while (size > 0) {
1920 size -= (ll+2);
1921 if (size < 0) {
1922 LOG("Insufficient data in buffer\n");
1923 return -1;
1926 while (ll > 1) {
1927 if (!compressed || (compressed && !(*ibuf & 1))) {
1928 obuf += yuvconvert(ibuf, obuf, out_fmt,
1929 in_uyvy, cam->mmap_kludge);
1930 ibuf += 4;
1931 ll -= 4;
1932 } else {
1933 /*skip compressed interval from previous frame*/
1934 int skipsize = skipcount(*ibuf >> 1, out_fmt);
1935 obuf += skipsize;
1936 if (obuf > end_obuf) {
1937 LOG("Insufficient data in buffer\n");
1938 return -1;
1940 ++ibuf;
1941 ll--;
1944 if (ll == 1) {
1945 if (*ibuf != EOL) {
1946 LOG("EOL not found giving up after %d/%d"
1947 " bytes\n", origsize-size, origsize);
1948 return -1;
1951 ibuf++; /* skip over EOL */
1953 if ((size > 3) && (ibuf[0] == EOI) && (ibuf[1] == EOI) &&
1954 (ibuf[2] == EOI) && (ibuf[3] == EOI)) {
1955 size -= 4;
1956 break;
1959 if (size > 1) {
1960 ll = ibuf[0] | (ibuf[1] << 8);
1961 ibuf += 2; /* skip over line length */
1963 } else {
1964 LOG("line length was not 1 but %d after %d/%d bytes\n",
1965 ll, origsize-size, origsize);
1966 return -1;
1970 cam->decompressed_frame.count = obuf-cam->decompressed_frame.data;
1972 return cam->decompressed_frame.count;
1975 /* InitStreamCap wrapper to select correct start line */
1976 static inline int init_stream_cap(struct cam_data *cam)
1978 return do_command(cam, CPIA_COMMAND_InitStreamCap,
1979 0, cam->params.streamStartLine, 0, 0);
1982 /* update various camera modes and settings */
1983 static void dispatch_commands(struct cam_data *cam)
1985 down(&cam->param_lock);
1986 if (cam->cmd_queue==COMMAND_NONE) {
1987 up(&cam->param_lock);
1988 return;
1990 DEB_BYTE(cam->cmd_queue);
1991 DEB_BYTE(cam->cmd_queue>>8);
1992 if (cam->cmd_queue & COMMAND_SETCOLOURPARAMS)
1993 do_command(cam, CPIA_COMMAND_SetColourParams,
1994 cam->params.colourParams.brightness,
1995 cam->params.colourParams.contrast,
1996 cam->params.colourParams.saturation, 0);
1998 if (cam->cmd_queue & COMMAND_SETCOMPRESSION)
1999 do_command(cam, CPIA_COMMAND_SetCompression,
2000 cam->params.compression.mode,
2001 cam->params.compression.decimation, 0, 0);
2003 if (cam->cmd_queue & COMMAND_SETFORMAT) {
2004 do_command(cam, CPIA_COMMAND_SetFormat,
2005 cam->params.format.videoSize,
2006 cam->params.format.subSample,
2007 cam->params.format.yuvOrder, 0);
2008 do_command(cam, CPIA_COMMAND_SetROI,
2009 cam->params.roi.colStart, cam->params.roi.colEnd,
2010 cam->params.roi.rowStart, cam->params.roi.rowEnd);
2011 cam->first_frame = 1;
2014 if (cam->cmd_queue & COMMAND_SETCOMPRESSIONTARGET)
2015 do_command(cam, CPIA_COMMAND_SetCompressionTarget,
2016 cam->params.compressionTarget.frTargeting,
2017 cam->params.compressionTarget.targetFR,
2018 cam->params.compressionTarget.targetQ, 0);
2020 if (cam->cmd_queue & COMMAND_SETYUVTHRESH)
2021 do_command(cam, CPIA_COMMAND_SetYUVThresh,
2022 cam->params.yuvThreshold.yThreshold,
2023 cam->params.yuvThreshold.uvThreshold, 0, 0);
2025 if (cam->cmd_queue & COMMAND_SETECPTIMING)
2026 do_command(cam, CPIA_COMMAND_SetECPTiming,
2027 cam->params.ecpTiming, 0, 0, 0);
2029 if (cam->cmd_queue & COMMAND_SETCOMPRESSIONPARAMS)
2030 do_command_extended(cam, CPIA_COMMAND_SetCompressionParams,
2031 0, 0, 0, 0,
2032 cam->params.compressionParams.hysteresis,
2033 cam->params.compressionParams.threshMax,
2034 cam->params.compressionParams.smallStep,
2035 cam->params.compressionParams.largeStep,
2036 cam->params.compressionParams.decimationHysteresis,
2037 cam->params.compressionParams.frDiffStepThresh,
2038 cam->params.compressionParams.qDiffStepThresh,
2039 cam->params.compressionParams.decimationThreshMod);
2041 if (cam->cmd_queue & COMMAND_SETEXPOSURE)
2042 do_command_extended(cam, CPIA_COMMAND_SetExposure,
2043 cam->params.exposure.gainMode,
2044 cam->params.exposure.expMode,
2045 cam->params.exposure.compMode,
2046 cam->params.exposure.centreWeight,
2047 cam->params.exposure.gain,
2048 cam->params.exposure.fineExp,
2049 cam->params.exposure.coarseExpLo,
2050 cam->params.exposure.coarseExpHi,
2051 cam->params.exposure.redComp,
2052 cam->params.exposure.green1Comp,
2053 cam->params.exposure.green2Comp,
2054 cam->params.exposure.blueComp);
2056 if (cam->cmd_queue & COMMAND_SETCOLOURBALANCE) {
2057 if (cam->params.colourBalance.balanceModeIsAuto) {
2058 do_command(cam, CPIA_COMMAND_SetColourBalance,
2059 2, 0, 0, 0);
2060 } else {
2061 do_command(cam, CPIA_COMMAND_SetColourBalance,
2063 cam->params.colourBalance.redGain,
2064 cam->params.colourBalance.greenGain,
2065 cam->params.colourBalance.blueGain);
2066 do_command(cam, CPIA_COMMAND_SetColourBalance,
2067 3, 0, 0, 0);
2071 if (cam->cmd_queue & COMMAND_SETSENSORFPS)
2072 do_command(cam, CPIA_COMMAND_SetSensorFPS,
2073 cam->params.sensorFps.divisor,
2074 cam->params.sensorFps.baserate, 0, 0);
2076 if (cam->cmd_queue & COMMAND_SETAPCOR)
2077 do_command(cam, CPIA_COMMAND_SetApcor,
2078 cam->params.apcor.gain1,
2079 cam->params.apcor.gain2,
2080 cam->params.apcor.gain4,
2081 cam->params.apcor.gain8);
2083 if (cam->cmd_queue & COMMAND_SETFLICKERCTRL)
2084 do_command(cam, CPIA_COMMAND_SetFlickerCtrl,
2085 cam->params.flickerControl.flickerMode,
2086 cam->params.flickerControl.coarseJump,
2087 cam->params.flickerControl.allowableOverExposure, 0);
2089 if (cam->cmd_queue & COMMAND_SETVLOFFSET)
2090 do_command(cam, CPIA_COMMAND_SetVLOffset,
2091 cam->params.vlOffset.gain1,
2092 cam->params.vlOffset.gain2,
2093 cam->params.vlOffset.gain4,
2094 cam->params.vlOffset.gain8);
2096 if (cam->cmd_queue & COMMAND_PAUSE)
2097 do_command(cam, CPIA_COMMAND_EndStreamCap, 0, 0, 0, 0);
2099 if (cam->cmd_queue & COMMAND_RESUME)
2100 init_stream_cap(cam);
2102 up(&cam->param_lock);
2103 cam->cmd_queue = COMMAND_NONE;
2104 return;
2107 /* kernel thread function to read image from camera */
2108 static void fetch_frame(void *data)
2110 int image_size, retry;
2111 struct cam_data *cam = (struct cam_data *)data;
2112 unsigned long oldjif, rate, diff;
2114 /* Allow up to two bad images in a row to be read and
2115 * ignored before an error is reported */
2116 for (retry = 0; retry < 3; ++retry) {
2117 if (retry)
2118 DBG("retry=%d\n", retry);
2120 if (!cam->ops)
2121 continue;
2123 /* load first frame always uncompressed */
2124 if (cam->first_frame &&
2125 cam->params.compression.mode != CPIA_COMPRESSION_NONE)
2126 do_command(cam, CPIA_COMMAND_SetCompression,
2127 CPIA_COMPRESSION_NONE,
2128 NO_DECIMATION, 0, 0);
2130 /* init camera upload */
2131 if (do_command(cam, CPIA_COMMAND_SetGrabMode,
2132 CPIA_GRAB_CONTINUOUS, 0, 0, 0))
2133 continue;
2135 if (do_command(cam, CPIA_COMMAND_GrabFrame, 0,
2136 cam->params.streamStartLine, 0, 0))
2137 continue;
2139 if (cam->ops->wait_for_stream_ready) {
2140 /* loop until image ready */
2141 do_command(cam, CPIA_COMMAND_GetCameraStatus,0,0,0,0);
2142 while (cam->params.status.streamState != STREAM_READY) {
2143 if (current->need_resched)
2144 schedule();
2146 current->state = TASK_INTERRUPTIBLE;
2148 /* sleep for 10 ms, hopefully ;) */
2149 schedule_timeout(10*HZ/1000);
2150 if (signal_pending(current))
2151 return;
2153 do_command(cam, CPIA_COMMAND_GetCameraStatus,
2154 0, 0, 0, 0);
2158 /* grab image from camera */
2159 if (current->need_resched)
2160 schedule();
2162 oldjif = jiffies;
2163 image_size = cam->ops->streamRead(cam->lowlevel_data,
2164 cam->raw_image, 0);
2165 if (image_size <= 0) {
2166 DBG("streamRead failed: %d\n", image_size);
2167 continue;
2170 rate = image_size * HZ / 1024;
2171 diff = jiffies-oldjif;
2172 cam->transfer_rate = diff==0 ? rate : rate/diff;
2173 /* diff==0 ? unlikely but possible */
2175 /* camera idle now so dispatch queued commands */
2176 dispatch_commands(cam);
2178 /* Update our knowledge of the camera state - FIXME: necessary? */
2179 do_command(cam, CPIA_COMMAND_GetColourBalance, 0, 0, 0, 0);
2180 do_command(cam, CPIA_COMMAND_GetExposure, 0, 0, 0, 0);
2182 /* decompress and convert image to by copying it from
2183 * raw_image to decompressed_frame
2185 if (current->need_resched)
2186 schedule();
2188 cam->image_size = parse_picture(cam, image_size);
2189 if (cam->image_size <= 0)
2190 DBG("parse_picture failed %d\n", cam->image_size);
2191 else
2192 break;
2195 if (retry < 3) {
2196 /* FIXME: this only works for double buffering */
2197 if (cam->frame[cam->curframe].state == FRAME_READY) {
2198 memcpy(cam->frame[cam->curframe].data,
2199 cam->decompressed_frame.data,
2200 cam->decompressed_frame.count);
2201 cam->frame[cam->curframe].state = FRAME_DONE;
2202 } else
2203 cam->decompressed_frame.state = FRAME_DONE;
2205 #if 0
2206 if (cam->first_frame &&
2207 cam->params.compression.mode != CPIA_COMPRESSION_NONE) {
2208 cam->first_frame = 0;
2209 cam->cmd_queue |= COMMAND_SETCOMPRESSION;
2211 #else
2212 if (cam->first_frame) {
2213 cam->first_frame = 0;
2214 cam->cmd_queue |= COMMAND_SETCOMPRESSION;
2215 cam->cmd_queue |= COMMAND_SETEXPOSURE;
2217 #endif
2221 static int capture_frame(struct cam_data *cam, struct video_mmap *vm)
2223 int retval = 0;
2225 if (!cam->frame_buf) {
2226 /* we do lazy allocation */
2227 if ((retval = allocate_frame_buf(cam)))
2228 return retval;
2231 /* FIXME: the first frame seems to be captured by the camera
2232 without regards to any initial settings, so we throw away
2233 that one, the next one is generated with our settings
2234 (exposure, color balance, ...)
2236 if (cam->first_frame) {
2237 cam->curframe = vm->frame;
2238 cam->frame[cam->curframe].state = FRAME_READY;
2239 fetch_frame(cam);
2240 if (cam->frame[cam->curframe].state != FRAME_DONE)
2241 retval = -EIO;
2243 cam->curframe = vm->frame;
2244 cam->frame[cam->curframe].state = FRAME_READY;
2245 fetch_frame(cam);
2246 if (cam->frame[cam->curframe].state != FRAME_DONE)
2247 retval=-EIO;
2249 return retval;
2252 static int goto_high_power(struct cam_data *cam)
2254 if (do_command(cam, CPIA_COMMAND_GotoHiPower, 0, 0, 0, 0))
2255 return -1;
2256 mdelay(100); /* windows driver does it too */
2257 if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0))
2258 return -1;
2259 if (cam->params.status.systemState == HI_POWER_STATE) {
2260 DBG("camera now in HIGH power state\n");
2261 return 0;
2263 printstatus(cam);
2264 return -1;
2267 static int goto_low_power(struct cam_data *cam)
2269 if (do_command(cam, CPIA_COMMAND_GotoLoPower, 0, 0, 0, 0))
2270 return -1;
2271 if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0))
2272 return -1;
2273 if (cam->params.status.systemState == LO_POWER_STATE) {
2274 DBG("camera now in LOW power state\n");
2275 return 0;
2277 printstatus(cam);
2278 return -1;
2281 static void save_camera_state(struct cam_data *cam)
2283 do_command(cam, CPIA_COMMAND_GetColourBalance, 0, 0, 0, 0);
2284 do_command(cam, CPIA_COMMAND_GetExposure, 0, 0, 0, 0);
2286 DBG("%d/%d/%d/%d/%d/%d/%d/%d\n",
2287 cam->params.exposure.gain,
2288 cam->params.exposure.fineExp,
2289 cam->params.exposure.coarseExpLo,
2290 cam->params.exposure.coarseExpHi,
2291 cam->params.exposure.redComp,
2292 cam->params.exposure.green1Comp,
2293 cam->params.exposure.green2Comp,
2294 cam->params.exposure.blueComp);
2295 DBG("%d/%d/%d\n",
2296 cam->params.colourBalance.redGain,
2297 cam->params.colourBalance.greenGain,
2298 cam->params.colourBalance.blueGain);
2301 static void set_camera_state(struct cam_data *cam)
2303 if(cam->params.colourBalance.balanceModeIsAuto) {
2304 do_command(cam, CPIA_COMMAND_SetColourBalance,
2305 2, 0, 0, 0);
2306 } else {
2307 do_command(cam, CPIA_COMMAND_SetColourBalance,
2309 cam->params.colourBalance.redGain,
2310 cam->params.colourBalance.greenGain,
2311 cam->params.colourBalance.blueGain);
2312 do_command(cam, CPIA_COMMAND_SetColourBalance,
2313 3, 0, 0, 0);
2317 do_command_extended(cam, CPIA_COMMAND_SetExposure,
2318 cam->params.exposure.gainMode, 1, 1,
2319 cam->params.exposure.centreWeight,
2320 cam->params.exposure.gain,
2321 cam->params.exposure.fineExp,
2322 cam->params.exposure.coarseExpLo,
2323 cam->params.exposure.coarseExpHi,
2324 cam->params.exposure.redComp,
2325 cam->params.exposure.green1Comp,
2326 cam->params.exposure.green2Comp,
2327 cam->params.exposure.blueComp);
2328 do_command_extended(cam, CPIA_COMMAND_SetExposure,
2329 0, 3, 0, 0,
2330 0, 0, 0, 0, 0, 0, 0, 0);
2332 if (!cam->params.exposure.gainMode)
2333 cam->params.exposure.gainMode = 2;
2334 if (!cam->params.exposure.expMode)
2335 cam->params.exposure.expMode = 2;
2336 if (!cam->params.exposure.centreWeight)
2337 cam->params.exposure.centreWeight = 1;
2339 cam->cmd_queue = COMMAND_SETCOMPRESSION |
2340 COMMAND_SETCOMPRESSIONTARGET |
2341 COMMAND_SETCOLOURPARAMS |
2342 COMMAND_SETFORMAT |
2343 COMMAND_SETYUVTHRESH |
2344 COMMAND_SETECPTIMING |
2345 COMMAND_SETCOMPRESSIONPARAMS |
2346 #if 0
2347 COMMAND_SETEXPOSURE |
2348 #endif
2349 COMMAND_SETCOLOURBALANCE |
2350 COMMAND_SETSENSORFPS |
2351 COMMAND_SETAPCOR |
2352 COMMAND_SETFLICKERCTRL |
2353 COMMAND_SETVLOFFSET;
2354 dispatch_commands(cam);
2355 save_camera_state(cam);
2357 return;
2360 static void get_version_information(struct cam_data *cam)
2362 /* GetCPIAVersion */
2363 do_command(cam, CPIA_COMMAND_GetCPIAVersion, 0, 0, 0, 0);
2365 /* GetPnPID */
2366 do_command(cam, CPIA_COMMAND_GetPnPID, 0, 0, 0, 0);
2369 /* initialize camera */
2370 static int reset_camera(struct cam_data *cam)
2372 /* Start the camera in low power mode */
2373 if (goto_low_power(cam)) {
2374 if (cam->params.status.systemState != WARM_BOOT_STATE)
2375 return -ENODEV;
2377 /* FIXME: this is just dirty trial and error */
2378 reset_camera_struct(cam);
2379 goto_high_power(cam);
2380 do_command(cam, CPIA_COMMAND_DiscardFrame, 0, 0, 0, 0);
2381 if (goto_low_power(cam))
2382 return -NODEV;
2385 /* procedure described in developer's guide p3-28 */
2387 /* Check the firmware version FIXME: should we check PNPID? */
2388 cam->params.version.firmwareVersion = 0;
2389 get_version_information(cam);
2390 if (cam->params.version.firmwareVersion != 1)
2391 return -ENODEV;
2393 /* The fatal error checking should be done after
2394 * the camera powers up (developer's guide p 3-38) */
2396 /* Set streamState before transition to high power to avoid bug
2397 * in firmware 1-02 */
2398 do_command(cam, CPIA_COMMAND_ModifyCameraStatus, STREAMSTATE, 0,
2399 STREAM_NOT_READY, 0);
2401 /* GotoHiPower */
2402 if (goto_high_power(cam))
2403 return -ENODEV;
2405 /* Check the camera status */
2406 if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0))
2407 return -EIO;
2409 if (cam->params.status.fatalError) {
2410 DBG("fatal_error: %#04x\n",
2411 cam->params.status.fatalError);
2412 DBG("vp_status: %#04x\n",
2413 cam->params.status.vpStatus);
2414 if (cam->params.status.fatalError & ~(COM_FLAG|CPIA_FLAG)) {
2415 /* Fatal error in camera */
2416 return -EIO;
2417 } else if (cam->params.status.fatalError & (COM_FLAG|CPIA_FLAG)) {
2418 /* Firmware 1-02 may do this for parallel port cameras,
2419 * just clear the flags (developer's guide p 3-38) */
2420 do_command(cam, CPIA_COMMAND_ModifyCameraStatus,
2421 FATALERROR, ~(COM_FLAG|CPIA_FLAG), 0, 0);
2425 /* Check the camera status again */
2426 if (cam->params.status.fatalError) {
2427 if (cam->params.status.fatalError)
2428 return -EIO;
2431 /* VPVersion can't be retrieved before the camera is in HiPower,
2432 * so get it here instead of in get_version_information. */
2433 do_command(cam, CPIA_COMMAND_GetVPVersion, 0, 0, 0, 0);
2435 /* set camera to a known state */
2436 set_camera_state(cam);
2438 return 0;
2441 /* ------------------------- V4L interface --------------------- */
2442 static int cpia_open(struct video_device *dev, int flags)
2444 int i;
2445 struct cam_data *cam = dev->priv;
2447 if (!cam) {
2448 DBG("Internal error, cam_data not found!\n");
2449 return -EBUSY;
2452 if (cam->open_count > 0) {
2453 DBG("Camera already open\n");
2454 return -EBUSY;
2457 if (!cam->raw_image) {
2458 cam->raw_image = rvmalloc(CPIA_MAX_IMAGE_SIZE);
2459 if (!cam->raw_image)
2460 return -ENOMEM;
2463 if (!cam->decompressed_frame.data) {
2464 cam->decompressed_frame.data = rvmalloc(CPIA_MAX_FRAME_SIZE);
2465 if (!cam->decompressed_frame.data) {
2466 rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
2467 cam->raw_image = NULL;
2468 return -ENOMEM;
2472 /* open cpia */
2473 if (cam->ops->open(cam->lowlevel_data)) {
2474 rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE);
2475 cam->decompressed_frame.data = NULL;
2476 rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
2477 cam->raw_image = NULL;
2478 return -ENODEV;
2481 /* reset the camera */
2482 if ((i = reset_camera(cam)) != 0) {
2483 cam->ops->close(cam->lowlevel_data);
2484 rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE);
2485 cam->decompressed_frame.data = NULL;
2486 rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
2487 cam->raw_image = NULL;
2488 return i;
2491 /* Set ownership of /proc/cpia/videoX to current user */
2492 if(cam->proc_entry)
2493 cam->proc_entry->uid = current->uid;
2495 /* set mark for loading first frame uncompressed */
2496 cam->first_frame = 1;
2498 /* init it to something */
2499 cam->mmap_kludge = 0;
2501 ++cam->open_count;
2502 #ifdef MODULE
2503 MOD_INC_USE_COUNT;
2504 #endif
2505 return 0;
2508 static void cpia_close(struct video_device *dev)
2510 struct cam_data *cam;
2512 cam = dev->priv;
2514 if (cam->ops) {
2515 /* Return ownership of /proc/cpia/videoX to root */
2516 if(cam->proc_entry)
2517 cam->proc_entry->uid = 0;
2519 /* save camera state for later open (developers guide ch 3.5.3) */
2520 save_camera_state(cam);
2522 /* GotoLoPower */
2523 goto_low_power(cam);
2525 /* Update the camera ststus */
2526 do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0);
2528 /* cleanup internal state stuff */
2529 free_frames(cam->frame);
2531 /* close cpia */
2532 cam->ops->close(cam->lowlevel_data);
2535 if (--cam->open_count == 0) {
2536 /* clean up capture-buffers */
2537 if (cam->raw_image) {
2538 rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
2539 cam->raw_image = NULL;
2542 if (cam->decompressed_frame.data) {
2543 rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE);
2544 cam->decompressed_frame.data = NULL;
2547 if (cam->frame_buf)
2548 free_frame_buf(cam);
2550 if (!cam->ops) {
2551 video_unregister_device(dev);
2552 kfree(cam);
2557 #ifdef MODULE
2558 MOD_DEC_USE_COUNT;
2559 #endif
2560 return;
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))
2570 return -EINTR;
2572 if (!buf) {
2573 DBG("buf NULL\n");
2574 up(&cam->busy_lock);
2575 return -EINVAL;
2578 if (!count) {
2579 DBG("count 0\n");
2580 up(&cam->busy_lock);
2581 return 0;
2584 if (!cam->ops) {
2585 DBG("ops NULL\n");
2586 up(&cam->busy_lock);
2587 return -ENODEV;
2590 /* upload frame */
2591 cam->decompressed_frame.state = FRAME_READY;
2592 cam->mmap_kludge=0;
2593 fetch_frame(cam);
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);
2598 return -EIO;
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,
2605 count);
2606 up(&cam->busy_lock);
2607 return -EFAULT;
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);
2613 return -EFAULT;
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;
2623 int retval = 0;
2625 if (!cam || !cam->ops)
2626 return -ENODEV;
2628 /* make this _really_ smp-safe */
2629 if (down_interruptible(&cam->busy_lock))
2630 return -EINTR;
2632 //DBG("cpia_ioctl: %u\n", ioctlnr);
2634 switch (ioctlnr) {
2635 /* query capabilites */
2636 case VIDIOCGCAP:
2638 struct video_capability b;
2640 DBG("VIDIOCGCAP\n");
2641 strcpy(b.name, "CPiA Camera");
2642 b.type = VID_TYPE_CAPTURE;
2643 b.channels = 1;
2644 b.audios = 0;
2645 b.maxwidth = 352; /* VIDEOSIZE_CIF */
2646 b.maxheight = 288;
2647 b.minwidth = 48; /* VIDEOSIZE_48_48 */
2648 b.minheight = 48;
2650 if (copy_to_user(arg, &b, sizeof(b)))
2651 retval = -EFAULT;
2653 break;
2656 /* get/set video source - we are a camera and nothing else */
2657 case VIDIOCGCHAN:
2659 struct video_channel v;
2661 DBG("VIDIOCGCHAN\n");
2662 if (copy_from_user(&v, arg, sizeof(v))) {
2663 retval = -EFAULT;
2664 break;
2666 if (v.channel != 0) {
2667 retval = -EINVAL;
2668 break;
2671 v.channel = 0;
2672 strcpy(v.name, "Camera");
2673 v.tuners = 0;
2674 v.flags = 0;
2675 v.type = VIDEO_TYPE_CAMERA;
2676 v.norm = 0;
2678 if (copy_to_user(arg, &v, sizeof(v)))
2679 retval = -EFAULT;
2680 break;
2683 case VIDIOCSCHAN:
2685 int v;
2687 DBG("VIDIOCSCHAN\n");
2688 if (copy_from_user(&v, arg, sizeof(v)))
2689 retval = -EFAULT;
2691 if (retval == 0 && v != 0)
2692 retval = -EINVAL;
2694 break;
2697 /* image properties */
2698 case VIDIOCGPICT:
2699 DBG("VIDIOCGPICT\n");
2700 if (copy_to_user(arg, &cam->vp, sizeof(struct video_picture)))
2701 retval = -EFAULT;
2702 break;
2704 case VIDIOCSPICT:
2706 struct video_picture vp;
2708 DBG("VIDIOCSPICT\n");
2710 /* copy_from_user */
2711 if (copy_from_user(&vp, arg, sizeof(vp))) {
2712 retval = -EFAULT;
2713 break;
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)) {
2720 retval = -EINVAL;
2721 break;
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,
2746 vp.contrast);
2747 break;
2750 /* get/set capture window */
2751 case VIDIOCGWIN:
2752 DBG("VIDIOCGWIN\n");
2754 if (copy_to_user(arg, &cam->vw, sizeof(struct video_window)))
2755 retval = -EFAULT;
2756 break;
2758 case VIDIOCSWIN:
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))) {
2764 retval = -EFAULT;
2765 break;
2768 if (vw.clipcount != 0) { /* clipping not supported */
2769 retval = -EINVAL;
2770 break;
2772 if (vw.clips != NULL) { /* clipping not supported */
2773 retval = -EINVAL;
2774 break;
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) {
2785 retval = -EINVAL;
2786 up(&cam->param_lock);
2787 break;
2789 cam->video_size = video_size;
2790 set_vw_size(cam);
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) {
2801 DBG("\n");
2802 dispatch_commands(cam);
2804 DBG("%d/%d:%d\n", cam->video_size,
2805 cam->vw.width, cam->vw.height);
2806 break;
2809 /* mmap interface */
2810 case VIDIOCGMBUF:
2812 struct video_mbuf vm;
2813 int i;
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)))
2823 retval = -EFAULT;
2825 break;
2828 case VIDIOCMCAPTURE:
2830 struct video_mmap vm;
2831 int video_size;
2833 if (copy_from_user((void *)&vm, (void *)arg, sizeof(vm))) {
2834 retval = -EFAULT;
2835 break;
2837 #if 1
2838 DBG("VIDIOCMCAPTURE: %d / %d / %dx%d\n", vm.format, vm.frame,
2839 vm.width, vm.height);
2840 #endif
2841 if (vm.frame<0||vm.frame>FRAME_NUM) {
2842 retval = -EINVAL;
2843 break;
2846 /* set video format */
2847 cam->vp.palette = vm.format;
2848 switch(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:
2855 cam->vp.depth = 16;
2856 break;
2857 case VIDEO_PALETTE_RGB24:
2858 cam->vp.depth = 24;
2859 break;
2860 case VIDEO_PALETTE_RGB32:
2861 cam->vp.depth = 32;
2862 break;
2863 default:
2864 retval = -EINVAL;
2865 break;
2867 if (retval)
2868 break;
2870 /* set video size */
2871 video_size = match_videosize(vm.width, vm.height);
2872 if (cam->video_size < 0) {
2873 retval = -EINVAL;
2874 break;
2876 if (video_size != cam->video_size) {
2877 cam->video_size = video_size;
2878 set_vw_size(cam);
2879 cam->cmd_queue |= COMMAND_SETFORMAT;
2880 dispatch_commands(cam);
2882 #if 0
2883 DBG("VIDIOCMCAPTURE: %d / %d/%d\n", cam->video_size,
2884 cam->vw.width, cam->vw.height);
2885 #endif
2886 /* according to v4l-spec we must start streaming here */
2887 cam->mmap_kludge = 1;
2888 retval = capture_frame(cam, &vm);
2890 break;
2893 case VIDIOCSYNC:
2895 int frame;
2897 if (copy_from_user((void *)&frame, arg, sizeof(int))) {
2898 retval = -EFAULT;
2899 break;
2901 //DBG("VIDIOCSYNC: %d\n", frame);
2903 if (frame<0 || frame >= FRAME_NUM) {
2904 retval = -EINVAL;
2905 break;
2908 switch (cam->frame[frame].state) {
2909 case FRAME_UNUSED:
2910 case FRAME_READY:
2911 case FRAME_GRABBING:
2912 DBG("sync to unused frame %d\n", frame);
2913 retval = -EINVAL;
2914 break;
2916 case FRAME_DONE:
2917 cam->frame[frame].state = FRAME_UNUSED;
2918 //DBG("VIDIOCSYNC: %d synced\n", frame);
2919 break;
2921 if (retval == -EINTR) {
2922 /* FIXME - xawtv does not handle this nice */
2923 retval = 0;
2925 break;
2928 /* pointless to implement overlay with this camera */
2929 case VIDIOCCAPTURE:
2930 retval = -EINVAL;
2931 break;
2932 case VIDIOCGFBUF:
2933 retval = -EINVAL;
2934 break;
2935 case VIDIOCSFBUF:
2936 retval = -EINVAL;
2937 break;
2938 case VIDIOCKEY:
2939 retval = -EINVAL;
2940 break;
2942 /* tuner interface - we have none */
2943 case VIDIOCGTUNER:
2944 retval = -EINVAL;
2945 break;
2946 case VIDIOCSTUNER:
2947 retval = -EINVAL;
2948 break;
2949 case VIDIOCGFREQ:
2950 retval = -EINVAL;
2951 break;
2952 case VIDIOCSFREQ:
2953 retval = -EINVAL;
2954 break;
2956 /* audio interface - we have none */
2957 case VIDIOCGAUDIO:
2958 retval = -EINVAL;
2959 break;
2960 case VIDIOCSAUDIO:
2961 retval = -EINVAL;
2962 break;
2963 default:
2964 retval = -ENOIOCTLCMD;
2965 break;
2968 up(&cam->param_lock);
2969 up(&cam->busy_lock);
2970 return retval;
2973 /* FIXME */
2974 static int cpia_mmap(struct video_device *dev, const char *adr,
2975 unsigned long size)
2977 unsigned long start = (unsigned long)adr;
2978 unsigned long page, pos;
2979 struct cam_data *cam = dev->priv;
2980 int retval;
2982 if (!cam || !cam->ops)
2983 return -ENODEV;
2985 DBG("cpia_mmap: %ld\n", size);
2987 if (size > FRAME_NUM*CPIA_MAX_FRAME_SIZE)
2988 return -EINVAL;
2990 if (!cam || !cam->ops)
2991 return -ENODEV;
2993 /* make this _really_ smp-safe */
2994 if (down_interruptible(&cam->busy_lock))
2995 return -EINTR;
2997 if (!cam->frame_buf) { /* we do lazy allocation */
2998 if ((retval = allocate_frame_buf(cam))) {
2999 up(&cam->busy_lock);
3000 return retval;
3004 pos = (unsigned long)(cam->frame_buf);
3005 while (size > 0) {
3006 page = kvirt_to_pa(pos);
3007 if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) {
3008 up(&cam->busy_lock);
3009 return -EAGAIN;
3011 start += PAGE_SIZE;
3012 pos += PAGE_SIZE;
3013 if (size > PAGE_SIZE)
3014 size -= PAGE_SIZE;
3015 else
3016 size = 0;
3019 DBG("cpia_mmap: %ld\n", size);
3020 up(&cam->busy_lock);
3022 return 0;
3025 int cpia_video_init(struct video_device *vdev)
3027 #ifdef CONFIG_PROC_FS
3028 create_proc_cpia_cam(vdev->priv);
3029 #endif
3030 return 0;
3033 static struct video_device cpia_template = {
3034 "CPiA Camera",
3035 VID_TYPE_CAPTURE,
3036 VID_HARDWARE_CPIA, /* FIXME */
3037 cpia_open, /* open */
3038 cpia_close, /* close */
3039 cpia_read, /* read */
3040 NULL, /* no write */
3041 NULL, /* no poll */
3042 cpia_ioctl, /* ioctl */
3043 cpia_mmap, /* mmap */
3044 cpia_video_init, /* initialize */
3045 NULL, /* priv */
3046 0, /* busy */
3047 -1 /* minor - unset */
3050 /* initialise cam_data structure */
3051 static void reset_camera_struct(struct cam_data *cam)
3053 /* The following parameter values are the defaults from
3054 * "Software Developer's Guide for CPiA Cameras". Any changes
3055 * to the defaults are noted in comments. */
3056 cam->params.colourParams.brightness = 50;
3057 cam->params.colourParams.contrast = 48;
3058 cam->params.colourParams.saturation = 50;
3059 cam->params.exposure.gainMode = 2;
3060 cam->params.exposure.expMode = 2; /* AEC */
3061 cam->params.exposure.compMode = 1;
3062 cam->params.exposure.centreWeight = 1;
3063 cam->params.exposure.gain = 0;
3064 cam->params.exposure.fineExp = 0;
3065 cam->params.exposure.coarseExpLo = 185;
3066 cam->params.exposure.coarseExpHi = 0;
3067 cam->params.exposure.redComp = 220;
3068 cam->params.exposure.green1Comp = 214;
3069 cam->params.exposure.green2Comp = 214;
3070 cam->params.exposure.blueComp = 230;
3071 cam->params.colourBalance.balanceModeIsAuto = 1;
3072 cam->params.colourBalance.redGain = 32;
3073 cam->params.colourBalance.greenGain = 6;
3074 cam->params.colourBalance.blueGain = 92;
3075 cam->params.apcor.gain1 = 0x1c;
3076 cam->params.apcor.gain2 = 0x1a;
3077 cam->params.apcor.gain4 = 0x2d;
3078 cam->params.apcor.gain8 = 0x2a;
3079 cam->params.flickerControl.flickerMode = 0;
3080 cam->params.flickerControl.coarseJump =
3081 flicker_jumps[cam->mainsFreq]
3082 [cam->params.sensorFps.baserate]
3083 [cam->params.sensorFps.divisor];
3084 cam->params.vlOffset.gain1 = 24;
3085 cam->params.vlOffset.gain2 = 28;
3086 cam->params.vlOffset.gain4 = 30;
3087 cam->params.vlOffset.gain8 = 30;
3088 cam->params.compressionParams.hysteresis = 3;
3089 cam->params.compressionParams.threshMax = 11;
3090 cam->params.compressionParams.smallStep = 1;
3091 cam->params.compressionParams.largeStep = 3;
3092 cam->params.compressionParams.decimationHysteresis = 2;
3093 cam->params.compressionParams.frDiffStepThresh = 5;
3094 cam->params.compressionParams.qDiffStepThresh = 3;
3095 cam->params.compressionParams.decimationThreshMod = 2;
3096 /* End of default values from Software Developer's Guide */
3098 cam->transfer_rate = 0;
3100 /* Set Sensor FPS to 15fps. This seems better than 30fps
3101 * for indoor lighting. */
3102 cam->params.sensorFps.divisor = 1;
3103 cam->params.sensorFps.baserate = 1;
3105 cam->params.yuvThreshold.yThreshold = 15; /* FIXME? */
3106 cam->params.yuvThreshold.uvThreshold = 15; /* FIXME? */
3108 cam->params.format.subSample = SUBSAMPLE_422;
3109 cam->params.format.yuvOrder = YUVORDER_YUYV;
3111 cam->params.compression.mode = CPIA_COMPRESSION_AUTO;
3112 cam->params.compressionTarget.frTargeting =
3113 CPIA_COMPRESSION_TARGET_QUALITY;
3114 cam->params.compressionTarget.targetFR = 7; /* FIXME? */
3115 cam->params.compressionTarget.targetQ = 10; /* FIXME? */
3117 cam->video_size = VIDEOSIZE_CIF;
3119 cam->vp.colour = 32768; /* 50% */
3120 cam->vp.hue = 32768; /* 50% */
3121 cam->vp.brightness = 32768; /* 50% */
3122 cam->vp.contrast = 32768; /* 50% */
3123 cam->vp.whiteness = 0; /* not used -> grayscale only */
3124 cam->vp.depth = 0; /* FIXME: to be set by user? */
3125 cam->vp.palette = VIDEO_PALETTE_RGB24; /* FIXME: to be set by user? */
3127 cam->vw.x = 0;
3128 cam->vw.y = 0;
3129 set_vw_size(cam);
3130 cam->vw.chromakey = 0;
3131 /* PP NOTE: my extension to use vw.flags for this, bear it! */
3132 cam->vw.flags = 0;
3133 cam->vw.clipcount = 0;
3134 cam->vw.clips = NULL;
3136 cam->cmd_queue = COMMAND_NONE;
3137 cam->first_frame = 0;
3139 return;
3142 /* initialize cam_data structure */
3143 static void init_camera_struct(struct cam_data *cam,
3144 struct cpia_camera_ops *ops )
3146 int i;
3148 /* Default everything to 0 */
3149 memset(cam, 0, sizeof(struct cam_data));
3151 cam->ops = ops;
3152 init_MUTEX(&cam->param_lock);
3153 init_MUTEX(&cam->busy_lock);
3155 reset_camera_struct(cam);
3157 cam->proc_entry = NULL;
3159 memcpy(&cam->vdev, &cpia_template, sizeof(cpia_template));
3160 cam->vdev.priv = cam;
3162 cam->curframe = 0;
3163 for (i = 0; i < FRAME_NUM; i++) {
3164 cam->frame[i].width = 0;
3165 cam->frame[i].height = 0;
3166 cam->frame[i].state = FRAME_UNUSED;
3167 cam->frame[i].data = NULL;
3169 cam->decompressed_frame.width = 0;
3170 cam->decompressed_frame.height = 0;
3171 cam->decompressed_frame.state = FRAME_UNUSED;
3172 cam->decompressed_frame.data = NULL;
3175 struct cam_data *cpia_register_camera(struct cpia_camera_ops *ops, void *lowlevel)
3177 struct cam_data *camera;
3179 /* Need a lock when adding/removing cameras. This doesn't happen
3180 * often and doesn't take very long, so grabbing the kernel lock
3181 * should be OK. */
3183 if ((camera = kmalloc(sizeof(struct cam_data), GFP_KERNEL)) == NULL) {
3184 unlock_kernel();
3185 return NULL;
3188 init_camera_struct( camera, ops );
3189 camera->lowlevel_data = lowlevel;
3191 /* register v4l device */
3192 if (video_register_device(&camera->vdev, VFL_TYPE_GRABBER) == -1) {
3193 kfree(camera);
3194 unlock_kernel();
3195 printk(KERN_DEBUG "video_register_device failed\n");
3196 return NULL;
3199 /* get version information from camera: open/reset/close */
3201 /* open cpia */
3202 if (camera->ops->open(camera->lowlevel_data))
3203 return camera;
3205 /* reset the camera */
3206 if (reset_camera(camera) != 0) {
3207 camera->ops->close(camera->lowlevel_data);
3208 return camera;
3211 /* close cpia */
3212 camera->ops->close(camera->lowlevel_data);
3214 /* Eh? Feeling happy? - jerdfelt */
3216 camera->ops->open(camera->lowlevel_data);
3217 camera->ops->close(camera->lowlevel_data);
3220 printk(KERN_INFO " CPiA Version: %d.%02d (%d.%d)\n",
3221 camera->params.version.firmwareVersion,
3222 camera->params.version.firmwareRevision,
3223 camera->params.version.vcVersion,
3224 camera->params.version.vcRevision);
3225 printk(KERN_INFO " CPiA PnP-ID: %04x:%04x:%04x\n",
3226 camera->params.pnpID.vendor,
3227 camera->params.pnpID.product,
3228 camera->params.pnpID.deviceRevision);
3229 printk(KERN_INFO " VP-Version: %d.%d %04x\n",
3230 camera->params.vpVersion.vpVersion,
3231 camera->params.vpVersion.vpRevision,
3232 camera->params.vpVersion.cameraHeadID);
3234 return camera;
3237 void cpia_unregister_camera(struct cam_data *cam)
3239 if (!cam->open_count) {
3240 DBG("unregistering video\n");
3241 video_unregister_device(&cam->vdev);
3242 } else {
3243 LOG("/dev/video%d removed while open, "
3244 "deferring video_unregister_device\n", cam->vdev.minor);
3245 DBG("camera open -- setting ops to NULL\n");
3246 cam->ops = NULL;
3249 #ifdef CONFIG_PROC_FS
3250 DBG("destroying /proc/cpia/video%d\n", cam->vdev.minor);
3251 destroy_proc_cpia_cam(cam);
3252 #endif
3253 if (!cam->open_count) {
3254 DBG("freeing camera\n");
3255 kfree(cam);
3259 /****************************************************************************
3261 * Module routines
3263 ***************************************************************************/
3265 #ifdef MODULE
3266 int init_module(void)
3268 printk(KERN_INFO "%s v%d.%d.%d\n", ABOUT,
3269 CPIA_MAJ_VER, CPIA_MIN_VER, CPIA_PATCH_VER);
3270 #ifdef CONFIG_PROC_FS
3271 proc_cpia_create();
3272 #endif
3273 #ifdef CONFIG_KMOD
3274 #ifdef CONFIG_VIDEO_CPIA_PP_MODULE
3275 request_module("cpia_pp");
3276 #endif
3277 #ifdef CONFIG_VIDEO_CPIA_USB_MODULE
3278 request_module("cpia_usb");
3279 #endif
3280 #endif
3281 return 0;
3284 void cleanup_module(void)
3286 #ifdef CONFIG_PROC_FS
3287 proc_cpia_destroy();
3288 #endif
3291 #else
3293 int cpia_init(struct video_init *unused)
3295 printk(KERN_INFO "%s v%d.%d.%d\n", ABOUT,
3296 CPIA_MAJ_VER, CPIA_MIN_VER, CPIA_PATCH_VER);
3297 #ifdef CONFIG_PROC_FS
3298 proc_cpia_create();
3299 #endif
3301 #ifdef CONFIG_VIDEO_CPIA_PP
3302 cpia_pp_init();
3303 #endif
3304 #ifdef CONFIG_KMOD
3305 #ifdef CONFIG_VIDEO_CPIA_PP_MODULE
3306 request_module("cpia_pp");
3307 #endif
3309 #ifdef CONFIG_VIDEO_CPIA_USB_MODULE
3310 request_module("cpia_usb");
3311 #endif
3312 #endif /* CONFIG_KMOD */
3313 #ifdef CONFIG_VIDEO_CPIA_USB
3314 cpia_usb_init();
3315 #endif
3316 return 0;
3319 /* Exported symbols for modules. */
3321 EXPORT_SYMBOL(cpia_register_camera);
3322 EXPORT_SYMBOL(cpia_unregister_camera);
3324 #endif