Import 2.3.99pre10-3
[davej-history.git] / drivers / char / cpia.c
blobe65b8ec25a90ebf0927fa566ce8a62f6970e2c9c
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 = page_address(pte_page(pte)) |
204 (adr & (PAGE_SIZE-1));
207 return ret;
210 /* Here we want the physical address of the memory.
211 * This is used when initializing the contents of the
212 * area and marking the pages as reserved.
214 static inline unsigned long kvirt_to_pa(unsigned long adr)
216 unsigned long va, kva, ret;
218 va = VMALLOC_VMADDR(adr);
219 kva = uvirt_to_kva(pgd_offset_k(va), va);
220 ret = __pa(kva);
221 return ret;
224 static void *rvmalloc(unsigned long size)
226 void *mem;
227 unsigned long adr, page;
229 /* Round it off to PAGE_SIZE */
230 size += (PAGE_SIZE - 1);
231 size &= ~(PAGE_SIZE - 1);
233 mem = vmalloc_32(size);
234 if (!mem)
235 return NULL;
237 memset(mem, 0, size); /* Clear the ram out, no junk to the user */
238 adr = (unsigned long) mem;
239 while (size > 0) {
240 page = kvirt_to_pa(adr);
241 mem_map_reserve(MAP_NR(__va(page)));
242 adr += PAGE_SIZE;
243 if (size > PAGE_SIZE)
244 size -= PAGE_SIZE;
245 else
246 size = 0;
249 return mem;
252 static void rvfree(void *mem, unsigned long size)
254 unsigned long adr, page;
256 if (!mem)
257 return;
259 size += (PAGE_SIZE - 1);
260 size &= ~(PAGE_SIZE - 1);
262 adr = (unsigned long) mem;
263 while (size > 0) {
264 page = kvirt_to_pa(adr);
265 mem_map_unreserve(MAP_NR(__va(page)));
266 adr += PAGE_SIZE;
267 if (size > PAGE_SIZE)
268 size -= PAGE_SIZE;
269 else
270 size = 0;
272 vfree(mem);
275 /**********************************************************************
277 * /proc interface
279 **********************************************************************/
280 #ifdef CONFIG_PROC_FS
281 static struct proc_dir_entry *cpia_proc_root=NULL;
283 static int cpia_read_proc(char *page, char **start, off_t off,
284 int count, int *eof, void *data)
286 char *out = page;
287 int len, tmp;
288 struct cam_data *cam = data;
289 char tmpstr[20];
291 /* IMPORTANT: This output MUST be kept under PAGE_SIZE
292 * or we need to get more sophisticated. */
294 out += sprintf(out, "read-only\n-----------------------\n");
295 out += sprintf(out, "V4L Driver version: %d.%d.%d\n",
296 CPIA_MAJ_VER, CPIA_MIN_VER, CPIA_PATCH_VER);
297 out += sprintf(out, "CPIA Version: %d.%02d (%d.%d)\n",
298 cam->params.version.firmwareVersion,
299 cam->params.version.firmwareRevision,
300 cam->params.version.vcVersion,
301 cam->params.version.vcRevision);
302 out += sprintf(out, "CPIA PnP-ID: %04x:%04x:%04x\n",
303 cam->params.pnpID.vendor, cam->params.pnpID.product,
304 cam->params.pnpID.deviceRevision);
305 out += sprintf(out, "VP-Version: %d.%d %04x\n",
306 cam->params.vpVersion.vpVersion,
307 cam->params.vpVersion.vpRevision,
308 cam->params.vpVersion.cameraHeadID);
310 out += sprintf(out, "system_state: %#04x\n",
311 cam->params.status.systemState);
312 out += sprintf(out, "grab_state: %#04x\n",
313 cam->params.status.grabState);
314 out += sprintf(out, "stream_state: %#04x\n",
315 cam->params.status.streamState);
316 out += sprintf(out, "fatal_error: %#04x\n",
317 cam->params.status.fatalError);
318 out += sprintf(out, "cmd_error: %#04x\n",
319 cam->params.status.cmdError);
320 out += sprintf(out, "debug_flags: %#04x\n",
321 cam->params.status.debugFlags);
322 out += sprintf(out, "vp_status: %#04x\n",
323 cam->params.status.vpStatus);
324 out += sprintf(out, "error_code: %#04x\n",
325 cam->params.status.errorCode);
326 out += sprintf(out, "video_size: %s\n",
327 cam->params.format.videoSize == VIDEOSIZE_CIF ?
328 "CIF " : "QCIF");
329 out += sprintf(out, "sub_sample: %s\n",
330 cam->params.format.subSample == SUBSAMPLE_420 ?
331 "420" : "422");
332 out += sprintf(out, "yuv_order: %s\n",
333 cam->params.format.yuvOrder == YUVORDER_YUYV ?
334 "YUYV" : "UYVY");
335 out += sprintf(out, "roi: (%3d, %3d) to (%3d, %3d)\n",
336 cam->params.roi.colStart*8,
337 cam->params.roi.rowStart*4,
338 cam->params.roi.colEnd*8,
339 cam->params.roi.rowEnd*4);
340 out += sprintf(out, "actual_fps: %3d\n", cam->fps);
341 out += sprintf(out, "transfer_rate: %4dkB/s\n",
342 cam->transfer_rate);
344 out += sprintf(out, "\nread-write\n");
345 out += sprintf(out, "----------------------- current min"
346 " max default comment\n");
347 out += sprintf(out, "brightness: %8d %8d %8d %8d\n",
348 cam->params.colourParams.brightness, 0, 100, 50);
349 if (cam->params.version.firmwareVersion == 1 &&
350 cam->params.version.firmwareRevision == 2)
351 /* 1-02 firmware limits contrast to 80 */
352 tmp = 80;
353 else
354 tmp = 96;
356 out += sprintf(out, "contrast: %8d %8d %8d %8d"
357 " steps of 8\n",
358 cam->params.colourParams.contrast, 0, tmp, 48);
359 out += sprintf(out, "saturation: %8d %8d %8d %8d\n",
360 cam->params.colourParams.saturation, 0, 100, 50);
361 tmp = (25000+5000*cam->params.sensorFps.baserate)/
362 (1<<cam->params.sensorFps.divisor);
363 out += sprintf(out, "sensor_fps: %4d.%03d %8d %8d %8d\n",
364 tmp/1000, tmp%1000, 3, 30, 15);
365 out += sprintf(out, "stream_start_line: %8d %8d %8d %8d\n",
366 2*cam->params.streamStartLine, 0,
367 cam->params.format.videoSize == VIDEOSIZE_CIF ? 288:144,
368 cam->params.format.videoSize == VIDEOSIZE_CIF ? 240:120);
369 out += sprintf(out, "ecp_timing: %8s %8s %8s %8s\n",
370 cam->params.ecpTiming ? "slow" : "normal", "slow",
371 "normal", "normal");
373 if (cam->params.colourBalance.balanceModeIsAuto) {
374 sprintf(tmpstr, "auto");
375 } else {
376 sprintf(tmpstr, "manual");
378 out += sprintf(out, "color_balance_mode: %8s %8s %8s"
379 " %8s\n", tmpstr, "manual", "auto", "auto");
380 out += sprintf(out, "red_gain: %8d %8d %8d %8d\n",
381 cam->params.colourBalance.redGain, 0, 212, 32);
382 out += sprintf(out, "green_gain: %8d %8d %8d %8d\n",
383 cam->params.colourBalance.greenGain, 0, 212, 6);
384 out += sprintf(out, "blue_gain: %8d %8d %8d %8d\n",
385 cam->params.colourBalance.blueGain, 0, 212, 92);
387 if (cam->params.version.firmwareVersion == 1 &&
388 cam->params.version.firmwareRevision == 2)
389 /* 1-02 firmware limits gain to 2 */
390 sprintf(tmpstr, "%8d %8d", 1, 2);
391 else
392 sprintf(tmpstr, "1,2,4,8");
394 if (cam->params.exposure.gainMode == 0)
395 out += sprintf(out, "max_gain: unknown %18s"
396 " %8d\n", tmpstr, 2);
397 else
398 out += sprintf(out, "max_gain: %8d %18s %8d\n",
399 1<<(cam->params.exposure.gainMode-1), tmpstr, 2);
401 switch(cam->params.exposure.expMode) {
402 case 1:
403 case 3:
404 sprintf(tmpstr, "manual");
405 break;
406 case 2:
407 sprintf(tmpstr, "auto");
408 break;
409 default:
410 sprintf(tmpstr, "unknown");
411 break;
413 out += sprintf(out, "exposure_mode: %8s %8s %8s"
414 " %8s\n", tmpstr, "manual", "auto", "auto");
415 out += sprintf(out, "centre_weight: %8s %8s %8s %8s\n",
416 (2-cam->params.exposure.centreWeight) ? "on" : "off",
417 "off", "on", "on");
418 out += sprintf(out, "gain: %8d %8d max_gain %8d 1,2,4,8 possible\n",
419 1<<cam->params.exposure.gain, 1, 1);
420 if (cam->params.version.firmwareVersion == 1 &&
421 cam->params.version.firmwareRevision == 2)
422 /* 1-02 firmware limits fineExp to 127 */
423 tmp = 255;
424 else
425 tmp = 511;
427 out += sprintf(out, "fine_exp: %8d %8d %8d %8d\n",
428 cam->params.exposure.fineExp*2, 0, tmp, 0);
429 if (cam->params.version.firmwareVersion == 1 &&
430 cam->params.version.firmwareRevision == 2)
431 /* 1-02 firmware limits coarseExpHi to 0 */
432 tmp = 255;
433 else
434 tmp = 65535;
436 out += sprintf(out, "coarse_exp: %8d %8d %8d"
437 " %8d\n", cam->params.exposure.coarseExpLo+
438 256*cam->params.exposure.coarseExpHi, 0, tmp, 185);
439 out += sprintf(out, "red_comp: %8d %8d %8d %8d\n",
440 cam->params.exposure.redComp, 220, 255, 220);
441 out += sprintf(out, "green1_comp: %8d %8d %8d %8d\n",
442 cam->params.exposure.green1Comp, 214, 255, 214);
443 out += sprintf(out, "green2_comp: %8d %8d %8d %8d\n",
444 cam->params.exposure.green2Comp, 214, 255, 214);
445 out += sprintf(out, "blue_comp: %8d %8d %8d %8d\n",
446 cam->params.exposure.blueComp, 230, 255, 230);
448 out += sprintf(out, "apcor_gain1: %#8x %#8x %#8x %#8x\n",
449 cam->params.apcor.gain1, 0, 0xff, 0x1c);
450 out += sprintf(out, "apcor_gain2: %#8x %#8x %#8x %#8x\n",
451 cam->params.apcor.gain2, 0, 0xff, 0x1a);
452 out += sprintf(out, "apcor_gain4: %#8x %#8x %#8x %#8x\n",
453 cam->params.apcor.gain4, 0, 0xff, 0x2d);
454 out += sprintf(out, "apcor_gain8: %#8x %#8x %#8x %#8x\n",
455 cam->params.apcor.gain8, 0, 0xff, 0x2a);
456 out += sprintf(out, "vl_offset_gain1: %8d %8d %8d %8d\n",
457 cam->params.vlOffset.gain1, 0, 255, 24);
458 out += sprintf(out, "vl_offset_gain2: %8d %8d %8d %8d\n",
459 cam->params.vlOffset.gain2, 0, 255, 28);
460 out += sprintf(out, "vl_offset_gain4: %8d %8d %8d %8d\n",
461 cam->params.vlOffset.gain4, 0, 255, 30);
462 out += sprintf(out, "vl_offset_gain8: %8d %8d %8d %8d\n",
463 cam->params.vlOffset.gain8, 0, 255, 30);
464 out += sprintf(out, "flicker_control: %8s %8s %8s %8s\n",
465 cam->params.flickerControl.flickerMode ? "on" : "off",
466 "off", "on", "off");
467 out += sprintf(out, "mains_frequency: %8d %8d %8d %8d"
468 " only 50/60\n",
469 cam->mainsFreq ? 60 : 50, 50, 60, 50);
470 out += sprintf(out, "allowable_overexposure: %8d %8d %8d %8d\n",
471 cam->params.flickerControl.allowableOverExposure, 0,
472 255, 0);
473 out += sprintf(out, "compression_mode: ");
474 switch(cam->params.compression.mode) {
475 case CPIA_COMPRESSION_NONE:
476 out += sprintf(out, "%8s", "none");
477 break;
478 case CPIA_COMPRESSION_AUTO:
479 out += sprintf(out, "%8s", "auto");
480 break;
481 case CPIA_COMPRESSION_MANUAL:
482 out += sprintf(out, "%8s", "manual");
483 break;
484 default:
485 out += sprintf(out, "%8s", "unknown");
486 break;
488 out += sprintf(out, " none,auto,manual auto\n");
489 out += sprintf(out, "decimation_enable: %8s %8s %8s %8s\n",
490 cam->params.compression.decimation ==
491 DECIMATION_ENAB ? "on":"off", "off", "off",
492 "off");
493 out += sprintf(out, "compression_target: %9s %9s %9s %9s\n",
494 cam->params.compressionTarget.frTargeting ==
495 CPIA_COMPRESSION_TARGET_FRAMERATE ?
496 "framerate":"quality",
497 "framerate", "quality", "quality");
498 out += sprintf(out, "target_framerate: %8d %8d %8d %8d\n",
499 cam->params.compressionTarget.targetFR, 0, 30, 7);
500 out += sprintf(out, "target_quality: %8d %8d %8d %8d\n",
501 cam->params.compressionTarget.targetQ, 0, 255, 10);
502 out += sprintf(out, "y_threshold: %8d %8d %8d %8d\n",
503 cam->params.yuvThreshold.yThreshold, 0, 31, 15);
504 out += sprintf(out, "uv_threshold: %8d %8d %8d %8d\n",
505 cam->params.yuvThreshold.uvThreshold, 0, 31, 15);
506 out += sprintf(out, "hysteresis: %8d %8d %8d %8d\n",
507 cam->params.compressionParams.hysteresis, 0, 255, 3);
508 out += sprintf(out, "threshold_max: %8d %8d %8d %8d\n",
509 cam->params.compressionParams.threshMax, 0, 255, 11);
510 out += sprintf(out, "small_step: %8d %8d %8d %8d\n",
511 cam->params.compressionParams.smallStep, 0, 255, 1);
512 out += sprintf(out, "large_step: %8d %8d %8d %8d\n",
513 cam->params.compressionParams.largeStep, 0, 255, 3);
514 out += sprintf(out, "decimation_hysteresis: %8d %8d %8d %8d\n",
515 cam->params.compressionParams.decimationHysteresis,
516 0, 255, 2);
517 out += sprintf(out, "fr_diff_step_thresh: %8d %8d %8d %8d\n",
518 cam->params.compressionParams.frDiffStepThresh,
519 0, 255, 5);
520 out += sprintf(out, "q_diff_step_thresh: %8d %8d %8d %8d\n",
521 cam->params.compressionParams.qDiffStepThresh,
522 0, 255, 3);
523 out += sprintf(out, "decimation_thresh_mod: %8d %8d %8d %8d\n",
524 cam->params.compressionParams.decimationThreshMod,
525 0, 255, 2);
527 len = out - page;
528 len -= off;
529 if (len < count) {
530 *eof = 1;
531 if (len <= 0) return 0;
532 } else
533 len = count;
535 *start = page + off;
536 return len;
539 static int cpia_write_proc(struct file *file, const char *buffer,
540 unsigned long count, void *data)
542 struct cam_data *cam = data;
543 struct cam_params new_params;
544 int retval, find_colon;
545 int size = count;
546 unsigned long val;
547 u32 command_flags = 0;
548 u8 new_mains;
550 if (down_interruptible(&cam->param_lock))
551 return -ERESTARTSYS;
554 * Skip over leading whitespace
556 while (count && isspace(*buffer)) {
557 --count;
558 ++buffer;
561 memcpy(&new_params, &cam->params, sizeof(struct cam_params));
562 new_mains = cam->mainsFreq;
564 #define MATCH(x) \
565 ({ \
566 int _len = strlen(x), _ret, _colon_found; \
567 _ret = (_len <= count && strncmp(buffer, x, _len) == 0); \
568 if (_ret) { \
569 buffer += _len; \
570 count -= _len; \
571 if (find_colon) { \
572 _colon_found = 0; \
573 while (count && (*buffer == ' ' || *buffer == '\t' || \
574 (!_colon_found && *buffer == ':'))) { \
575 if (*buffer == ':') \
576 _colon_found = 1; \
577 --count; \
578 ++buffer; \
580 if (!count || !_colon_found) \
581 retval = -EINVAL; \
582 find_colon = 0; \
585 _ret; \
587 #define FIRMWARE_VERSION(x,y) (new_params.version.firmwareVersion == (x) && \
588 new_params.version.firmwareRevision == (y))
589 #define VALUE \
590 ({ \
591 char *_p; \
592 unsigned long int _ret; \
593 _ret = simple_strtoul(buffer, &_p, 0); \
594 if (_p == buffer) \
595 retval = -EINVAL; \
596 else { \
597 count -= _p - buffer; \
598 buffer = _p; \
600 _ret; \
603 retval = 0;
604 while (count && !retval) {
605 find_colon = 1;
606 if (MATCH("brightness")) {
607 if (!retval)
608 val = VALUE;
610 if (!retval) {
611 if (val <= 100)
612 new_params.colourParams.brightness = val;
613 else
614 retval = -EINVAL;
616 command_flags |= COMMAND_SETCOLOURPARAMS;
617 } else if (MATCH("contrast")) {
618 if (!retval)
619 val = VALUE;
621 if (!retval) {
622 if (val <= 100) {
623 /* contrast is in steps of 8, so round*/
624 val = ((val + 3) / 8) * 8;
625 /* 1-02 firmware limits contrast to 80*/
626 if (FIRMWARE_VERSION(1,2) && val > 80)
627 val = 80;
629 new_params.colourParams.contrast = val;
630 } else
631 retval = -EINVAL;
633 command_flags |= COMMAND_SETCOLOURPARAMS;
634 } else if (MATCH("saturation")) {
635 if (!retval)
636 val = VALUE;
638 if (!retval) {
639 if (val <= 100)
640 new_params.colourParams.saturation = val;
641 else
642 retval = -EINVAL;
644 command_flags |= COMMAND_SETCOLOURPARAMS;
645 } else if (MATCH("sensor_fps")) {
646 if (!retval)
647 val = VALUE;
649 if (!retval) {
650 /* find values so that sensorFPS is minimized,
651 * but >= val */
652 if (val > 30)
653 retval = -EINVAL;
654 else if (val > 25) {
655 new_params.sensorFps.divisor = 0;
656 new_params.sensorFps.baserate = 1;
657 } else if (val > 15) {
658 new_params.sensorFps.divisor = 0;
659 new_params.sensorFps.baserate = 0;
660 } else if (val > 12) {
661 new_params.sensorFps.divisor = 1;
662 new_params.sensorFps.baserate = 1;
663 } else if (val > 7) {
664 new_params.sensorFps.divisor = 1;
665 new_params.sensorFps.baserate = 0;
666 } else if (val > 6) {
667 new_params.sensorFps.divisor = 2;
668 new_params.sensorFps.baserate = 1;
669 } else if (val > 3) {
670 new_params.sensorFps.divisor = 2;
671 new_params.sensorFps.baserate = 0;
672 } else {
673 new_params.sensorFps.divisor = 3;
674 /* Either base rate would work here */
675 new_params.sensorFps.baserate = 1;
677 new_params.flickerControl.coarseJump =
678 flicker_jumps[new_mains]
679 [new_params.sensorFps.baserate]
680 [new_params.sensorFps.divisor];
681 if (new_params.flickerControl.flickerMode)
682 command_flags |= COMMAND_SETFLICKERCTRL;
684 command_flags |= COMMAND_SETSENSORFPS;
685 } else if (MATCH("stream_start_line")) {
686 if (!retval)
687 val = VALUE;
689 if (!retval) {
690 int max_line = 288;
692 if (new_params.format.videoSize == VIDEOSIZE_QCIF)
693 max_line = 144;
694 if (val <= max_line)
695 new_params.streamStartLine = val/2;
696 else
697 retval = -EINVAL;
699 } else if (MATCH("ecp_timing")) {
700 if (!retval && MATCH("normal"))
701 new_params.ecpTiming = 0;
702 else if (!retval && MATCH("slow"))
703 new_params.ecpTiming = 1;
704 else
705 retval = -EINVAL;
707 command_flags |= COMMAND_SETECPTIMING;
708 } else if (MATCH("color_balance_mode")) {
709 if (!retval && MATCH("manual"))
710 new_params.colourBalance.balanceModeIsAuto = 0;
711 else if (!retval && MATCH("auto"))
712 new_params.colourBalance.balanceModeIsAuto = 1;
713 else
714 retval = -EINVAL;
716 command_flags |= COMMAND_SETCOLOURBALANCE;
717 } else if (MATCH("red_gain")) {
718 if (!retval)
719 val = VALUE;
721 if (!retval) {
722 if (val <= 212)
723 new_params.colourBalance.redGain = val;
724 else
725 retval = -EINVAL;
727 command_flags |= COMMAND_SETCOLOURBALANCE;
728 } else if (MATCH("green_gain")) {
729 if (!retval)
730 val = VALUE;
732 if (!retval) {
733 if (val <= 212)
734 new_params.colourBalance.greenGain = val;
735 else
736 retval = -EINVAL;
738 command_flags |= COMMAND_SETCOLOURBALANCE;
739 } else if (MATCH("blue_gain")) {
740 if (!retval)
741 val = VALUE;
743 if (!retval) {
744 if (val <= 212)
745 new_params.colourBalance.blueGain = val;
746 else
747 retval = -EINVAL;
749 command_flags |= COMMAND_SETCOLOURBALANCE;
750 } else if (MATCH("max_gain")) {
751 if (!retval)
752 val = VALUE;
754 if (!retval) {
755 /* 1-02 firmware limits gain to 2 */
756 if (FIRMWARE_VERSION(1,2) && val > 2)
757 val = 2;
758 switch(val) {
759 case 1:
760 new_params.exposure.gainMode = 1;
761 break;
762 case 2:
763 new_params.exposure.gainMode = 2;
764 break;
765 case 4:
766 new_params.exposure.gainMode = 3;
767 break;
768 case 8:
769 new_params.exposure.gainMode = 4;
770 break;
771 default:
772 retval = -EINVAL;
773 break;
776 command_flags |= COMMAND_SETEXPOSURE;
777 } else if (MATCH("exposure_mode")) {
778 if (!retval && MATCH("auto"))
779 new_params.exposure.expMode = 2;
780 else if (!retval && MATCH("manual")) {
781 if (new_params.exposure.expMode == 2)
782 new_params.exposure.expMode = 3;
783 new_params.flickerControl.flickerMode = 0;
784 command_flags |= COMMAND_SETFLICKERCTRL;
785 } else
786 retval = -EINVAL;
788 command_flags |= COMMAND_SETEXPOSURE;
789 } else if (MATCH("centre_weight")) {
790 if (!retval && MATCH("on"))
791 new_params.exposure.centreWeight = 1;
792 else if (!retval && MATCH("off"))
793 new_params.exposure.centreWeight = 2;
794 else
795 retval = -EINVAL;
797 command_flags |= COMMAND_SETEXPOSURE;
798 } else if (MATCH("gain")) {
799 if (!retval)
800 val = VALUE;
802 if (!retval) {
803 switch(val) {
804 case 1:
805 new_params.exposure.gain = 0;
806 new_params.exposure.expMode = 1;
807 new_params.flickerControl.flickerMode = 0;
808 command_flags |= COMMAND_SETFLICKERCTRL;
809 break;
810 case 2:
811 new_params.exposure.gain = 1;
812 new_params.exposure.expMode = 1;
813 new_params.flickerControl.flickerMode = 0;
814 command_flags |= COMMAND_SETFLICKERCTRL;
815 break;
816 case 4:
817 new_params.exposure.gain = 2;
818 new_params.exposure.expMode = 1;
819 new_params.flickerControl.flickerMode = 0;
820 command_flags |= COMMAND_SETFLICKERCTRL;
821 break;
822 case 8:
823 new_params.exposure.gain = 3;
824 new_params.exposure.expMode = 1;
825 new_params.flickerControl.flickerMode = 0;
826 command_flags |= COMMAND_SETFLICKERCTRL;
827 break;
828 default:
829 retval = -EINVAL;
830 break;
832 command_flags |= COMMAND_SETEXPOSURE;
833 if (new_params.exposure.gain >
834 new_params.exposure.gainMode-1)
835 retval = -EINVAL;
837 } else if (MATCH("fine_exp")) {
838 if (!retval)
839 val = VALUE;
841 if (!retval) {
842 if (val < 256) {
843 /* 1-02 firmware limits fineExp to 127*/
844 if (FIRMWARE_VERSION(1,2) && val > 127)
845 val = 127;
846 new_params.exposure.fineExp = val;
847 new_params.exposure.expMode = 1;
848 command_flags |= COMMAND_SETEXPOSURE;
849 new_params.flickerControl.flickerMode = 0;
850 command_flags |= COMMAND_SETFLICKERCTRL;
851 } else
852 retval = -EINVAL;
854 } else if (MATCH("coarse_exp")) {
855 if (!retval)
856 val = VALUE;
858 if (!retval) {
859 if (val < 65536) {
860 /* 1-02 firmware limits
861 * coarseExp to 255 */
862 if (FIRMWARE_VERSION(1,2) && val > 255)
863 val = 255;
864 new_params.exposure.coarseExpLo =
865 val & 0xff;
866 new_params.exposure.coarseExpHi =
867 val >> 8;
868 new_params.exposure.expMode = 1;
869 command_flags |= COMMAND_SETEXPOSURE;
870 new_params.flickerControl.flickerMode = 0;
871 command_flags |= COMMAND_SETFLICKERCTRL;
872 } else
873 retval = -EINVAL;
875 } else if (MATCH("red_comp")) {
876 if (!retval)
877 val = VALUE;
879 if (!retval) {
880 if (val >= 220 && val <= 255) {
881 new_params.exposure.redComp = val;
882 command_flags |= COMMAND_SETEXPOSURE;
883 } else
884 retval = -EINVAL;
886 } else if (MATCH("green1_comp")) {
887 if (!retval)
888 val = VALUE;
890 if (!retval) {
891 if (val >= 214 && val <= 255) {
892 new_params.exposure.green1Comp = val;
893 command_flags |= COMMAND_SETEXPOSURE;
894 } else
895 retval = -EINVAL;
897 } else if (MATCH("green2_comp")) {
898 if (!retval)
899 val = VALUE;
901 if (!retval) {
902 if (val >= 214 && val <= 255) {
903 new_params.exposure.green2Comp = val;
904 command_flags |= COMMAND_SETEXPOSURE;
905 } else
906 retval = -EINVAL;
908 } else if (MATCH("blue_comp")) {
909 if (!retval)
910 val = VALUE;
912 if (!retval) {
913 if (val >= 230 && val <= 255) {
914 new_params.exposure.blueComp = val;
915 command_flags |= COMMAND_SETEXPOSURE;
916 } else
917 retval = -EINVAL;
919 } else if (MATCH("apcor_gain1")) {
920 if (!retval)
921 val = VALUE;
923 if (!retval) {
924 command_flags |= COMMAND_SETAPCOR;
925 if (val <= 0xff)
926 new_params.apcor.gain1 = val;
927 else
928 retval = -EINVAL;
930 } else if (MATCH("apcor_gain2")) {
931 if (!retval)
932 val = VALUE;
934 if (!retval) {
935 command_flags |= COMMAND_SETAPCOR;
936 if (val <= 0xff)
937 new_params.apcor.gain2 = val;
938 else
939 retval = -EINVAL;
941 } else if (MATCH("apcor_gain4")) {
942 if (!retval)
943 val = VALUE;
945 if (!retval) {
946 command_flags |= COMMAND_SETAPCOR;
947 if (val <= 0xff)
948 new_params.apcor.gain4 = val;
949 else
950 retval = -EINVAL;
952 } else if (MATCH("apcor_gain8")) {
953 if (!retval)
954 val = VALUE;
956 if (!retval) {
957 command_flags |= COMMAND_SETAPCOR;
958 if (val <= 0xff)
959 new_params.apcor.gain8 = val;
960 else
961 retval = -EINVAL;
963 } else if (MATCH("vl_offset_gain1")) {
964 if (!retval)
965 val = VALUE;
967 if (!retval) {
968 if (val <= 0xff)
969 new_params.vlOffset.gain1 = val;
970 else
971 retval = -EINVAL;
973 command_flags |= COMMAND_SETVLOFFSET;
974 } else if (MATCH("vl_offset_gain2")) {
975 if (!retval)
976 val = VALUE;
978 if (!retval) {
979 if (val <= 0xff)
980 new_params.vlOffset.gain2 = val;
981 else
982 retval = -EINVAL;
984 command_flags |= COMMAND_SETVLOFFSET;
985 } else if (MATCH("vl_offset_gain4")) {
986 if (!retval)
987 val = VALUE;
989 if (!retval) {
990 if (val <= 0xff)
991 new_params.vlOffset.gain4 = val;
992 else
993 retval = -EINVAL;
995 command_flags |= COMMAND_SETVLOFFSET;
996 } else if (MATCH("vl_offset_gain8")) {
997 if (!retval)
998 val = VALUE;
1000 if (!retval) {
1001 if (val <= 0xff)
1002 new_params.vlOffset.gain8 = val;
1003 else
1004 retval = -EINVAL;
1006 command_flags |= COMMAND_SETVLOFFSET;
1007 } else if (MATCH("flicker_control")) {
1008 if (!retval && MATCH("on")) {
1009 new_params.flickerControl.flickerMode = 1;
1010 new_params.exposure.expMode = 2;
1011 command_flags |= COMMAND_SETEXPOSURE;
1012 } else if (!retval && MATCH("off"))
1013 new_params.flickerControl.flickerMode = 0;
1014 else
1015 retval = -EINVAL;
1017 command_flags |= COMMAND_SETFLICKERCTRL;
1018 } else if (MATCH("mains_frequency")) {
1019 if (!retval && MATCH("50")) {
1020 new_mains = 0;
1021 new_params.flickerControl.coarseJump =
1022 flicker_jumps[new_mains]
1023 [new_params.sensorFps.baserate]
1024 [new_params.sensorFps.divisor];
1025 if (new_params.flickerControl.flickerMode)
1026 command_flags |= COMMAND_SETFLICKERCTRL;
1027 } else if (!retval && MATCH("60")) {
1028 new_mains = 1;
1029 new_params.flickerControl.coarseJump =
1030 flicker_jumps[new_mains]
1031 [new_params.sensorFps.baserate]
1032 [new_params.sensorFps.divisor];
1033 if (new_params.flickerControl.flickerMode)
1034 command_flags |= COMMAND_SETFLICKERCTRL;
1035 } else
1036 retval = -EINVAL;
1037 } else if (MATCH("allowable_overexposure")) {
1038 if (!retval)
1039 val = VALUE;
1041 if (!retval) {
1042 if (val <= 0xff) {
1043 new_params.flickerControl.
1044 allowableOverExposure = val;
1045 command_flags |= COMMAND_SETFLICKERCTRL;
1046 } else
1047 retval = -EINVAL;
1049 } else if (MATCH("compression_mode")) {
1050 if (!retval && MATCH("none"))
1051 new_params.compression.mode =
1052 CPIA_COMPRESSION_NONE;
1053 else if (!retval && MATCH("auto"))
1054 new_params.compression.mode =
1055 CPIA_COMPRESSION_AUTO;
1056 else if (!retval && MATCH("manual"))
1057 new_params.compression.mode =
1058 CPIA_COMPRESSION_MANUAL;
1059 else
1060 retval = -EINVAL;
1062 command_flags |= COMMAND_SETCOMPRESSION;
1063 } else if (MATCH("decimation_enable")) {
1064 if (!retval && MATCH("off"))
1065 new_params.compression.decimation = 0;
1066 else
1067 retval = -EINVAL;
1069 command_flags |= COMMAND_SETCOMPRESSION;
1070 } else if (MATCH("compression_target")) {
1071 if (!retval && MATCH("quality"))
1072 new_params.compressionTarget.frTargeting =
1073 CPIA_COMPRESSION_TARGET_QUALITY;
1074 else if (!retval && MATCH("framerate"))
1075 new_params.compressionTarget.frTargeting =
1076 CPIA_COMPRESSION_TARGET_FRAMERATE;
1077 else
1078 retval = -EINVAL;
1080 command_flags |= COMMAND_SETCOMPRESSIONTARGET;
1081 } else if (MATCH("target_framerate")) {
1082 if (!retval)
1083 val = VALUE;
1085 if (!retval)
1086 new_params.compressionTarget.targetFR = val;
1087 command_flags |= COMMAND_SETCOMPRESSIONTARGET;
1088 } else if (MATCH("target_quality")) {
1089 if (!retval)
1090 val = VALUE;
1092 if (!retval)
1093 new_params.compressionTarget.targetQ = val;
1095 command_flags |= COMMAND_SETCOMPRESSIONTARGET;
1096 } else if (MATCH("y_threshold")) {
1097 if (!retval)
1098 val = VALUE;
1100 if (!retval) {
1101 if (val < 32)
1102 new_params.yuvThreshold.yThreshold = val;
1103 else
1104 retval = -EINVAL;
1106 command_flags |= COMMAND_SETYUVTHRESH;
1107 } else if (MATCH("uv_threshold")) {
1108 if (!retval)
1109 val = VALUE;
1111 if (!retval) {
1112 if (val < 32)
1113 new_params.yuvThreshold.uvThreshold = val;
1114 else
1115 retval = -EINVAL;
1117 command_flags |= COMMAND_SETYUVTHRESH;
1118 } else if (MATCH("hysteresis")) {
1119 if (!retval)
1120 val = VALUE;
1122 if (!retval) {
1123 if (val <= 0xff)
1124 new_params.compressionParams.hysteresis = val;
1125 else
1126 retval = -EINVAL;
1128 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1129 } else if (MATCH("threshold_max")) {
1130 if (!retval)
1131 val = VALUE;
1133 if (!retval) {
1134 if (val <= 0xff)
1135 new_params.compressionParams.threshMax = val;
1136 else
1137 retval = -EINVAL;
1139 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1140 } else if (MATCH("small_step")) {
1141 if (!retval)
1142 val = VALUE;
1144 if (!retval) {
1145 if (val <= 0xff)
1146 new_params.compressionParams.smallStep = val;
1147 else
1148 retval = -EINVAL;
1150 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1151 } else if (MATCH("large_step")) {
1152 if (!retval)
1153 val = VALUE;
1155 if (!retval) {
1156 if (val <= 0xff)
1157 new_params.compressionParams.largeStep = val;
1158 else
1159 retval = -EINVAL;
1161 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1162 } else if (MATCH("decimation_hysteresis")) {
1163 if (!retval)
1164 val = VALUE;
1166 if (!retval) {
1167 if (val <= 0xff)
1168 new_params.compressionParams.decimationHysteresis = val;
1169 else
1170 retval = -EINVAL;
1172 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1173 } else if (MATCH("fr_diff_step_thresh")) {
1174 if (!retval)
1175 val = VALUE;
1177 if (!retval) {
1178 if (val <= 0xff)
1179 new_params.compressionParams.frDiffStepThresh = val;
1180 else
1181 retval = -EINVAL;
1183 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1184 } else if (MATCH("q_diff_step_thresh")) {
1185 if (!retval)
1186 val = VALUE;
1188 if (!retval) {
1189 if (val <= 0xff)
1190 new_params.compressionParams.qDiffStepThresh = val;
1191 else
1192 retval = -EINVAL;
1194 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1195 } else if (MATCH("decimation_thresh_mod")) {
1196 if (!retval)
1197 val = VALUE;
1199 if (!retval) {
1200 if (val <= 0xff)
1201 new_params.compressionParams.decimationThreshMod = val;
1202 else
1203 retval = -EINVAL;
1205 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1206 } else {
1207 DBG("No match found\n");
1208 retval = -EINVAL;
1211 if (!retval) {
1212 while (count && isspace(*buffer) && *buffer != '\n') {
1213 --count;
1214 ++buffer;
1216 if (count) {
1217 if (*buffer != '\n' && *buffer != ';')
1218 retval = -EINVAL;
1219 else {
1220 --count;
1221 ++buffer;
1226 #undef MATCH
1227 #undef FIRMWARE_VERSION
1228 #undef VALUE
1229 #undef FIND_VALUE
1230 #undef FIND_END
1231 if (!retval) {
1232 if (command_flags & COMMAND_SETCOLOURPARAMS) {
1233 /* Adjust cam->vp to reflect these changes */
1234 cam->vp.brightness =
1235 new_params.colourParams.brightness*65535/100;
1236 cam->vp.contrast =
1237 new_params.colourParams.contrast*65535/100;
1238 cam->vp.colour =
1239 new_params.colourParams.saturation*65535/100;
1242 memcpy(&cam->params, &new_params, sizeof(struct cam_params));
1243 cam->mainsFreq = new_mains;
1244 cam->cmd_queue |= command_flags;
1245 retval = size;
1246 } else
1247 DBG("error: %d\n", retval);
1249 up(&cam->param_lock);
1251 return retval;
1254 static void create_proc_cpia_cam(struct cam_data *cam)
1256 char name[7];
1257 struct proc_dir_entry *ent;
1259 if (!cpia_proc_root || !cam)
1260 return;
1262 sprintf(name, "video%d", cam->vdev.minor);
1264 ent = create_proc_entry(name, S_IFREG|S_IRUGO|S_IWUSR, cpia_proc_root);
1265 if (!ent)
1266 return;
1268 ent->data = cam;
1269 ent->read_proc = cpia_read_proc;
1270 ent->write_proc = cpia_write_proc;
1271 ent->size = 3626;
1272 cam->proc_entry = ent;
1275 static void destroy_proc_cpia_cam(struct cam_data *cam)
1277 char name[7];
1279 if (!cam || !cam->proc_entry)
1280 return;
1282 sprintf(name, "video%d", cam->vdev.minor);
1283 remove_proc_entry(name, cpia_proc_root);
1284 cam->proc_entry = NULL;
1287 static void proc_cpia_create(void)
1289 cpia_proc_root = create_proc_entry("cpia", S_IFDIR, 0);
1291 if (cpia_proc_root)
1292 cpia_proc_root->owner = THIS_MODULE;
1293 else
1294 LOG("Unable to initialise /proc/cpia\n");
1297 static void proc_cpia_destroy(void)
1299 remove_proc_entry("cpia", 0);
1301 #endif /* CONFIG_PROC_FS */
1303 /* ----------------------- debug functions ---------------------- */
1305 #define printstatus(cam) \
1306 DBG("%02x %02x %02x %02x %02x %02x %02x %02x\n",\
1307 cam->params.status.systemState, cam->params.status.grabState, \
1308 cam->params.status.streamState, cam->params.status.fatalError, \
1309 cam->params.status.cmdError, cam->params.status.debugFlags, \
1310 cam->params.status.vpStatus, cam->params.status.errorCode);
1312 /* ----------------------- v4l helpers -------------------------- */
1314 /* supported frame palettes and depths */
1315 static inline int valid_mode(u16 palette, u16 depth)
1317 return (palette == VIDEO_PALETTE_GREY && depth == 8) ||
1318 (palette == VIDEO_PALETTE_RGB555 && depth == 16) ||
1319 (palette == VIDEO_PALETTE_RGB565 && depth == 16) ||
1320 (palette == VIDEO_PALETTE_RGB24 && depth == 24) ||
1321 (palette == VIDEO_PALETTE_RGB32 && depth == 32) ||
1322 (palette == VIDEO_PALETTE_YUV422 && depth == 16) ||
1323 (palette == VIDEO_PALETTE_YUYV && depth == 16) ||
1324 (palette == VIDEO_PALETTE_UYVY && depth == 16);
1327 static int match_videosize( int width, int height )
1329 /* return the best match, where 'best' is as always
1330 * the largest that is not bigger than what is requested. */
1331 if (width>=352 && height>=288)
1332 return VIDEOSIZE_352_288; /* CIF */
1334 if (width>=320 && height>=240)
1335 return VIDEOSIZE_320_240; /* SIF */
1337 if (width>=288 && height>=216)
1338 return VIDEOSIZE_288_216;
1340 if (width>=256 && height>=192)
1341 return VIDEOSIZE_256_192;
1343 if (width>=224 && height>=168)
1344 return VIDEOSIZE_224_168;
1346 if (width>=192 && height>=144)
1347 return VIDEOSIZE_192_144;
1349 if (width>=176 && height>=144)
1350 return VIDEOSIZE_176_144; /* QCIF */
1352 if (width>=160 && height>=120)
1353 return VIDEOSIZE_160_120; /* QSIF */
1355 if (width>=128 && height>=96)
1356 return VIDEOSIZE_128_96;
1358 if (width>=88 && height>=72)
1359 return VIDEOSIZE_88_72;
1361 if (width>=64 && height>=48)
1362 return VIDEOSIZE_64_48;
1364 if (width>=48 && height>=48)
1365 return VIDEOSIZE_48_48;
1367 return -1;
1370 /* these are the capture sizes we support */
1371 static void set_vw_size(struct cam_data *cam)
1373 /* the col/row/start/end values are the result of simple math */
1374 /* study the SetROI-command in cpia developers guide p 2-22 */
1375 /* streamStartLine is set to the recommended value in the cpia */
1376 /* developers guide p 3-37 */
1377 switch(cam->video_size) {
1378 case VIDEOSIZE_CIF:
1379 cam->vw.width = 352;
1380 cam->vw.height = 288;
1381 cam->params.format.videoSize=VIDEOSIZE_CIF;
1382 cam->params.roi.colStart=0;
1383 cam->params.roi.colEnd=44;
1384 cam->params.roi.rowStart=0;
1385 cam->params.roi.rowEnd=72;
1386 cam->params.streamStartLine = 120;
1387 break;
1388 case VIDEOSIZE_SIF:
1389 cam->vw.width = 320;
1390 cam->vw.height = 240;
1391 cam->params.format.videoSize=VIDEOSIZE_CIF;
1392 cam->params.roi.colStart=2;
1393 cam->params.roi.colEnd=42;
1394 cam->params.roi.rowStart=6;
1395 cam->params.roi.rowEnd=66;
1396 cam->params.streamStartLine = 120;
1397 break;
1398 case VIDEOSIZE_288_216:
1399 cam->vw.width = 288;
1400 cam->vw.height = 216;
1401 cam->params.format.videoSize=VIDEOSIZE_CIF;
1402 cam->params.roi.colStart=4;
1403 cam->params.roi.colEnd=40;
1404 cam->params.roi.rowStart=9;
1405 cam->params.roi.rowEnd=63;
1406 cam->params.streamStartLine = 120;
1407 break;
1408 case VIDEOSIZE_256_192:
1409 cam->vw.width = 256;
1410 cam->vw.height = 192;
1411 cam->params.format.videoSize=VIDEOSIZE_CIF;
1412 cam->params.roi.colStart=6;
1413 cam->params.roi.colEnd=38;
1414 cam->params.roi.rowStart=12;
1415 cam->params.roi.rowEnd=60;
1416 cam->params.streamStartLine = 120;
1417 break;
1418 case VIDEOSIZE_224_168:
1419 cam->vw.width = 224;
1420 cam->vw.height = 168;
1421 cam->params.format.videoSize=VIDEOSIZE_CIF;
1422 cam->params.roi.colStart=8;
1423 cam->params.roi.colEnd=36;
1424 cam->params.roi.rowStart=15;
1425 cam->params.roi.rowEnd=57;
1426 cam->params.streamStartLine = 120;
1427 break;
1428 case VIDEOSIZE_192_144:
1429 cam->vw.width = 192;
1430 cam->vw.height = 144;
1431 cam->params.format.videoSize=VIDEOSIZE_CIF;
1432 cam->params.roi.colStart=10;
1433 cam->params.roi.colEnd=34;
1434 cam->params.roi.rowStart=18;
1435 cam->params.roi.rowEnd=54;
1436 cam->params.streamStartLine = 120;
1437 break;
1438 case VIDEOSIZE_QCIF:
1439 cam->vw.width = 176;
1440 cam->vw.height = 144;
1441 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1442 cam->params.roi.colStart=0;
1443 cam->params.roi.colEnd=22;
1444 cam->params.roi.rowStart=0;
1445 cam->params.roi.rowEnd=36;
1446 cam->params.streamStartLine = 60;
1447 break;
1448 case VIDEOSIZE_QSIF:
1449 cam->vw.width = 160;
1450 cam->vw.height = 120;
1451 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1452 cam->params.roi.colStart=1;
1453 cam->params.roi.colEnd=21;
1454 cam->params.roi.rowStart=3;
1455 cam->params.roi.rowEnd=33;
1456 cam->params.streamStartLine = 60;
1457 break;
1458 case VIDEOSIZE_128_96:
1459 cam->vw.width = 128;
1460 cam->vw.height = 96;
1461 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1462 cam->params.roi.colStart=3;
1463 cam->params.roi.colEnd=19;
1464 cam->params.roi.rowStart=6;
1465 cam->params.roi.rowEnd=30;
1466 cam->params.streamStartLine = 60;
1467 break;
1468 case VIDEOSIZE_88_72:
1469 cam->vw.width = 88;
1470 cam->vw.height = 72;
1471 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1472 cam->params.roi.colStart=5;
1473 cam->params.roi.colEnd=16;
1474 cam->params.roi.rowStart=9;
1475 cam->params.roi.rowEnd=27;
1476 cam->params.streamStartLine = 60;
1477 break;
1478 case VIDEOSIZE_64_48:
1479 cam->vw.width = 64;
1480 cam->vw.height = 48;
1481 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1482 cam->params.roi.colStart=7;
1483 cam->params.roi.colEnd=15;
1484 cam->params.roi.rowStart=12;
1485 cam->params.roi.rowEnd=24;
1486 cam->params.streamStartLine = 60;
1487 break;
1488 case VIDEOSIZE_48_48:
1489 cam->vw.width = 48;
1490 cam->vw.height = 48;
1491 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1492 cam->params.roi.colStart=8;
1493 cam->params.roi.colEnd=14;
1494 cam->params.roi.rowStart=6;
1495 cam->params.roi.rowEnd=30;
1496 cam->params.streamStartLine = 60;
1497 break;
1498 default:
1499 LOG("bad videosize value: %d\n", cam->video_size);
1502 return;
1505 static int allocate_frame_buf(struct cam_data *cam)
1507 int i;
1509 cam->frame_buf = rvmalloc(FRAME_NUM * CPIA_MAX_FRAME_SIZE);
1510 if (!cam->frame_buf)
1511 return -ENOBUFS;
1513 for (i = 0; i < FRAME_NUM; i++)
1514 cam->frame[i].data = cam->frame_buf + i * CPIA_MAX_FRAME_SIZE;
1516 return 0;
1519 static int free_frame_buf(struct cam_data *cam)
1521 int i;
1523 rvfree(cam->frame_buf, FRAME_NUM*CPIA_MAX_FRAME_SIZE);
1524 cam->frame_buf = 0;
1525 for (i=0; i < FRAME_NUM; i++)
1526 cam->frame[i].data = NULL;
1528 return 0;
1532 static void inline free_frames(struct cpia_frame frame[FRAME_NUM])
1534 int i;
1536 for (i=0; i < FRAME_NUM; i++)
1537 frame[i].state = FRAME_UNUSED;
1538 return;
1541 /**********************************************************************
1543 * General functions
1545 **********************************************************************/
1546 /* send an arbitrary command to the camera */
1547 static int do_command(struct cam_data *cam, u16 command, u8 a, u8 b, u8 c, u8 d)
1549 int retval, datasize;
1550 u8 cmd[8], data[8];
1552 switch(command) {
1553 case CPIA_COMMAND_GetCPIAVersion:
1554 case CPIA_COMMAND_GetPnPID:
1555 case CPIA_COMMAND_GetCameraStatus:
1556 case CPIA_COMMAND_GetVPVersion:
1557 datasize=8;
1558 break;
1559 case CPIA_COMMAND_GetColourParams:
1560 case CPIA_COMMAND_GetColourBalance:
1561 case CPIA_COMMAND_GetExposure:
1562 down(&cam->param_lock);
1563 datasize=8;
1564 break;
1565 default:
1566 datasize=0;
1567 break;
1570 cmd[0] = command>>8;
1571 cmd[1] = command&0xff;
1572 cmd[2] = a;
1573 cmd[3] = b;
1574 cmd[4] = c;
1575 cmd[5] = d;
1576 cmd[6] = datasize;
1577 cmd[7] = 0;
1579 retval = cam->ops->transferCmd(cam->lowlevel_data, cmd, data);
1580 if (retval) {
1581 DBG("%x - failed, retval=%d\n", command, retval);
1582 if (command == CPIA_COMMAND_GetColourParams ||
1583 command == CPIA_COMMAND_GetColourBalance ||
1584 command == CPIA_COMMAND_GetExposure)
1585 up(&cam->param_lock);
1586 } else {
1587 switch(command) {
1588 case CPIA_COMMAND_GetCPIAVersion:
1589 cam->params.version.firmwareVersion = data[0];
1590 cam->params.version.firmwareRevision = data[1];
1591 cam->params.version.vcVersion = data[2];
1592 cam->params.version.vcRevision = data[3];
1593 break;
1594 case CPIA_COMMAND_GetPnPID:
1595 cam->params.pnpID.vendor = data[0]+(((u16)data[1])<<8);
1596 cam->params.pnpID.product = data[2]+(((u16)data[3])<<8);
1597 cam->params.pnpID.deviceRevision =
1598 data[4]+(((u16)data[5])<<8);
1599 break;
1600 case CPIA_COMMAND_GetCameraStatus:
1601 cam->params.status.systemState = data[0];
1602 cam->params.status.grabState = data[1];
1603 cam->params.status.streamState = data[2];
1604 cam->params.status.fatalError = data[3];
1605 cam->params.status.cmdError = data[4];
1606 cam->params.status.debugFlags = data[5];
1607 cam->params.status.vpStatus = data[6];
1608 cam->params.status.errorCode = data[7];
1609 break;
1610 case CPIA_COMMAND_GetVPVersion:
1611 cam->params.vpVersion.vpVersion = data[0];
1612 cam->params.vpVersion.vpRevision = data[1];
1613 cam->params.vpVersion.cameraHeadID =
1614 data[2]+(((u16)data[3])<<8);
1615 break;
1616 case CPIA_COMMAND_GetColourParams:
1617 cam->params.colourParams.brightness = data[0];
1618 cam->params.colourParams.contrast = data[1];
1619 cam->params.colourParams.saturation = data[2];
1620 up(&cam->param_lock);
1621 break;
1622 case CPIA_COMMAND_GetColourBalance:
1623 cam->params.colourBalance.redGain = data[0];
1624 cam->params.colourBalance.greenGain = data[1];
1625 cam->params.colourBalance.blueGain = data[2];
1626 up(&cam->param_lock);
1627 break;
1628 case CPIA_COMMAND_GetExposure:
1629 cam->params.exposure.gain = data[0];
1630 cam->params.exposure.fineExp = data[1];
1631 cam->params.exposure.coarseExpLo = data[2];
1632 cam->params.exposure.coarseExpHi = data[3];
1633 cam->params.exposure.redComp = data[4];
1634 cam->params.exposure.green1Comp = data[5];
1635 cam->params.exposure.green2Comp = data[6];
1636 cam->params.exposure.blueComp = data[7];
1637 /* If the *Comp parameters are wacko, generate
1638 * a warning, and reset them back to default
1639 * values. - rich@annexia.org
1641 if (cam->params.exposure.redComp < 220 ||
1642 cam->params.exposure.redComp > 255 ||
1643 cam->params.exposure.green1Comp < 214 ||
1644 cam->params.exposure.green1Comp > 255 ||
1645 cam->params.exposure.green2Comp < 214 ||
1646 cam->params.exposure.green2Comp > 255 ||
1647 cam->params.exposure.blueComp < 230 ||
1648 cam->params.exposure.blueComp > 255)
1650 printk (KERN_WARNING "*_comp parameters have gone AWOL (%d/%d/%d/%d) - reseting them\n",
1651 cam->params.exposure.redComp,
1652 cam->params.exposure.green1Comp,
1653 cam->params.exposure.green2Comp,
1654 cam->params.exposure.blueComp);
1655 cam->params.exposure.redComp = 220;
1656 cam->params.exposure.green1Comp = 214;
1657 cam->params.exposure.green2Comp = 214;
1658 cam->params.exposure.blueComp = 230;
1660 up(&cam->param_lock);
1661 break;
1662 default:
1663 break;
1666 return retval;
1669 /* send a command to the camera with an additional data transaction */
1670 static int do_command_extended(struct cam_data *cam, u16 command,
1671 u8 a, u8 b, u8 c, u8 d,
1672 u8 e, u8 f, u8 g, u8 h,
1673 u8 i, u8 j, u8 k, u8 l)
1675 int retval;
1676 u8 cmd[8], data[8];
1678 cmd[0] = command>>8;
1679 cmd[1] = command&0xff;
1680 cmd[2] = a;
1681 cmd[3] = b;
1682 cmd[4] = c;
1683 cmd[5] = d;
1684 cmd[6] = 8;
1685 cmd[7] = 0;
1686 data[0] = e;
1687 data[1] = f;
1688 data[2] = g;
1689 data[3] = h;
1690 data[4] = i;
1691 data[5] = j;
1692 data[6] = k;
1693 data[7] = l;
1695 retval = cam->ops->transferCmd(cam->lowlevel_data, cmd, data);
1696 if (retval)
1697 LOG("%x - failed\n", command);
1699 return retval;
1702 /**********************************************************************
1704 * Colorspace conversion
1706 **********************************************************************/
1707 #define LIMIT(x) ((((x)>0xffffff)?0xff0000:(((x)<=0xffff)?0:(x)&0xff0000))>>16)
1709 static int yuvconvert(unsigned char *yuv, unsigned char *rgb, int out_fmt,
1710 int in_uyvy, int mmap_kludge)
1712 int y, u, v, r, g, b, y1;
1714 switch(out_fmt) {
1715 case VIDEO_PALETTE_RGB555:
1716 case VIDEO_PALETTE_RGB565:
1717 case VIDEO_PALETTE_RGB24:
1718 case VIDEO_PALETTE_RGB32:
1719 if (in_uyvy) {
1720 u = *yuv++ - 128;
1721 y = (*yuv++ - 16) * 76310;
1722 v = *yuv++ - 128;
1723 y1 = (*yuv - 16) * 76310;
1724 } else {
1725 y = (*yuv++ - 16) * 76310;
1726 u = *yuv++ - 128;
1727 y1 = (*yuv++ - 16) * 76310;
1728 v = *yuv - 128;
1730 r = 104635 * v;
1731 g = -25690 * u + -53294 * v;
1732 b = 132278 * u;
1733 break;
1734 default:
1735 y = *yuv++;
1736 u = *yuv++;
1737 y1 = *yuv++;
1738 v = *yuv;
1739 /* Just to avoid compiler warnings */
1740 r = 0;
1741 g = 0;
1742 b = 0;
1743 break;
1745 switch(out_fmt) {
1746 case VIDEO_PALETTE_RGB555:
1747 *rgb++ = ((LIMIT(g+y) & 0xf8) << 2) | (LIMIT(b+y) >> 3);
1748 *rgb++ = ((LIMIT(r+y) & 0xf8) >> 1) | (LIMIT(g+y) >> 6);
1749 *rgb++ = ((LIMIT(g+y1) & 0xf8) << 2) | (LIMIT(b+y1) >> 3);
1750 *rgb = ((LIMIT(r+y1) & 0xf8) >> 1) | (LIMIT(g+y1) >> 6);
1751 return 4;
1752 case VIDEO_PALETTE_RGB565:
1753 *rgb++ = ((LIMIT(g+y) & 0xfc) << 3) | (LIMIT(b+y) >> 3);
1754 *rgb++ = (LIMIT(r+y) & 0xf8) | (LIMIT(g+y) >> 5);
1755 *rgb++ = ((LIMIT(g+y1) & 0xfc) << 3) | (LIMIT(b+y1) >> 3);
1756 *rgb = (LIMIT(r+y1) & 0xf8) | (LIMIT(g+y1) >> 5);
1757 return 4;
1758 case VIDEO_PALETTE_RGB24:
1759 if (mmap_kludge) {
1760 *rgb++ = LIMIT(b+y);
1761 *rgb++ = LIMIT(g+y);
1762 *rgb++ = LIMIT(r+y);
1763 *rgb++ = LIMIT(b+y1);
1764 *rgb++ = LIMIT(g+y1);
1765 *rgb = LIMIT(r+y1);
1766 } else {
1767 *rgb++ = LIMIT(r+y);
1768 *rgb++ = LIMIT(g+y);
1769 *rgb++ = LIMIT(b+y);
1770 *rgb++ = LIMIT(r+y1);
1771 *rgb++ = LIMIT(g+y1);
1772 *rgb = LIMIT(b+y1);
1774 return 6;
1775 case VIDEO_PALETTE_RGB32:
1776 if (mmap_kludge) {
1777 *rgb++ = LIMIT(b+y);
1778 *rgb++ = LIMIT(g+y);
1779 *rgb++ = LIMIT(r+y);
1780 rgb++;
1781 *rgb++ = LIMIT(b+y1);
1782 *rgb++ = LIMIT(g+y1);
1783 *rgb = LIMIT(r+y1);
1784 } else {
1785 *rgb++ = LIMIT(r+y);
1786 *rgb++ = LIMIT(g+y);
1787 *rgb++ = LIMIT(b+y);
1788 rgb++;
1789 *rgb++ = LIMIT(r+y1);
1790 *rgb++ = LIMIT(g+y1);
1791 *rgb = LIMIT(b+y1);
1793 return 8;
1794 case VIDEO_PALETTE_GREY:
1795 *rgb++ = y;
1796 *rgb = y1;
1797 return 2;
1798 case VIDEO_PALETTE_YUV422:
1799 case VIDEO_PALETTE_YUYV:
1800 *rgb++ = y;
1801 *rgb++ = u;
1802 *rgb++ = y1;
1803 *rgb = v;
1804 return 4;
1805 case VIDEO_PALETTE_UYVY:
1806 *rgb++ = u;
1807 *rgb++ = y;
1808 *rgb++ = v;
1809 *rgb = y1;
1810 return 4;
1811 default:
1812 DBG("Empty: %d\n", out_fmt);
1813 return 0;
1817 static int skipcount(int count, int fmt)
1819 switch(fmt) {
1820 case VIDEO_PALETTE_GREY:
1821 case VIDEO_PALETTE_RGB555:
1822 case VIDEO_PALETTE_RGB565:
1823 case VIDEO_PALETTE_YUV422:
1824 case VIDEO_PALETTE_YUYV:
1825 case VIDEO_PALETTE_UYVY:
1826 return 2*count;
1827 case VIDEO_PALETTE_RGB24:
1828 return 3*count;
1829 case VIDEO_PALETTE_RGB32:
1830 return 4*count;
1831 default:
1832 return 0;
1836 static int parse_picture(struct cam_data *cam, int size)
1838 u8 *obuf, *ibuf, *end_obuf;
1839 int ll, in_uyvy, compressed, origsize, out_fmt;
1841 /* make sure params don't change while we are decoding */
1842 down(&cam->param_lock);
1844 obuf = cam->decompressed_frame.data;
1845 end_obuf = obuf+CPIA_MAX_FRAME_SIZE;
1846 ibuf = cam->raw_image;
1847 origsize = size;
1848 out_fmt = cam->vp.palette;
1850 if ((ibuf[0] != MAGIC_0) || (ibuf[1] != MAGIC_1)) {
1851 LOG("header not found\n");
1852 up(&cam->param_lock);
1853 return -1;
1856 if ((ibuf[16] != VIDEOSIZE_QCIF) && (ibuf[16] != VIDEOSIZE_CIF)) {
1857 LOG("wrong video size\n");
1858 up(&cam->param_lock);
1859 return -1;
1862 if (ibuf[17] != SUBSAMPLE_422) {
1863 LOG("illegal subtype %d\n",ibuf[17]);
1864 up(&cam->param_lock);
1865 return -1;
1868 if (ibuf[18] != YUVORDER_YUYV && ibuf[18] != YUVORDER_UYVY) {
1869 LOG("illegal yuvorder %d\n",ibuf[18]);
1870 up(&cam->param_lock);
1871 return -1;
1873 in_uyvy = ibuf[18] == YUVORDER_UYVY;
1875 #if 0
1876 /* FIXME: ROI mismatch occurs when switching capture sizes */
1877 if ((ibuf[24] != cam->params.roi.colStart) ||
1878 (ibuf[25] != cam->params.roi.colEnd) ||
1879 (ibuf[26] != cam->params.roi.rowStart) ||
1880 (ibuf[27] != cam->params.roi.rowEnd)) {
1881 LOG("ROI mismatch\n");
1882 up(&cam->param_lock);
1883 return -1;
1885 #endif
1887 if ((ibuf[28] != NOT_COMPRESSED) && (ibuf[28] != COMPRESSED)) {
1888 LOG("illegal compression %d\n",ibuf[28]);
1889 up(&cam->param_lock);
1890 return -1;
1892 compressed = (ibuf[28] == COMPRESSED);
1894 if (ibuf[29] != NO_DECIMATION) {
1895 LOG("decimation not supported\n");
1896 up(&cam->param_lock);
1897 return -1;
1900 cam->params.yuvThreshold.yThreshold = ibuf[30];
1901 cam->params.yuvThreshold.uvThreshold = ibuf[31];
1902 cam->params.status.systemState = ibuf[32];
1903 cam->params.status.grabState = ibuf[33];
1904 cam->params.status.streamState = ibuf[34];
1905 cam->params.status.fatalError = ibuf[35];
1906 cam->params.status.cmdError = ibuf[36];
1907 cam->params.status.debugFlags = ibuf[37];
1908 cam->params.status.vpStatus = ibuf[38];
1909 cam->params.status.errorCode = ibuf[39];
1910 cam->fps = ibuf[41];
1911 up(&cam->param_lock);
1913 ibuf += FRAME_HEADER_SIZE;
1914 size -= FRAME_HEADER_SIZE;
1915 ll = ibuf[0] | (ibuf[1] << 8);
1916 ibuf += 2;
1918 while (size > 0) {
1919 size -= (ll+2);
1920 if (size < 0) {
1921 LOG("Insufficient data in buffer\n");
1922 return -1;
1925 while (ll > 1) {
1926 if (!compressed || (compressed && !(*ibuf & 1))) {
1927 obuf += yuvconvert(ibuf, obuf, out_fmt,
1928 in_uyvy, cam->mmap_kludge);
1929 ibuf += 4;
1930 ll -= 4;
1931 } else {
1932 /*skip compressed interval from previous frame*/
1933 int skipsize = skipcount(*ibuf >> 1, out_fmt);
1934 obuf += skipsize;
1935 if (obuf > end_obuf) {
1936 LOG("Insufficient data in buffer\n");
1937 return -1;
1939 ++ibuf;
1940 ll--;
1943 if (ll == 1) {
1944 if (*ibuf != EOL) {
1945 LOG("EOL not found giving up after %d/%d"
1946 " bytes\n", origsize-size, origsize);
1947 return -1;
1950 ibuf++; /* skip over EOL */
1952 if ((size > 3) && (ibuf[0] == EOI) && (ibuf[1] == EOI) &&
1953 (ibuf[2] == EOI) && (ibuf[3] == EOI)) {
1954 size -= 4;
1955 break;
1958 if (size > 1) {
1959 ll = ibuf[0] | (ibuf[1] << 8);
1960 ibuf += 2; /* skip over line length */
1962 } else {
1963 LOG("line length was not 1 but %d after %d/%d bytes\n",
1964 ll, origsize-size, origsize);
1965 return -1;
1969 cam->decompressed_frame.count = obuf-cam->decompressed_frame.data;
1971 return cam->decompressed_frame.count;
1974 /* InitStreamCap wrapper to select correct start line */
1975 static inline int init_stream_cap(struct cam_data *cam)
1977 return do_command(cam, CPIA_COMMAND_InitStreamCap,
1978 0, cam->params.streamStartLine, 0, 0);
1981 /* update various camera modes and settings */
1982 static void dispatch_commands(struct cam_data *cam)
1984 down(&cam->param_lock);
1985 if (cam->cmd_queue==COMMAND_NONE) {
1986 up(&cam->param_lock);
1987 return;
1989 DEB_BYTE(cam->cmd_queue);
1990 DEB_BYTE(cam->cmd_queue>>8);
1991 if (cam->cmd_queue & COMMAND_SETCOLOURPARAMS)
1992 do_command(cam, CPIA_COMMAND_SetColourParams,
1993 cam->params.colourParams.brightness,
1994 cam->params.colourParams.contrast,
1995 cam->params.colourParams.saturation, 0);
1997 if (cam->cmd_queue & COMMAND_SETCOMPRESSION)
1998 do_command(cam, CPIA_COMMAND_SetCompression,
1999 cam->params.compression.mode,
2000 cam->params.compression.decimation, 0, 0);
2002 if (cam->cmd_queue & COMMAND_SETFORMAT) {
2003 do_command(cam, CPIA_COMMAND_SetFormat,
2004 cam->params.format.videoSize,
2005 cam->params.format.subSample,
2006 cam->params.format.yuvOrder, 0);
2007 do_command(cam, CPIA_COMMAND_SetROI,
2008 cam->params.roi.colStart, cam->params.roi.colEnd,
2009 cam->params.roi.rowStart, cam->params.roi.rowEnd);
2010 cam->first_frame = 1;
2013 if (cam->cmd_queue & COMMAND_SETCOMPRESSIONTARGET)
2014 do_command(cam, CPIA_COMMAND_SetCompressionTarget,
2015 cam->params.compressionTarget.frTargeting,
2016 cam->params.compressionTarget.targetFR,
2017 cam->params.compressionTarget.targetQ, 0);
2019 if (cam->cmd_queue & COMMAND_SETYUVTHRESH)
2020 do_command(cam, CPIA_COMMAND_SetYUVThresh,
2021 cam->params.yuvThreshold.yThreshold,
2022 cam->params.yuvThreshold.uvThreshold, 0, 0);
2024 if (cam->cmd_queue & COMMAND_SETECPTIMING)
2025 do_command(cam, CPIA_COMMAND_SetECPTiming,
2026 cam->params.ecpTiming, 0, 0, 0);
2028 if (cam->cmd_queue & COMMAND_SETCOMPRESSIONPARAMS)
2029 do_command_extended(cam, CPIA_COMMAND_SetCompressionParams,
2030 0, 0, 0, 0,
2031 cam->params.compressionParams.hysteresis,
2032 cam->params.compressionParams.threshMax,
2033 cam->params.compressionParams.smallStep,
2034 cam->params.compressionParams.largeStep,
2035 cam->params.compressionParams.decimationHysteresis,
2036 cam->params.compressionParams.frDiffStepThresh,
2037 cam->params.compressionParams.qDiffStepThresh,
2038 cam->params.compressionParams.decimationThreshMod);
2040 if (cam->cmd_queue & COMMAND_SETEXPOSURE)
2041 do_command_extended(cam, CPIA_COMMAND_SetExposure,
2042 cam->params.exposure.gainMode,
2043 cam->params.exposure.expMode,
2044 cam->params.exposure.compMode,
2045 cam->params.exposure.centreWeight,
2046 cam->params.exposure.gain,
2047 cam->params.exposure.fineExp,
2048 cam->params.exposure.coarseExpLo,
2049 cam->params.exposure.coarseExpHi,
2050 cam->params.exposure.redComp,
2051 cam->params.exposure.green1Comp,
2052 cam->params.exposure.green2Comp,
2053 cam->params.exposure.blueComp);
2055 if (cam->cmd_queue & COMMAND_SETCOLOURBALANCE) {
2056 if (cam->params.colourBalance.balanceModeIsAuto) {
2057 do_command(cam, CPIA_COMMAND_SetColourBalance,
2058 2, 0, 0, 0);
2059 } else {
2060 do_command(cam, CPIA_COMMAND_SetColourBalance,
2062 cam->params.colourBalance.redGain,
2063 cam->params.colourBalance.greenGain,
2064 cam->params.colourBalance.blueGain);
2065 do_command(cam, CPIA_COMMAND_SetColourBalance,
2066 3, 0, 0, 0);
2070 if (cam->cmd_queue & COMMAND_SETSENSORFPS)
2071 do_command(cam, CPIA_COMMAND_SetSensorFPS,
2072 cam->params.sensorFps.divisor,
2073 cam->params.sensorFps.baserate, 0, 0);
2075 if (cam->cmd_queue & COMMAND_SETAPCOR)
2076 do_command(cam, CPIA_COMMAND_SetApcor,
2077 cam->params.apcor.gain1,
2078 cam->params.apcor.gain2,
2079 cam->params.apcor.gain4,
2080 cam->params.apcor.gain8);
2082 if (cam->cmd_queue & COMMAND_SETFLICKERCTRL)
2083 do_command(cam, CPIA_COMMAND_SetFlickerCtrl,
2084 cam->params.flickerControl.flickerMode,
2085 cam->params.flickerControl.coarseJump,
2086 cam->params.flickerControl.allowableOverExposure, 0);
2088 if (cam->cmd_queue & COMMAND_SETVLOFFSET)
2089 do_command(cam, CPIA_COMMAND_SetVLOffset,
2090 cam->params.vlOffset.gain1,
2091 cam->params.vlOffset.gain2,
2092 cam->params.vlOffset.gain4,
2093 cam->params.vlOffset.gain8);
2095 if (cam->cmd_queue & COMMAND_PAUSE)
2096 do_command(cam, CPIA_COMMAND_EndStreamCap, 0, 0, 0, 0);
2098 if (cam->cmd_queue & COMMAND_RESUME)
2099 init_stream_cap(cam);
2101 up(&cam->param_lock);
2102 cam->cmd_queue = COMMAND_NONE;
2103 return;
2106 /* kernel thread function to read image from camera */
2107 static void fetch_frame(void *data)
2109 int image_size, retry;
2110 struct cam_data *cam = (struct cam_data *)data;
2111 unsigned long oldjif, rate, diff;
2113 /* Allow up to two bad images in a row to be read and
2114 * ignored before an error is reported */
2115 for (retry = 0; retry < 3; ++retry) {
2116 if (retry)
2117 DBG("retry=%d\n", retry);
2119 if (!cam->ops)
2120 continue;
2122 /* load first frame always uncompressed */
2123 if (cam->first_frame &&
2124 cam->params.compression.mode != CPIA_COMPRESSION_NONE)
2125 do_command(cam, CPIA_COMMAND_SetCompression,
2126 CPIA_COMPRESSION_NONE,
2127 NO_DECIMATION, 0, 0);
2129 /* init camera upload */
2130 if (do_command(cam, CPIA_COMMAND_SetGrabMode,
2131 CPIA_GRAB_CONTINUOUS, 0, 0, 0))
2132 continue;
2134 if (do_command(cam, CPIA_COMMAND_GrabFrame, 0,
2135 cam->params.streamStartLine, 0, 0))
2136 continue;
2138 if (cam->ops->wait_for_stream_ready) {
2139 /* loop until image ready */
2140 do_command(cam, CPIA_COMMAND_GetCameraStatus,0,0,0,0);
2141 while (cam->params.status.streamState != STREAM_READY) {
2142 if (current->need_resched)
2143 schedule();
2145 current->state = TASK_INTERRUPTIBLE;
2147 /* sleep for 10 ms, hopefully ;) */
2148 schedule_timeout(10*HZ/1000);
2149 if (signal_pending(current))
2150 return;
2152 do_command(cam, CPIA_COMMAND_GetCameraStatus,
2153 0, 0, 0, 0);
2157 /* grab image from camera */
2158 if (current->need_resched)
2159 schedule();
2161 oldjif = jiffies;
2162 image_size = cam->ops->streamRead(cam->lowlevel_data,
2163 cam->raw_image, 0);
2164 if (image_size <= 0) {
2165 DBG("streamRead failed: %d\n", image_size);
2166 continue;
2169 rate = image_size * HZ / 1024;
2170 diff = jiffies-oldjif;
2171 cam->transfer_rate = diff==0 ? rate : rate/diff;
2172 /* diff==0 ? unlikely but possible */
2174 /* camera idle now so dispatch queued commands */
2175 dispatch_commands(cam);
2177 /* Update our knowledge of the camera state - FIXME: necessary? */
2178 do_command(cam, CPIA_COMMAND_GetColourBalance, 0, 0, 0, 0);
2179 do_command(cam, CPIA_COMMAND_GetExposure, 0, 0, 0, 0);
2181 /* decompress and convert image to by copying it from
2182 * raw_image to decompressed_frame
2184 if (current->need_resched)
2185 schedule();
2187 cam->image_size = parse_picture(cam, image_size);
2188 if (cam->image_size <= 0)
2189 DBG("parse_picture failed %d\n", cam->image_size);
2190 else
2191 break;
2194 if (retry < 3) {
2195 /* FIXME: this only works for double buffering */
2196 if (cam->frame[cam->curframe].state == FRAME_READY) {
2197 memcpy(cam->frame[cam->curframe].data,
2198 cam->decompressed_frame.data,
2199 cam->decompressed_frame.count);
2200 cam->frame[cam->curframe].state = FRAME_DONE;
2201 } else
2202 cam->decompressed_frame.state = FRAME_DONE;
2204 #if 0
2205 if (cam->first_frame &&
2206 cam->params.compression.mode != CPIA_COMPRESSION_NONE) {
2207 cam->first_frame = 0;
2208 cam->cmd_queue |= COMMAND_SETCOMPRESSION;
2210 #else
2211 if (cam->first_frame) {
2212 cam->first_frame = 0;
2213 cam->cmd_queue |= COMMAND_SETCOMPRESSION;
2214 cam->cmd_queue |= COMMAND_SETEXPOSURE;
2216 #endif
2220 static int capture_frame(struct cam_data *cam, struct video_mmap *vm)
2222 int retval = 0;
2224 if (!cam->frame_buf) {
2225 /* we do lazy allocation */
2226 if ((retval = allocate_frame_buf(cam)))
2227 return retval;
2230 /* FIXME: the first frame seems to be captured by the camera
2231 without regards to any initial settings, so we throw away
2232 that one, the next one is generated with our settings
2233 (exposure, color balance, ...)
2235 if (cam->first_frame) {
2236 cam->curframe = vm->frame;
2237 cam->frame[cam->curframe].state = FRAME_READY;
2238 fetch_frame(cam);
2239 if (cam->frame[cam->curframe].state != FRAME_DONE)
2240 retval = -EIO;
2242 cam->curframe = vm->frame;
2243 cam->frame[cam->curframe].state = FRAME_READY;
2244 fetch_frame(cam);
2245 if (cam->frame[cam->curframe].state != FRAME_DONE)
2246 retval=-EIO;
2248 return retval;
2251 static int goto_high_power(struct cam_data *cam)
2253 if (do_command(cam, CPIA_COMMAND_GotoHiPower, 0, 0, 0, 0))
2254 return -1;
2255 mdelay(100); /* windows driver does it too */
2256 if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0))
2257 return -1;
2258 if (cam->params.status.systemState == HI_POWER_STATE) {
2259 DBG("camera now in HIGH power state\n");
2260 return 0;
2262 printstatus(cam);
2263 return -1;
2266 static int goto_low_power(struct cam_data *cam)
2268 if (do_command(cam, CPIA_COMMAND_GotoLoPower, 0, 0, 0, 0))
2269 return -1;
2270 if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0))
2271 return -1;
2272 if (cam->params.status.systemState == LO_POWER_STATE) {
2273 DBG("camera now in LOW power state\n");
2274 return 0;
2276 printstatus(cam);
2277 return -1;
2280 static void save_camera_state(struct cam_data *cam)
2282 do_command(cam, CPIA_COMMAND_GetColourBalance, 0, 0, 0, 0);
2283 do_command(cam, CPIA_COMMAND_GetExposure, 0, 0, 0, 0);
2285 DBG("%d/%d/%d/%d/%d/%d/%d/%d\n",
2286 cam->params.exposure.gain,
2287 cam->params.exposure.fineExp,
2288 cam->params.exposure.coarseExpLo,
2289 cam->params.exposure.coarseExpHi,
2290 cam->params.exposure.redComp,
2291 cam->params.exposure.green1Comp,
2292 cam->params.exposure.green2Comp,
2293 cam->params.exposure.blueComp);
2294 DBG("%d/%d/%d\n",
2295 cam->params.colourBalance.redGain,
2296 cam->params.colourBalance.greenGain,
2297 cam->params.colourBalance.blueGain);
2300 static void set_camera_state(struct cam_data *cam)
2302 if(cam->params.colourBalance.balanceModeIsAuto) {
2303 do_command(cam, CPIA_COMMAND_SetColourBalance,
2304 2, 0, 0, 0);
2305 } else {
2306 do_command(cam, CPIA_COMMAND_SetColourBalance,
2308 cam->params.colourBalance.redGain,
2309 cam->params.colourBalance.greenGain,
2310 cam->params.colourBalance.blueGain);
2311 do_command(cam, CPIA_COMMAND_SetColourBalance,
2312 3, 0, 0, 0);
2316 do_command_extended(cam, CPIA_COMMAND_SetExposure,
2317 cam->params.exposure.gainMode, 1, 1,
2318 cam->params.exposure.centreWeight,
2319 cam->params.exposure.gain,
2320 cam->params.exposure.fineExp,
2321 cam->params.exposure.coarseExpLo,
2322 cam->params.exposure.coarseExpHi,
2323 cam->params.exposure.redComp,
2324 cam->params.exposure.green1Comp,
2325 cam->params.exposure.green2Comp,
2326 cam->params.exposure.blueComp);
2327 do_command_extended(cam, CPIA_COMMAND_SetExposure,
2328 0, 3, 0, 0,
2329 0, 0, 0, 0, 0, 0, 0, 0);
2331 if (!cam->params.exposure.gainMode)
2332 cam->params.exposure.gainMode = 2;
2333 if (!cam->params.exposure.expMode)
2334 cam->params.exposure.expMode = 2;
2335 if (!cam->params.exposure.centreWeight)
2336 cam->params.exposure.centreWeight = 1;
2338 cam->cmd_queue = COMMAND_SETCOMPRESSION |
2339 COMMAND_SETCOMPRESSIONTARGET |
2340 COMMAND_SETCOLOURPARAMS |
2341 COMMAND_SETFORMAT |
2342 COMMAND_SETYUVTHRESH |
2343 COMMAND_SETECPTIMING |
2344 COMMAND_SETCOMPRESSIONPARAMS |
2345 #if 0
2346 COMMAND_SETEXPOSURE |
2347 #endif
2348 COMMAND_SETCOLOURBALANCE |
2349 COMMAND_SETSENSORFPS |
2350 COMMAND_SETAPCOR |
2351 COMMAND_SETFLICKERCTRL |
2352 COMMAND_SETVLOFFSET;
2353 dispatch_commands(cam);
2354 save_camera_state(cam);
2356 return;
2359 static void get_version_information(struct cam_data *cam)
2361 /* GetCPIAVersion */
2362 do_command(cam, CPIA_COMMAND_GetCPIAVersion, 0, 0, 0, 0);
2364 /* GetPnPID */
2365 do_command(cam, CPIA_COMMAND_GetPnPID, 0, 0, 0, 0);
2368 /* initialize camera */
2369 static int reset_camera(struct cam_data *cam)
2371 /* Start the camera in low power mode */
2372 if (goto_low_power(cam)) {
2373 if (cam->params.status.systemState != WARM_BOOT_STATE)
2374 return -ENODEV;
2376 /* FIXME: this is just dirty trial and error */
2377 reset_camera_struct(cam);
2378 goto_high_power(cam);
2379 do_command(cam, CPIA_COMMAND_DiscardFrame, 0, 0, 0, 0);
2380 if (goto_low_power(cam))
2381 return -NODEV;
2384 /* procedure described in developer's guide p3-28 */
2386 /* Check the firmware version FIXME: should we check PNPID? */
2387 cam->params.version.firmwareVersion = 0;
2388 get_version_information(cam);
2389 if (cam->params.version.firmwareVersion != 1)
2390 return -ENODEV;
2392 /* The fatal error checking should be done after
2393 * the camera powers up (developer's guide p 3-38) */
2395 /* Set streamState before transition to high power to avoid bug
2396 * in firmware 1-02 */
2397 do_command(cam, CPIA_COMMAND_ModifyCameraStatus, STREAMSTATE, 0,
2398 STREAM_NOT_READY, 0);
2400 /* GotoHiPower */
2401 if (goto_high_power(cam))
2402 return -ENODEV;
2404 /* Check the camera status */
2405 if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0))
2406 return -EIO;
2408 if (cam->params.status.fatalError) {
2409 DBG("fatal_error: %#04x\n",
2410 cam->params.status.fatalError);
2411 DBG("vp_status: %#04x\n",
2412 cam->params.status.vpStatus);
2413 if (cam->params.status.fatalError & ~(COM_FLAG|CPIA_FLAG)) {
2414 /* Fatal error in camera */
2415 return -EIO;
2416 } else if (cam->params.status.fatalError & (COM_FLAG|CPIA_FLAG)) {
2417 /* Firmware 1-02 may do this for parallel port cameras,
2418 * just clear the flags (developer's guide p 3-38) */
2419 do_command(cam, CPIA_COMMAND_ModifyCameraStatus,
2420 FATALERROR, ~(COM_FLAG|CPIA_FLAG), 0, 0);
2424 /* Check the camera status again */
2425 if (cam->params.status.fatalError) {
2426 if (cam->params.status.fatalError)
2427 return -EIO;
2430 /* VPVersion can't be retrieved before the camera is in HiPower,
2431 * so get it here instead of in get_version_information. */
2432 do_command(cam, CPIA_COMMAND_GetVPVersion, 0, 0, 0, 0);
2434 /* set camera to a known state */
2435 set_camera_state(cam);
2437 return 0;
2440 /* ------------------------- V4L interface --------------------- */
2441 static int cpia_open(struct video_device *dev, int flags)
2443 int i;
2444 struct cam_data *cam = dev->priv;
2446 if (!cam) {
2447 DBG("Internal error, cam_data not found!\n");
2448 return -EBUSY;
2451 if (cam->open_count > 0) {
2452 DBG("Camera already open\n");
2453 return -EBUSY;
2456 if (!cam->raw_image) {
2457 cam->raw_image = rvmalloc(CPIA_MAX_IMAGE_SIZE);
2458 if (!cam->raw_image)
2459 return -ENOMEM;
2462 if (!cam->decompressed_frame.data) {
2463 cam->decompressed_frame.data = rvmalloc(CPIA_MAX_FRAME_SIZE);
2464 if (!cam->decompressed_frame.data) {
2465 rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
2466 cam->raw_image = NULL;
2467 return -ENOMEM;
2471 /* open cpia */
2472 if (cam->ops->open(cam->lowlevel_data)) {
2473 rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE);
2474 cam->decompressed_frame.data = NULL;
2475 rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
2476 cam->raw_image = NULL;
2477 return -ENODEV;
2480 /* reset the camera */
2481 if ((i = reset_camera(cam)) != 0) {
2482 cam->ops->close(cam->lowlevel_data);
2483 rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE);
2484 cam->decompressed_frame.data = NULL;
2485 rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
2486 cam->raw_image = NULL;
2487 return i;
2490 /* Set ownership of /proc/cpia/videoX to current user */
2491 if(cam->proc_entry)
2492 cam->proc_entry->uid = current->uid;
2494 /* set mark for loading first frame uncompressed */
2495 cam->first_frame = 1;
2497 /* init it to something */
2498 cam->mmap_kludge = 0;
2500 ++cam->open_count;
2501 #ifdef MODULE
2502 MOD_INC_USE_COUNT;
2503 #endif
2504 return 0;
2507 static void cpia_close(struct video_device *dev)
2509 struct cam_data *cam;
2511 cam = dev->priv;
2513 if (cam->ops) {
2514 /* Return ownership of /proc/cpia/videoX to root */
2515 if(cam->proc_entry)
2516 cam->proc_entry->uid = 0;
2518 /* save camera state for later open (developers guide ch 3.5.3) */
2519 save_camera_state(cam);
2521 /* GotoLoPower */
2522 goto_low_power(cam);
2524 /* Update the camera ststus */
2525 do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0);
2527 /* cleanup internal state stuff */
2528 free_frames(cam->frame);
2530 /* close cpia */
2531 cam->ops->close(cam->lowlevel_data);
2534 if (--cam->open_count == 0) {
2535 /* clean up capture-buffers */
2536 if (cam->raw_image) {
2537 rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
2538 cam->raw_image = NULL;
2541 if (cam->decompressed_frame.data) {
2542 rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE);
2543 cam->decompressed_frame.data = NULL;
2546 if (cam->frame_buf)
2547 free_frame_buf(cam);
2549 if (!cam->ops) {
2550 video_unregister_device(dev);
2551 kfree(cam);
2556 #ifdef MODULE
2557 MOD_DEC_USE_COUNT;
2558 #endif
2559 return;
2562 static long cpia_read(struct video_device *dev, char *buf,
2563 unsigned long count, int noblock)
2565 struct cam_data *cam = dev->priv;
2567 /* make this _really_ smp and multithredi-safe */
2568 if (down_interruptible(&cam->busy_lock))
2569 return -EINTR;
2571 if (!buf) {
2572 DBG("buf NULL\n");
2573 up(&cam->busy_lock);
2574 return -EINVAL;
2577 if (!count) {
2578 DBG("count 0\n");
2579 up(&cam->busy_lock);
2580 return 0;
2583 if (!cam->ops) {
2584 DBG("ops NULL\n");
2585 up(&cam->busy_lock);
2586 return -ENODEV;
2589 /* upload frame */
2590 cam->decompressed_frame.state = FRAME_READY;
2591 cam->mmap_kludge=0;
2592 fetch_frame(cam);
2593 if (cam->decompressed_frame.state != FRAME_DONE) {
2594 DBG("upload failed %d/%d\n", cam->decompressed_frame.count,
2595 cam->decompressed_frame.state);
2596 up(&cam->busy_lock);
2597 return -EIO;
2599 cam->decompressed_frame.state = FRAME_UNUSED;
2601 /* copy data to user space */
2602 if (cam->decompressed_frame.count > count) {
2603 DBG("count wrong: %d, %lu\n", cam->decompressed_frame.count,
2604 count);
2605 up(&cam->busy_lock);
2606 return -EFAULT;
2608 if (copy_to_user(buf, cam->decompressed_frame.data,
2609 cam->decompressed_frame.count)) {
2610 DBG("copy_to_user failed\n");
2611 up(&cam->busy_lock);
2612 return -EFAULT;
2615 up(&cam->busy_lock);
2616 return cam->decompressed_frame.count;
2619 static int cpia_ioctl(struct video_device *dev, unsigned int ioctlnr, void *arg)
2621 struct cam_data *cam = dev->priv;
2622 int retval = 0;
2624 if (!cam || !cam->ops)
2625 return -ENODEV;
2627 /* make this _really_ smp-safe */
2628 if (down_interruptible(&cam->busy_lock))
2629 return -EINTR;
2631 //DBG("cpia_ioctl: %u\n", ioctlnr);
2633 switch (ioctlnr) {
2634 /* query capabilites */
2635 case VIDIOCGCAP:
2637 struct video_capability b;
2639 DBG("VIDIOCGCAP\n");
2640 strcpy(b.name, "CPiA Camera");
2641 b.type = VID_TYPE_CAPTURE;
2642 b.channels = 1;
2643 b.audios = 0;
2644 b.maxwidth = 352; /* VIDEOSIZE_CIF */
2645 b.maxheight = 288;
2646 b.minwidth = 48; /* VIDEOSIZE_48_48 */
2647 b.minheight = 48;
2649 if (copy_to_user(arg, &b, sizeof(b)))
2650 retval = -EFAULT;
2652 break;
2655 /* get/set video source - we are a camera and nothing else */
2656 case VIDIOCGCHAN:
2658 struct video_channel v;
2660 DBG("VIDIOCGCHAN\n");
2661 if (copy_from_user(&v, arg, sizeof(v))) {
2662 retval = -EFAULT;
2663 break;
2665 if (v.channel != 0) {
2666 retval = -EINVAL;
2667 break;
2670 v.channel = 0;
2671 strcpy(v.name, "Camera");
2672 v.tuners = 0;
2673 v.flags = 0;
2674 v.type = VIDEO_TYPE_CAMERA;
2675 v.norm = 0;
2677 if (copy_to_user(arg, &v, sizeof(v)))
2678 retval = -EFAULT;
2679 break;
2682 case VIDIOCSCHAN:
2684 int v;
2686 DBG("VIDIOCSCHAN\n");
2687 if (copy_from_user(&v, arg, sizeof(v)))
2688 retval = -EFAULT;
2690 if (retval == 0 && v != 0)
2691 retval = -EINVAL;
2693 break;
2696 /* image properties */
2697 case VIDIOCGPICT:
2698 DBG("VIDIOCGPICT\n");
2699 if (copy_to_user(arg, &cam->vp, sizeof(struct video_picture)))
2700 retval = -EFAULT;
2701 break;
2703 case VIDIOCSPICT:
2705 struct video_picture vp;
2707 DBG("VIDIOCSPICT\n");
2709 /* copy_from_user */
2710 if (copy_from_user(&vp, arg, sizeof(vp))) {
2711 retval = -EFAULT;
2712 break;
2715 /* check validity */
2716 DBG("palette: %d\n", vp.palette);
2717 DBG("depth: %d\n", vp.depth);
2718 if (!valid_mode(vp.palette, vp.depth)) {
2719 retval = -EINVAL;
2720 break;
2723 down(&cam->param_lock);
2724 /* brightness, colour, contrast need no check 0-65535 */
2725 memcpy( &cam->vp, &vp, sizeof(vp) );
2726 /* update cam->params.colourParams */
2727 cam->params.colourParams.brightness = vp.brightness*100/65535;
2728 cam->params.colourParams.contrast = vp.contrast*100/65535;
2729 cam->params.colourParams.saturation = vp.colour*100/65535;
2730 /* contrast is in steps of 8, so round */
2731 cam->params.colourParams.contrast =
2732 ((cam->params.colourParams.contrast + 3) / 8) * 8;
2733 if (cam->params.version.firmwareVersion == 1 &&
2734 cam->params.version.firmwareRevision == 2 &&
2735 cam->params.colourParams.contrast > 80) {
2736 /* 1-02 firmware limits contrast to 80 */
2737 cam->params.colourParams.contrast = 80;
2740 /* queue command to update camera */
2741 cam->cmd_queue |= COMMAND_SETCOLOURPARAMS;
2742 up(&cam->param_lock);
2743 DBG("VIDIOCSPICT: %d / %d // %d / %d / %d / %d\n",
2744 vp.depth, vp.palette, vp.brightness, vp.hue, vp.colour,
2745 vp.contrast);
2746 break;
2749 /* get/set capture window */
2750 case VIDIOCGWIN:
2751 DBG("VIDIOCGWIN\n");
2753 if (copy_to_user(arg, &cam->vw, sizeof(struct video_window)))
2754 retval = -EFAULT;
2755 break;
2757 case VIDIOCSWIN:
2759 /* copy_from_user, check validity, copy to internal structure */
2760 struct video_window vw;
2761 DBG("VIDIOCSWIN\n");
2762 if (copy_from_user(&vw, arg, sizeof(vw))) {
2763 retval = -EFAULT;
2764 break;
2767 if (vw.clipcount != 0) { /* clipping not supported */
2768 retval = -EINVAL;
2769 break;
2771 if (vw.clips != NULL) { /* clipping not supported */
2772 retval = -EINVAL;
2773 break;
2776 /* we set the video window to something smaller or equal to what
2777 * is requested by the user???
2779 down(&cam->param_lock);
2780 if (vw.width != cam->vw.width || vw.height != cam->vw.height) {
2781 int video_size = match_videosize(vw.width, vw.height);
2783 if (video_size < 0) {
2784 retval = -EINVAL;
2785 up(&cam->param_lock);
2786 break;
2788 cam->video_size = video_size;
2789 set_vw_size(cam);
2790 DBG("%d / %d\n", cam->vw.width, cam->vw.height);
2791 cam->cmd_queue |= COMMAND_SETFORMAT;
2794 // FIXME needed??? memcpy(&cam->vw, &vw, sizeof(vw));
2795 up(&cam->param_lock);
2797 /* setformat ignored by camera during streaming,
2798 * so stop/dispatch/start */
2799 if (cam->cmd_queue & COMMAND_SETFORMAT) {
2800 DBG("\n");
2801 dispatch_commands(cam);
2803 DBG("%d/%d:%d\n", cam->video_size,
2804 cam->vw.width, cam->vw.height);
2805 break;
2808 /* mmap interface */
2809 case VIDIOCGMBUF:
2811 struct video_mbuf vm;
2812 int i;
2814 DBG("VIDIOCGMBUF\n");
2815 memset(&vm, 0, sizeof(vm));
2816 vm.size = CPIA_MAX_FRAME_SIZE*FRAME_NUM;
2817 vm.frames = FRAME_NUM;
2818 for (i = 0; i < FRAME_NUM; i++)
2819 vm.offsets[i] = CPIA_MAX_FRAME_SIZE * i;
2821 if (copy_to_user((void *)arg, (void *)&vm, sizeof(vm)))
2822 retval = -EFAULT;
2824 break;
2827 case VIDIOCMCAPTURE:
2829 struct video_mmap vm;
2830 int video_size;
2832 if (copy_from_user((void *)&vm, (void *)arg, sizeof(vm))) {
2833 retval = -EFAULT;
2834 break;
2836 #if 1
2837 DBG("VIDIOCMCAPTURE: %d / %d / %dx%d\n", vm.format, vm.frame,
2838 vm.width, vm.height);
2839 #endif
2840 if (vm.frame<0||vm.frame>FRAME_NUM) {
2841 retval = -EINVAL;
2842 break;
2845 /* set video format */
2846 cam->vp.palette = vm.format;
2847 switch(vm.format) {
2848 case VIDEO_PALETTE_GREY:
2849 case VIDEO_PALETTE_RGB555:
2850 case VIDEO_PALETTE_RGB565:
2851 case VIDEO_PALETTE_YUV422:
2852 case VIDEO_PALETTE_YUYV:
2853 case VIDEO_PALETTE_UYVY:
2854 cam->vp.depth = 16;
2855 break;
2856 case VIDEO_PALETTE_RGB24:
2857 cam->vp.depth = 24;
2858 break;
2859 case VIDEO_PALETTE_RGB32:
2860 cam->vp.depth = 32;
2861 break;
2862 default:
2863 retval = -EINVAL;
2864 break;
2866 if (retval)
2867 break;
2869 /* set video size */
2870 video_size = match_videosize(vm.width, vm.height);
2871 if (cam->video_size < 0) {
2872 retval = -EINVAL;
2873 break;
2875 if (video_size != cam->video_size) {
2876 cam->video_size = video_size;
2877 set_vw_size(cam);
2878 cam->cmd_queue |= COMMAND_SETFORMAT;
2879 dispatch_commands(cam);
2881 #if 0
2882 DBG("VIDIOCMCAPTURE: %d / %d/%d\n", cam->video_size,
2883 cam->vw.width, cam->vw.height);
2884 #endif
2885 /* according to v4l-spec we must start streaming here */
2886 cam->mmap_kludge = 1;
2887 retval = capture_frame(cam, &vm);
2889 break;
2892 case VIDIOCSYNC:
2894 int frame;
2896 if (copy_from_user((void *)&frame, arg, sizeof(int))) {
2897 retval = -EFAULT;
2898 break;
2900 //DBG("VIDIOCSYNC: %d\n", frame);
2902 if (frame<0 || frame >= FRAME_NUM) {
2903 retval = -EINVAL;
2904 break;
2907 switch (cam->frame[frame].state) {
2908 case FRAME_UNUSED:
2909 case FRAME_READY:
2910 case FRAME_GRABBING:
2911 DBG("sync to unused frame %d\n", frame);
2912 retval = -EINVAL;
2913 break;
2915 case FRAME_DONE:
2916 cam->frame[frame].state = FRAME_UNUSED;
2917 //DBG("VIDIOCSYNC: %d synced\n", frame);
2918 break;
2920 if (retval == -EINTR) {
2921 /* FIXME - xawtv does not handle this nice */
2922 retval = 0;
2924 break;
2927 /* pointless to implement overlay with this camera */
2928 case VIDIOCCAPTURE:
2929 retval = -EINVAL;
2930 break;
2931 case VIDIOCGFBUF:
2932 retval = -EINVAL;
2933 break;
2934 case VIDIOCSFBUF:
2935 retval = -EINVAL;
2936 break;
2937 case VIDIOCKEY:
2938 retval = -EINVAL;
2939 break;
2941 /* tuner interface - we have none */
2942 case VIDIOCGTUNER:
2943 retval = -EINVAL;
2944 break;
2945 case VIDIOCSTUNER:
2946 retval = -EINVAL;
2947 break;
2948 case VIDIOCGFREQ:
2949 retval = -EINVAL;
2950 break;
2951 case VIDIOCSFREQ:
2952 retval = -EINVAL;
2953 break;
2955 /* audio interface - we have none */
2956 case VIDIOCGAUDIO:
2957 retval = -EINVAL;
2958 break;
2959 case VIDIOCSAUDIO:
2960 retval = -EINVAL;
2961 break;
2962 default:
2963 retval = -ENOIOCTLCMD;
2964 break;
2967 up(&cam->param_lock);
2968 up(&cam->busy_lock);
2969 return retval;
2972 /* FIXME */
2973 static int cpia_mmap(struct video_device *dev, const char *adr,
2974 unsigned long size)
2976 unsigned long start = (unsigned long)adr;
2977 unsigned long page, pos;
2978 struct cam_data *cam = dev->priv;
2979 int retval;
2981 if (!cam || !cam->ops)
2982 return -ENODEV;
2984 DBG("cpia_mmap: %ld\n", size);
2986 if (size > FRAME_NUM*CPIA_MAX_FRAME_SIZE)
2987 return -EINVAL;
2989 if (!cam || !cam->ops)
2990 return -ENODEV;
2992 /* make this _really_ smp-safe */
2993 if (down_interruptible(&cam->busy_lock))
2994 return -EINTR;
2996 if (!cam->frame_buf) { /* we do lazy allocation */
2997 if ((retval = allocate_frame_buf(cam))) {
2998 up(&cam->busy_lock);
2999 return retval;
3003 pos = (unsigned long)(cam->frame_buf);
3004 while (size > 0) {
3005 page = kvirt_to_pa(pos);
3006 if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) {
3007 up(&cam->busy_lock);
3008 return -EAGAIN;
3010 start += PAGE_SIZE;
3011 pos += PAGE_SIZE;
3012 if (size > PAGE_SIZE)
3013 size -= PAGE_SIZE;
3014 else
3015 size = 0;
3018 DBG("cpia_mmap: %ld\n", size);
3019 up(&cam->busy_lock);
3021 return 0;
3024 int cpia_video_init(struct video_device *vdev)
3026 #ifdef CONFIG_PROC_FS
3027 create_proc_cpia_cam(vdev->priv);
3028 #endif
3029 return 0;
3032 static struct video_device cpia_template = {
3033 "CPiA Camera",
3034 VID_TYPE_CAPTURE,
3035 VID_HARDWARE_CPIA, /* FIXME */
3036 cpia_open, /* open */
3037 cpia_close, /* close */
3038 cpia_read, /* read */
3039 NULL, /* no write */
3040 NULL, /* no poll */
3041 cpia_ioctl, /* ioctl */
3042 cpia_mmap, /* mmap */
3043 cpia_video_init, /* initialize */
3044 NULL, /* priv */
3045 0, /* busy */
3046 -1 /* minor - unset */
3049 /* initialise cam_data structure */
3050 static void reset_camera_struct(struct cam_data *cam)
3052 /* The following parameter values are the defaults from
3053 * "Software Developer's Guide for CPiA Cameras". Any changes
3054 * to the defaults are noted in comments. */
3055 cam->params.colourParams.brightness = 50;
3056 cam->params.colourParams.contrast = 48;
3057 cam->params.colourParams.saturation = 50;
3058 cam->params.exposure.gainMode = 2;
3059 cam->params.exposure.expMode = 2; /* AEC */
3060 cam->params.exposure.compMode = 1;
3061 cam->params.exposure.centreWeight = 1;
3062 cam->params.exposure.gain = 0;
3063 cam->params.exposure.fineExp = 0;
3064 cam->params.exposure.coarseExpLo = 185;
3065 cam->params.exposure.coarseExpHi = 0;
3066 cam->params.exposure.redComp = 220;
3067 cam->params.exposure.green1Comp = 214;
3068 cam->params.exposure.green2Comp = 214;
3069 cam->params.exposure.blueComp = 230;
3070 cam->params.colourBalance.balanceModeIsAuto = 1;
3071 cam->params.colourBalance.redGain = 32;
3072 cam->params.colourBalance.greenGain = 6;
3073 cam->params.colourBalance.blueGain = 92;
3074 cam->params.apcor.gain1 = 0x1c;
3075 cam->params.apcor.gain2 = 0x1a;
3076 cam->params.apcor.gain4 = 0x2d;
3077 cam->params.apcor.gain8 = 0x2a;
3078 cam->params.flickerControl.flickerMode = 0;
3079 cam->params.flickerControl.coarseJump =
3080 flicker_jumps[cam->mainsFreq]
3081 [cam->params.sensorFps.baserate]
3082 [cam->params.sensorFps.divisor];
3083 cam->params.vlOffset.gain1 = 24;
3084 cam->params.vlOffset.gain2 = 28;
3085 cam->params.vlOffset.gain4 = 30;
3086 cam->params.vlOffset.gain8 = 30;
3087 cam->params.compressionParams.hysteresis = 3;
3088 cam->params.compressionParams.threshMax = 11;
3089 cam->params.compressionParams.smallStep = 1;
3090 cam->params.compressionParams.largeStep = 3;
3091 cam->params.compressionParams.decimationHysteresis = 2;
3092 cam->params.compressionParams.frDiffStepThresh = 5;
3093 cam->params.compressionParams.qDiffStepThresh = 3;
3094 cam->params.compressionParams.decimationThreshMod = 2;
3095 /* End of default values from Software Developer's Guide */
3097 cam->transfer_rate = 0;
3099 /* Set Sensor FPS to 15fps. This seems better than 30fps
3100 * for indoor lighting. */
3101 cam->params.sensorFps.divisor = 1;
3102 cam->params.sensorFps.baserate = 1;
3104 cam->params.yuvThreshold.yThreshold = 15; /* FIXME? */
3105 cam->params.yuvThreshold.uvThreshold = 15; /* FIXME? */
3107 cam->params.format.subSample = SUBSAMPLE_422;
3108 cam->params.format.yuvOrder = YUVORDER_YUYV;
3110 cam->params.compression.mode = CPIA_COMPRESSION_AUTO;
3111 cam->params.compressionTarget.frTargeting =
3112 CPIA_COMPRESSION_TARGET_QUALITY;
3113 cam->params.compressionTarget.targetFR = 7; /* FIXME? */
3114 cam->params.compressionTarget.targetQ = 10; /* FIXME? */
3116 cam->video_size = VIDEOSIZE_CIF;
3118 cam->vp.colour = 32768; /* 50% */
3119 cam->vp.hue = 32768; /* 50% */
3120 cam->vp.brightness = 32768; /* 50% */
3121 cam->vp.contrast = 32768; /* 50% */
3122 cam->vp.whiteness = 0; /* not used -> grayscale only */
3123 cam->vp.depth = 0; /* FIXME: to be set by user? */
3124 cam->vp.palette = VIDEO_PALETTE_RGB24; /* FIXME: to be set by user? */
3126 cam->vw.x = 0;
3127 cam->vw.y = 0;
3128 set_vw_size(cam);
3129 cam->vw.chromakey = 0;
3130 /* PP NOTE: my extension to use vw.flags for this, bear it! */
3131 cam->vw.flags = 0;
3132 cam->vw.clipcount = 0;
3133 cam->vw.clips = NULL;
3135 cam->cmd_queue = COMMAND_NONE;
3136 cam->first_frame = 0;
3138 return;
3141 /* initialize cam_data structure */
3142 static void init_camera_struct(struct cam_data *cam,
3143 struct cpia_camera_ops *ops )
3145 int i;
3147 /* Default everything to 0 */
3148 memset(cam, 0, sizeof(struct cam_data));
3150 cam->ops = ops;
3151 init_MUTEX(&cam->param_lock);
3152 init_MUTEX(&cam->busy_lock);
3154 reset_camera_struct(cam);
3156 cam->proc_entry = NULL;
3158 memcpy(&cam->vdev, &cpia_template, sizeof(cpia_template));
3159 cam->vdev.priv = cam;
3161 cam->curframe = 0;
3162 for (i = 0; i < FRAME_NUM; i++) {
3163 cam->frame[i].width = 0;
3164 cam->frame[i].height = 0;
3165 cam->frame[i].state = FRAME_UNUSED;
3166 cam->frame[i].data = NULL;
3168 cam->decompressed_frame.width = 0;
3169 cam->decompressed_frame.height = 0;
3170 cam->decompressed_frame.state = FRAME_UNUSED;
3171 cam->decompressed_frame.data = NULL;
3174 struct cam_data *cpia_register_camera(struct cpia_camera_ops *ops, void *lowlevel)
3176 struct cam_data *camera;
3178 /* Need a lock when adding/removing cameras. This doesn't happen
3179 * often and doesn't take very long, so grabbing the kernel lock
3180 * should be OK. */
3182 if ((camera = kmalloc(sizeof(struct cam_data), GFP_KERNEL)) == NULL) {
3183 unlock_kernel();
3184 return NULL;
3187 init_camera_struct( camera, ops );
3188 camera->lowlevel_data = lowlevel;
3190 /* register v4l device */
3191 if (video_register_device(&camera->vdev, VFL_TYPE_GRABBER) == -1) {
3192 kfree(camera);
3193 unlock_kernel();
3194 printk(KERN_DEBUG "video_register_device failed\n");
3195 return NULL;
3198 /* get version information from camera: open/reset/close */
3200 /* open cpia */
3201 if (camera->ops->open(camera->lowlevel_data))
3202 return camera;
3204 /* reset the camera */
3205 if (reset_camera(camera) != 0) {
3206 camera->ops->close(camera->lowlevel_data);
3207 return camera;
3210 /* close cpia */
3211 camera->ops->close(camera->lowlevel_data);
3213 /* Eh? Feeling happy? - jerdfelt */
3215 camera->ops->open(camera->lowlevel_data);
3216 camera->ops->close(camera->lowlevel_data);
3219 printk(KERN_INFO " CPiA Version: %d.%02d (%d.%d)\n",
3220 camera->params.version.firmwareVersion,
3221 camera->params.version.firmwareRevision,
3222 camera->params.version.vcVersion,
3223 camera->params.version.vcRevision);
3224 printk(KERN_INFO " CPiA PnP-ID: %04x:%04x:%04x\n",
3225 camera->params.pnpID.vendor,
3226 camera->params.pnpID.product,
3227 camera->params.pnpID.deviceRevision);
3228 printk(KERN_INFO " VP-Version: %d.%d %04x\n",
3229 camera->params.vpVersion.vpVersion,
3230 camera->params.vpVersion.vpRevision,
3231 camera->params.vpVersion.cameraHeadID);
3233 return camera;
3236 void cpia_unregister_camera(struct cam_data *cam)
3238 if (!cam->open_count) {
3239 DBG("unregistering video\n");
3240 video_unregister_device(&cam->vdev);
3241 } else {
3242 LOG("/dev/video%d removed while open, "
3243 "deferring video_unregister_device\n", cam->vdev.minor);
3244 DBG("camera open -- setting ops to NULL\n");
3245 cam->ops = NULL;
3248 #ifdef CONFIG_PROC_FS
3249 DBG("destroying /proc/cpia/video%d\n", cam->vdev.minor);
3250 destroy_proc_cpia_cam(cam);
3251 #endif
3252 if (!cam->open_count) {
3253 DBG("freeing camera\n");
3254 kfree(cam);
3258 /****************************************************************************
3260 * Module routines
3262 ***************************************************************************/
3264 #ifdef MODULE
3265 int init_module(void)
3267 printk(KERN_INFO "%s v%d.%d.%d\n", ABOUT,
3268 CPIA_MAJ_VER, CPIA_MIN_VER, CPIA_PATCH_VER);
3269 #ifdef CONFIG_PROC_FS
3270 proc_cpia_create();
3271 #endif
3272 #ifdef CONFIG_KMOD
3273 #ifdef CONFIG_VIDEO_CPIA_PP_MODULE
3274 request_module("cpia_pp");
3275 #endif
3276 #ifdef CONFIG_VIDEO_CPIA_USB_MODULE
3277 request_module("cpia_usb");
3278 #endif
3279 #endif
3280 return 0;
3283 void cleanup_module(void)
3285 #ifdef CONFIG_PROC_FS
3286 proc_cpia_destroy();
3287 #endif
3290 #else
3292 int cpia_init(struct video_init *unused)
3294 printk(KERN_INFO "%s v%d.%d.%d\n", ABOUT,
3295 CPIA_MAJ_VER, CPIA_MIN_VER, CPIA_PATCH_VER);
3296 #ifdef CONFIG_PROC_FS
3297 proc_cpia_create();
3298 #endif
3300 #ifdef CONFIG_VIDEO_CPIA_PP
3301 cpia_pp_init();
3302 #endif
3303 #ifdef CONFIG_KMOD
3304 #ifdef CONFIG_VIDEO_CPIA_PP_MODULE
3305 request_module("cpia_pp");
3306 #endif
3308 #ifdef CONFIG_VIDEO_CPIA_USB_MODULE
3309 request_module("cpia_usb");
3310 #endif
3311 #endif /* CONFIG_KMOD */
3312 #ifdef CONFIG_VIDEO_CPIA_USB
3313 cpia_usb_init();
3314 #endif
3315 return 0;
3318 /* Exported symbols for modules. */
3320 EXPORT_SYMBOL(cpia_register_camera);
3321 EXPORT_SYMBOL(cpia_unregister_camera);
3323 #endif