File: /usr/src/linux/drivers/media/video/cpia.c
1 /*
2 * cpia CPiA driver
3 *
4 * Supports CPiA based Video Camera's.
5 *
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
9 *
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.
14 *
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.
19 *
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.
23 */
24
25 /* #define _CPIA_DEBUG_ define for verbose debug output */
26 #include <linux/config.h>
27
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>
41
42 #ifdef CONFIG_KMOD
43 #include <linux/kmod.h>
44 #endif
45
46 #include "cpia.h"
47
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
54
55 static int video_nr = -1;
56
57 #ifdef MODULE
58 MODULE_PARM(video_nr,"i");
59 MODULE_AUTHOR("Scott J. Bertin <sbertin@mindspring.com> & Peter Pregler <Peter_Pregler@email.com> & Johannes Erdfelt <jerdfelt@valinux.com>");
60 MODULE_DESCRIPTION("V4L-driver for Vision CPiA based cameras");
61 MODULE_SUPPORTED_DEVICE("video");
62 #endif
63
64 #define ABOUT "V4L-Driver for Vision CPiA based cameras"
65
66 #ifndef VID_HARDWARE_CPIA
67 #define VID_HARDWARE_CPIA 24 /* FIXME -> from linux/videodev.h */
68 #endif
69
70 #define CPIA_MODULE_CPIA (0<<5)
71 #define CPIA_MODULE_SYSTEM (1<<5)
72 #define CPIA_MODULE_VP_CTRL (5<<5)
73 #define CPIA_MODULE_CAPTURE (6<<5)
74 #define CPIA_MODULE_DEBUG (7<<5)
75
76 #define INPUT (DATA_IN << 8)
77 #define OUTPUT (DATA_OUT << 8)
78
79 #define CPIA_COMMAND_GetCPIAVersion (INPUT | CPIA_MODULE_CPIA | 1)
80 #define CPIA_COMMAND_GetPnPID (INPUT | CPIA_MODULE_CPIA | 2)
81 #define CPIA_COMMAND_GetCameraStatus (INPUT | CPIA_MODULE_CPIA | 3)
82 #define CPIA_COMMAND_GotoHiPower (OUTPUT | CPIA_MODULE_CPIA | 4)
83 #define CPIA_COMMAND_GotoLoPower (OUTPUT | CPIA_MODULE_CPIA | 5)
84 #define CPIA_COMMAND_GotoSuspend (OUTPUT | CPIA_MODULE_CPIA | 7)
85 #define CPIA_COMMAND_GotoPassThrough (OUTPUT | CPIA_MODULE_CPIA | 8)
86 #define CPIA_COMMAND_ModifyCameraStatus (OUTPUT | CPIA_MODULE_CPIA | 10)
87
88 #define CPIA_COMMAND_ReadVCRegs (INPUT | CPIA_MODULE_SYSTEM | 1)
89 #define CPIA_COMMAND_WriteVCReg (OUTPUT | CPIA_MODULE_SYSTEM | 2)
90 #define CPIA_COMMAND_ReadMCPorts (INPUT | CPIA_MODULE_SYSTEM | 3)
91 #define CPIA_COMMAND_WriteMCPort (OUTPUT | CPIA_MODULE_SYSTEM | 4)
92 #define CPIA_COMMAND_SetBaudRate (OUTPUT | CPIA_MODULE_SYSTEM | 5)
93 #define CPIA_COMMAND_SetECPTiming (OUTPUT | CPIA_MODULE_SYSTEM | 6)
94 #define CPIA_COMMAND_ReadIDATA (INPUT | CPIA_MODULE_SYSTEM | 7)
95 #define CPIA_COMMAND_WriteIDATA (OUTPUT | CPIA_MODULE_SYSTEM | 8)
96 #define CPIA_COMMAND_GenericCall (OUTPUT | CPIA_MODULE_SYSTEM | 9)
97 #define CPIA_COMMAND_I2CStart (OUTPUT | CPIA_MODULE_SYSTEM | 10)
98 #define CPIA_COMMAND_I2CStop (OUTPUT | CPIA_MODULE_SYSTEM | 11)
99 #define CPIA_COMMAND_I2CWrite (OUTPUT | CPIA_MODULE_SYSTEM | 12)
100 #define CPIA_COMMAND_I2CRead (INPUT | CPIA_MODULE_SYSTEM | 13)
101
102 #define CPIA_COMMAND_GetVPVersion (INPUT | CPIA_MODULE_VP_CTRL | 1)
103 #define CPIA_COMMAND_SetColourParams (OUTPUT | CPIA_MODULE_VP_CTRL | 3)
104 #define CPIA_COMMAND_SetExposure (OUTPUT | CPIA_MODULE_VP_CTRL | 4)
105 #define CPIA_COMMAND_SetColourBalance (OUTPUT | CPIA_MODULE_VP_CTRL | 6)
106 #define CPIA_COMMAND_SetSensorFPS (OUTPUT | CPIA_MODULE_VP_CTRL | 7)
107 #define CPIA_COMMAND_SetVPDefaults (OUTPUT | CPIA_MODULE_VP_CTRL | 8)
108 #define CPIA_COMMAND_SetApcor (OUTPUT | CPIA_MODULE_VP_CTRL | 9)
109 #define CPIA_COMMAND_SetFlickerCtrl (OUTPUT | CPIA_MODULE_VP_CTRL | 10)
110 #define CPIA_COMMAND_SetVLOffset (OUTPUT | CPIA_MODULE_VP_CTRL | 11)
111 #define CPIA_COMMAND_GetColourParams (INPUT | CPIA_MODULE_VP_CTRL | 16)
112 #define CPIA_COMMAND_GetColourBalance (INPUT | CPIA_MODULE_VP_CTRL | 17)
113 #define CPIA_COMMAND_GetExposure (INPUT | CPIA_MODULE_VP_CTRL | 18)
114 #define CPIA_COMMAND_SetSensorMatrix (OUTPUT | CPIA_MODULE_VP_CTRL | 19)
115 #define CPIA_COMMAND_ColourBars (OUTPUT | CPIA_MODULE_VP_CTRL | 25)
116 #define CPIA_COMMAND_ReadVPRegs (INPUT | CPIA_MODULE_VP_CTRL | 30)
117 #define CPIA_COMMAND_WriteVPReg (OUTPUT | CPIA_MODULE_VP_CTRL | 31)
118
119 #define CPIA_COMMAND_GrabFrame (OUTPUT | CPIA_MODULE_CAPTURE | 1)
120 #define CPIA_COMMAND_UploadFrame (OUTPUT | CPIA_MODULE_CAPTURE | 2)
121 #define CPIA_COMMAND_SetGrabMode (OUTPUT | CPIA_MODULE_CAPTURE | 3)
122 #define CPIA_COMMAND_InitStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 4)
123 #define CPIA_COMMAND_FiniStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 5)
124 #define CPIA_COMMAND_StartStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 6)
125 #define CPIA_COMMAND_EndStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 7)
126 #define CPIA_COMMAND_SetFormat (OUTPUT | CPIA_MODULE_CAPTURE | 8)
127 #define CPIA_COMMAND_SetROI (OUTPUT | CPIA_MODULE_CAPTURE | 9)
128 #define CPIA_COMMAND_SetCompression (OUTPUT | CPIA_MODULE_CAPTURE | 10)
129 #define CPIA_COMMAND_SetCompressionTarget (OUTPUT | CPIA_MODULE_CAPTURE | 11)
130 #define CPIA_COMMAND_SetYUVThresh (OUTPUT | CPIA_MODULE_CAPTURE | 12)
131 #define CPIA_COMMAND_SetCompressionParams (OUTPUT | CPIA_MODULE_CAPTURE | 13)
132 #define CPIA_COMMAND_DiscardFrame (OUTPUT | CPIA_MODULE_CAPTURE | 14)
133
134 #define CPIA_COMMAND_OutputRS232 (OUTPUT | CPIA_MODULE_DEBUG | 1)
135 #define CPIA_COMMAND_AbortProcess (OUTPUT | CPIA_MODULE_DEBUG | 4)
136 #define CPIA_COMMAND_SetDramPage (OUTPUT | CPIA_MODULE_DEBUG | 5)
137 #define CPIA_COMMAND_StartDramUpload (OUTPUT | CPIA_MODULE_DEBUG | 6)
138 #define CPIA_COMMAND_StartDummyDtream (OUTPUT | CPIA_MODULE_DEBUG | 8)
139 #define CPIA_COMMAND_AbortStream (OUTPUT | CPIA_MODULE_DEBUG | 9)
140 #define CPIA_COMMAND_DownloadDRAM (OUTPUT | CPIA_MODULE_DEBUG | 10)
141
142 enum {
143 FRAME_READY, /* Ready to grab into */
144 FRAME_GRABBING, /* In the process of being grabbed into */
145 FRAME_DONE, /* Finished grabbing, but not been synced yet */
146 FRAME_UNUSED, /* Unused (no MCAPTURE) */
147 };
148
149 #define COMMAND_NONE 0x0000
150 #define COMMAND_SETCOMPRESSION 0x0001
151 #define COMMAND_SETCOMPRESSIONTARGET 0x0002
152 #define COMMAND_SETCOLOURPARAMS 0x0004
153 #define COMMAND_SETFORMAT 0x0008
154 #define COMMAND_PAUSE 0x0010
155 #define COMMAND_RESUME 0x0020
156 #define COMMAND_SETYUVTHRESH 0x0040
157 #define COMMAND_SETECPTIMING 0x0080
158 #define COMMAND_SETCOMPRESSIONPARAMS 0x0100
159 #define COMMAND_SETEXPOSURE 0x0200
160 #define COMMAND_SETCOLOURBALANCE 0x0400
161 #define COMMAND_SETSENSORFPS 0x0800
162 #define COMMAND_SETAPCOR 0x1000
163 #define COMMAND_SETFLICKERCTRL 0x2000
164 #define COMMAND_SETVLOFFSET 0x4000
165
166 /* Developer's Guide Table 5 p 3-34
167 * indexed by [mains][sensorFps.baserate][sensorFps.divisor]*/
168 static u8 flicker_jumps[2][2][4] =
169 { { { 76, 38, 19, 9 }, { 92, 46, 23, 11 } },
170 { { 64, 32, 16, 8 }, { 76, 38, 19, 9} }
171 };
172
173 /* forward declaration of local function */
174 static void reset_camera_struct(struct cam_data *cam);
175
176 /**********************************************************************
177 *
178 * Memory management
179 *
180 * This is a shameless copy from the USB-cpia driver (linux kernel
181 * version 2.3.29 or so, I have no idea what this code actually does ;).
182 * Actually it seems to be a copy of a shameless copy of the bttv-driver.
183 * Or that is a copy of a shameless copy of ... (To the powers: is there
184 * no generic kernel-function to do this sort of stuff?)
185 *
186 * Yes, it was a shameless copy from the bttv-driver. IIRC, Alan says
187 * there will be one, but apparentely not yet - jerdfelt
188 *
189 **********************************************************************/
190
191 /* Given PGD from the address space's page table, return the kernel
192 * virtual mapping of the physical memory mapped at ADR.
193 */
194 static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr)
195 {
196 unsigned long ret = 0UL;
197 pmd_t *pmd;
198 pte_t *ptep, pte;
199
200 if (!pgd_none(*pgd)) {
201 pmd = pmd_offset(pgd, adr);
202 if (!pmd_none(*pmd)) {
203 ptep = pte_offset(pmd, adr);
204 pte = *ptep;
205 if (pte_present(pte)) {
206 ret = (unsigned long) page_address(pte_page(pte));
207 ret |= (adr & (PAGE_SIZE-1));
208 }
209 }
210 }
211 return ret;
212 }
213
214 /* Here we want the physical address of the memory.
215 * This is used when initializing the contents of the
216 * area and marking the pages as reserved.
217 */
218 static inline unsigned long kvirt_to_pa(unsigned long adr)
219 {
220 unsigned long va, kva, ret;
221
222 va = VMALLOC_VMADDR(adr);
223 kva = uvirt_to_kva(pgd_offset_k(va), va);
224 ret = __pa(kva);
225 return ret;
226 }
227
228 static void *rvmalloc(unsigned long size)
229 {
230 void *mem;
231 unsigned long adr, page;
232
233 /* Round it off to PAGE_SIZE */
234 size += (PAGE_SIZE - 1);
235 size &= ~(PAGE_SIZE - 1);
236
237 mem = vmalloc_32(size);
238 if (!mem)
239 return NULL;
240
241 memset(mem, 0, size); /* Clear the ram out, no junk to the user */
242 adr = (unsigned long) mem;
243 while (size > 0) {
244 page = kvirt_to_pa(adr);
245 mem_map_reserve(virt_to_page(__va(page)));
246 adr += PAGE_SIZE;
247 if (size > PAGE_SIZE)
248 size -= PAGE_SIZE;
249 else
250 size = 0;
251 }
252
253 return mem;
254 }
255
256 static void rvfree(void *mem, unsigned long size)
257 {
258 unsigned long adr, page;
259
260 if (!mem)
261 return;
262
263 size += (PAGE_SIZE - 1);
264 size &= ~(PAGE_SIZE - 1);
265
266 adr = (unsigned long) mem;
267 while (size > 0) {
268 page = kvirt_to_pa(adr);
269 mem_map_unreserve(virt_to_page(__va(page)));
270 adr += PAGE_SIZE;
271 if (size > PAGE_SIZE)
272 size -= PAGE_SIZE;
273 else
274 size = 0;
275 }
276 vfree(mem);
277 }
278
279 /**********************************************************************
280 *
281 * /proc interface
282 *
283 **********************************************************************/
284 #ifdef CONFIG_PROC_FS
285 static struct proc_dir_entry *cpia_proc_root=NULL;
286
287 static int cpia_read_proc(char *page, char **start, off_t off,
288 int count, int *eof, void *data)
289 {
290 char *out = page;
291 int len, tmp;
292 struct cam_data *cam = data;
293 char tmpstr[20];
294
295 /* IMPORTANT: This output MUST be kept under PAGE_SIZE
296 * or we need to get more sophisticated. */
297
298 out += sprintf(out, "read-only\n-----------------------\n");
299 out += sprintf(out, "V4L Driver version: %d.%d.%d\n",
300 CPIA_MAJ_VER, CPIA_MIN_VER, CPIA_PATCH_VER);
301 out += sprintf(out, "CPIA Version: %d.%02d (%d.%d)\n",
302 cam->params.version.firmwareVersion,
303 cam->params.version.firmwareRevision,
304 cam->params.version.vcVersion,
305 cam->params.version.vcRevision);
306 out += sprintf(out, "CPIA PnP-ID: %04x:%04x:%04x\n",
307 cam->params.pnpID.vendor, cam->params.pnpID.product,
308 cam->params.pnpID.deviceRevision);
309 out += sprintf(out, "VP-Version: %d.%d %04x\n",
310 cam->params.vpVersion.vpVersion,
311 cam->params.vpVersion.vpRevision,
312 cam->params.vpVersion.cameraHeadID);
313
314 out += sprintf(out, "system_state: %#04x\n",
315 cam->params.status.systemState);
316 out += sprintf(out, "grab_state: %#04x\n",
317 cam->params.status.grabState);
318 out += sprintf(out, "stream_state: %#04x\n",
319 cam->params.status.streamState);
320 out += sprintf(out, "fatal_error: %#04x\n",
321 cam->params.status.fatalError);
322 out += sprintf(out, "cmd_error: %#04x\n",
323 cam->params.status.cmdError);
324 out += sprintf(out, "debug_flags: %#04x\n",
325 cam->params.status.debugFlags);
326 out += sprintf(out, "vp_status: %#04x\n",
327 cam->params.status.vpStatus);
328 out += sprintf(out, "error_code: %#04x\n",
329 cam->params.status.errorCode);
330 out += sprintf(out, "video_size: %s\n",
331 cam->params.format.videoSize == VIDEOSIZE_CIF ?
332 "CIF " : "QCIF");
333 out += sprintf(out, "sub_sample: %s\n",
334 cam->params.format.subSample == SUBSAMPLE_420 ?
335 "420" : "422");
336 out += sprintf(out, "yuv_order: %s\n",
337 cam->params.format.yuvOrder == YUVORDER_YUYV ?
338 "YUYV" : "UYVY");
339 out += sprintf(out, "roi: (%3d, %3d) to (%3d, %3d)\n",
340 cam->params.roi.colStart*8,
341 cam->params.roi.rowStart*4,
342 cam->params.roi.colEnd*8,
343 cam->params.roi.rowEnd*4);
344 out += sprintf(out, "actual_fps: %3d\n", cam->fps);
345 out += sprintf(out, "transfer_rate: %4dkB/s\n",
346 cam->transfer_rate);
347
348 out += sprintf(out, "\nread-write\n");
349 out += sprintf(out, "----------------------- current min"
350 " max default comment\n");
351 out += sprintf(out, "brightness: %8d %8d %8d %8d\n",
352 cam->params.colourParams.brightness, 0, 100, 50);
353 if (cam->params.version.firmwareVersion == 1 &&
354 cam->params.version.firmwareRevision == 2)
355 /* 1-02 firmware limits contrast to 80 */
356 tmp = 80;
357 else
358 tmp = 96;
359
360 out += sprintf(out, "contrast: %8d %8d %8d %8d"
361 " steps of 8\n",
362 cam->params.colourParams.contrast, 0, tmp, 48);
363 out += sprintf(out, "saturation: %8d %8d %8d %8d\n",
364 cam->params.colourParams.saturation, 0, 100, 50);
365 tmp = (25000+5000*cam->params.sensorFps.baserate)/
366 (1<<cam->params.sensorFps.divisor);
367 out += sprintf(out, "sensor_fps: %4d.%03d %8d %8d %8d\n",
368 tmp/1000, tmp%1000, 3, 30, 15);
369 out += sprintf(out, "stream_start_line: %8d %8d %8d %8d\n",
370 2*cam->params.streamStartLine, 0,
371 cam->params.format.videoSize == VIDEOSIZE_CIF ? 288:144,
372 cam->params.format.videoSize == VIDEOSIZE_CIF ? 240:120);
373 out += sprintf(out, "ecp_timing: %8s %8s %8s %8s\n",
374 cam->params.ecpTiming ? "slow" : "normal", "slow",
375 "normal", "normal");
376
377 if (cam->params.colourBalance.balanceModeIsAuto) {
378 sprintf(tmpstr, "auto");
379 } else {
380 sprintf(tmpstr, "manual");
381 }
382 out += sprintf(out, "color_balance_mode: %8s %8s %8s"
383 " %8s\n", tmpstr, "manual", "auto", "auto");
384 out += sprintf(out, "red_gain: %8d %8d %8d %8d\n",
385 cam->params.colourBalance.redGain, 0, 212, 32);
386 out += sprintf(out, "green_gain: %8d %8d %8d %8d\n",
387 cam->params.colourBalance.greenGain, 0, 212, 6);
388 out += sprintf(out, "blue_gain: %8d %8d %8d %8d\n",
389 cam->params.colourBalance.blueGain, 0, 212, 92);
390
391 if (cam->params.version.firmwareVersion == 1 &&
392 cam->params.version.firmwareRevision == 2)
393 /* 1-02 firmware limits gain to 2 */
394 sprintf(tmpstr, "%8d %8d", 1, 2);
395 else
396 sprintf(tmpstr, "1,2,4,8");
397
398 if (cam->params.exposure.gainMode == 0)
399 out += sprintf(out, "max_gain: unknown %18s"
400 " %8d\n", tmpstr, 2);
401 else
402 out += sprintf(out, "max_gain: %8d %18s %8d\n",
403 1<<(cam->params.exposure.gainMode-1), tmpstr, 2);
404
405 switch(cam->params.exposure.expMode) {
406 case 1:
407 case 3:
408 sprintf(tmpstr, "manual");
409 break;
410 case 2:
411 sprintf(tmpstr, "auto");
412 break;
413 default:
414 sprintf(tmpstr, "unknown");
415 break;
416 }
417 out += sprintf(out, "exposure_mode: %8s %8s %8s"
418 " %8s\n", tmpstr, "manual", "auto", "auto");
419 out += sprintf(out, "centre_weight: %8s %8s %8s %8s\n",
420 (2-cam->params.exposure.centreWeight) ? "on" : "off",
421 "off", "on", "on");
422 out += sprintf(out, "gain: %8d %8d max_gain %8d 1,2,4,8 possible\n",
423 1<<cam->params.exposure.gain, 1, 1);
424 if (cam->params.version.firmwareVersion == 1 &&
425 cam->params.version.firmwareRevision == 2)
426 /* 1-02 firmware limits fineExp to 127 */
427 tmp = 255;
428 else
429 tmp = 511;
430
431 out += sprintf(out, "fine_exp: %8d %8d %8d %8d\n",
432 cam->params.exposure.fineExp*2, 0, tmp, 0);
433 if (cam->params.version.firmwareVersion == 1 &&
434 cam->params.version.firmwareRevision == 2)
435 /* 1-02 firmware limits coarseExpHi to 0 */
436 tmp = 255;
437 else
438 tmp = 65535;
439
440 out += sprintf(out, "coarse_exp: %8d %8d %8d"
441 " %8d\n", cam->params.exposure.coarseExpLo+
442 256*cam->params.exposure.coarseExpHi, 0, tmp, 185);
443 out += sprintf(out, "red_comp: %8d %8d %8d %8d\n",
444 cam->params.exposure.redComp, 220, 255, 220);
445 out += sprintf(out, "green1_comp: %8d %8d %8d %8d\n",
446 cam->params.exposure.green1Comp, 214, 255, 214);
447 out += sprintf(out, "green2_comp: %8d %8d %8d %8d\n",
448 cam->params.exposure.green2Comp, 214, 255, 214);
449 out += sprintf(out, "blue_comp: %8d %8d %8d %8d\n",
450 cam->params.exposure.blueComp, 230, 255, 230);
451
452 out += sprintf(out, "apcor_gain1: %#8x %#8x %#8x %#8x\n",
453 cam->params.apcor.gain1, 0, 0xff, 0x1c);
454 out += sprintf(out, "apcor_gain2: %#8x %#8x %#8x %#8x\n",
455 cam->params.apcor.gain2, 0, 0xff, 0x1a);
456 out += sprintf(out, "apcor_gain4: %#8x %#8x %#8x %#8x\n",
457 cam->params.apcor.gain4, 0, 0xff, 0x2d);
458 out += sprintf(out, "apcor_gain8: %#8x %#8x %#8x %#8x\n",
459 cam->params.apcor.gain8, 0, 0xff, 0x2a);
460 out += sprintf(out, "vl_offset_gain1: %8d %8d %8d %8d\n",
461 cam->params.vlOffset.gain1, 0, 255, 24);
462 out += sprintf(out, "vl_offset_gain2: %8d %8d %8d %8d\n",
463 cam->params.vlOffset.gain2, 0, 255, 28);
464 out += sprintf(out, "vl_offset_gain4: %8d %8d %8d %8d\n",
465 cam->params.vlOffset.gain4, 0, 255, 30);
466 out += sprintf(out, "vl_offset_gain8: %8d %8d %8d %8d\n",
467 cam->params.vlOffset.gain8, 0, 255, 30);
468 out += sprintf(out, "flicker_control: %8s %8s %8s %8s\n",
469 cam->params.flickerControl.flickerMode ? "on" : "off",
470 "off", "on", "off");
471 out += sprintf(out, "mains_frequency: %8d %8d %8d %8d"
472 " only 50/60\n",
473 cam->mainsFreq ? 60 : 50, 50, 60, 50);
474 out += sprintf(out, "allowable_overexposure: %8d %8d %8d %8d\n",
475 cam->params.flickerControl.allowableOverExposure, 0,
476 255, 0);
477 out += sprintf(out, "compression_mode: ");
478 switch(cam->params.compression.mode) {
479 case CPIA_COMPRESSION_NONE:
480 out += sprintf(out, "%8s", "none");
481 break;
482 case CPIA_COMPRESSION_AUTO:
483 out += sprintf(out, "%8s", "auto");
484 break;
485 case CPIA_COMPRESSION_MANUAL:
486 out += sprintf(out, "%8s", "manual");
487 break;
488 default:
489 out += sprintf(out, "%8s", "unknown");
490 break;
491 }
492 out += sprintf(out, " none,auto,manual auto\n");
493 out += sprintf(out, "decimation_enable: %8s %8s %8s %8s\n",
494 cam->params.compression.decimation ==
495 DECIMATION_ENAB ? "on":"off", "off", "off",
496 "off");
497 out += sprintf(out, "compression_target: %9s %9s %9s %9s\n",
498 cam->params.compressionTarget.frTargeting ==
499 CPIA_COMPRESSION_TARGET_FRAMERATE ?
500 "framerate":"quality",
501 "framerate", "quality", "quality");
502 out += sprintf(out, "target_framerate: %8d %8d %8d %8d\n",
503 cam->params.compressionTarget.targetFR, 0, 30, 7);
504 out += sprintf(out, "target_quality: %8d %8d %8d %8d\n",
505 cam->params.compressionTarget.targetQ, 0, 255, 10);
506 out += sprintf(out, "y_threshold: %8d %8d %8d %8d\n",
507 cam->params.yuvThreshold.yThreshold, 0, 31, 15);
508 out += sprintf(out, "uv_threshold: %8d %8d %8d %8d\n",
509 cam->params.yuvThreshold.uvThreshold, 0, 31, 15);
510 out += sprintf(out, "hysteresis: %8d %8d %8d %8d\n",
511 cam->params.compressionParams.hysteresis, 0, 255, 3);
512 out += sprintf(out, "threshold_max: %8d %8d %8d %8d\n",
513 cam->params.compressionParams.threshMax, 0, 255, 11);
514 out += sprintf(out, "small_step: %8d %8d %8d %8d\n",
515 cam->params.compressionParams.smallStep, 0, 255, 1);
516 out += sprintf(out, "large_step: %8d %8d %8d %8d\n",
517 cam->params.compressionParams.largeStep, 0, 255, 3);
518 out += sprintf(out, "decimation_hysteresis: %8d %8d %8d %8d\n",
519 cam->params.compressionParams.decimationHysteresis,
520 0, 255, 2);
521 out += sprintf(out, "fr_diff_step_thresh: %8d %8d %8d %8d\n",
522 cam->params.compressionParams.frDiffStepThresh,
523 0, 255, 5);
524 out += sprintf(out, "q_diff_step_thresh: %8d %8d %8d %8d\n",
525 cam->params.compressionParams.qDiffStepThresh,
526 0, 255, 3);
527 out += sprintf(out, "decimation_thresh_mod: %8d %8d %8d %8d\n",
528 cam->params.compressionParams.decimationThreshMod,
529 0, 255, 2);
530
531 len = out - page;
532 len -= off;
533 if (len < count) {
534 *eof = 1;
535 if (len <= 0) return 0;
536 } else
537 len = count;
538
539 *start = page + off;
540 return len;
541 }
542
543 static int cpia_write_proc(struct file *file, const char *buffer,
544 unsigned long count, void *data)
545 {
546 return -EINVAL;
547 #if 0
548 struct cam_data *cam = data;
549 struct cam_params new_params;
550 int retval, find_colon;
551 int size = count;
552 unsigned long val;
553 u32 command_flags = 0;
554 u8 new_mains;
555
556 if (down_interruptible(&cam->param_lock))
557 return -ERESTARTSYS;
558
559 /*
560 * Skip over leading whitespace
561 */
562 while (count && isspace(*buffer)) {
563 --count;
564 ++buffer;
565 }
566
567 memcpy(&new_params, &cam->params, sizeof(struct cam_params));
568 new_mains = cam->mainsFreq;
569
570 #define MATCH(x) \
571 ({ \
572 int _len = strlen(x), _ret, _colon_found; \
573 _ret = (_len <= count && strncmp(buffer, x, _len) == 0); \
574 if (_ret) { \
575 buffer += _len; \
576 count -= _len; \
577 if (find_colon) { \
578 _colon_found = 0; \
579 while (count && (*buffer == ' ' || *buffer == '\t' || \
580 (!_colon_found && *buffer == ':'))) { \
581 if (*buffer == ':') \
582 _colon_found = 1; \
583 --count; \
584 ++buffer; \
585 } \
586 if (!count || !_colon_found) \
587 retval = -EINVAL; \
588 find_colon = 0; \
589 } \
590 } \
591 _ret; \
592 })
593 #define FIRMWARE_VERSION(x,y) (new_params.version.firmwareVersion == (x) && \
594 new_params.version.firmwareRevision == (y))
595 #define VALUE \
596 ({ \
597 char *_p; \
598 unsigned long int _ret; \
599 _ret = simple_strtoul(buffer, &_p, 0); \
600 if (_p == buffer) \
601 retval = -EINVAL; \
602 else { \
603 count -= _p - buffer; \
604 buffer = _p; \
605 } \
606 _ret; \
607 })
608
609 retval = 0;
610 while (count && !retval) {
611 find_colon = 1;
612 if (MATCH("brightness")) {
613 if (!retval)
614 val = VALUE;
615
616 if (!retval) {
617 if (val <= 100)
618 new_params.colourParams.brightness = val;
619 else
620 retval = -EINVAL;
621 }
622 command_flags |= COMMAND_SETCOLOURPARAMS;
623 } else if (MATCH("contrast")) {
624 if (!retval)
625 val = VALUE;
626
627 if (!retval) {
628 if (val <= 100) {
629 /* contrast is in steps of 8, so round*/
630 val = ((val + 3) / 8) * 8;
631 /* 1-02 firmware limits contrast to 80*/
632 if (FIRMWARE_VERSION(1,2) && val > 80)
633 val = 80;
634
635 new_params.colourParams.contrast = val;
636 } else
637 retval = -EINVAL;
638 }
639 command_flags |= COMMAND_SETCOLOURPARAMS;
640 } else if (MATCH("saturation")) {
641 if (!retval)
642 val = VALUE;
643
644 if (!retval) {
645 if (val <= 100)
646 new_params.colourParams.saturation = val;
647 else
648 retval = -EINVAL;
649 }
650 command_flags |= COMMAND_SETCOLOURPARAMS;
651 } else if (MATCH("sensor_fps")) {
652 if (!retval)
653 val = VALUE;
654
655 if (!retval) {
656 /* find values so that sensorFPS is minimized,
657 * but >= val */
658 if (val > 30)
659 retval = -EINVAL;
660 else if (val > 25) {
661 new_params.sensorFps.divisor = 0;
662 new_params.sensorFps.baserate = 1;
663 } else if (val > 15) {
664 new_params.sensorFps.divisor = 0;
665 new_params.sensorFps.baserate = 0;
666 } else if (val > 12) {
667 new_params.sensorFps.divisor = 1;
668 new_params.sensorFps.baserate = 1;
669 } else if (val > 7) {
670 new_params.sensorFps.divisor = 1;
671 new_params.sensorFps.baserate = 0;
672 } else if (val > 6) {
673 new_params.sensorFps.divisor = 2;
674 new_params.sensorFps.baserate = 1;
675 } else if (val > 3) {
676 new_params.sensorFps.divisor = 2;
677 new_params.sensorFps.baserate = 0;
678 } else {
679 new_params.sensorFps.divisor = 3;
680 /* Either base rate would work here */
681 new_params.sensorFps.baserate = 1;
682 }
683 new_params.flickerControl.coarseJump =
684 flicker_jumps[new_mains]
685 [new_params.sensorFps.baserate]
686 [new_params.sensorFps.divisor];
687 if (new_params.flickerControl.flickerMode)
688 command_flags |= COMMAND_SETFLICKERCTRL;
689 }
690 command_flags |= COMMAND_SETSENSORFPS;
691 } else if (MATCH("stream_start_line")) {
692 if (!retval)
693 val = VALUE;
694
695 if (!retval) {
696 int max_line = 288;
697
698 if (new_params.format.videoSize == VIDEOSIZE_QCIF)
699 max_line = 144;
700 if (val <= max_line)
701 new_params.streamStartLine = val/2;
702 else
703 retval = -EINVAL;
704 }
705 } else if (MATCH("ecp_timing")) {
706 if (!retval && MATCH("normal"))
707 new_params.ecpTiming = 0;
708 else if (!retval && MATCH("slow"))
709 new_params.ecpTiming = 1;
710 else
711 retval = -EINVAL;
712
713 command_flags |= COMMAND_SETECPTIMING;
714 } else if (MATCH("color_balance_mode")) {
715 if (!retval && MATCH("manual"))
716 new_params.colourBalance.balanceModeIsAuto = 0;
717 else if (!retval && MATCH("auto"))
718 new_params.colourBalance.balanceModeIsAuto = 1;
719 else
720 retval = -EINVAL;
721
722 command_flags |= COMMAND_SETCOLOURBALANCE;
723 } else if (MATCH("red_gain")) {
724 if (!retval)
725 val = VALUE;
726
727 if (!retval) {
728 if (val <= 212)
729 new_params.colourBalance.redGain = val;
730 else
731 retval = -EINVAL;
732 }
733 command_flags |= COMMAND_SETCOLOURBALANCE;
734 } else if (MATCH("green_gain")) {
735 if (!retval)
736 val = VALUE;
737
738 if (!retval) {
739 if (val <= 212)
740 new_params.colourBalance.greenGain = val;
741 else
742 retval = -EINVAL;
743 }
744 command_flags |= COMMAND_SETCOLOURBALANCE;
745 } else if (MATCH("blue_gain")) {
746 if (!retval)
747 val = VALUE;
748
749 if (!retval) {
750 if (val <= 212)
751 new_params.colourBalance.blueGain = val;
752 else
753 retval = -EINVAL;
754 }
755 command_flags |= COMMAND_SETCOLOURBALANCE;
756 } else if (MATCH("max_gain")) {
757 if (!retval)
758 val = VALUE;
759
760 if (!retval) {
761 /* 1-02 firmware limits gain to 2 */
762 if (FIRMWARE_VERSION(1,2) && val > 2)
763 val = 2;
764 switch(val) {
765 case 1:
766 new_params.exposure.gainMode = 1;
767 break;
768 case 2:
769 new_params.exposure.gainMode = 2;
770 break;
771 case 4:
772 new_params.exposure.gainMode = 3;
773 break;
774 case 8:
775 new_params.exposure.gainMode = 4;
776 break;
777 default:
778 retval = -EINVAL;
779 break;
780 }
781 }
782 command_flags |= COMMAND_SETEXPOSURE;
783 } else if (MATCH("exposure_mode")) {
784 if (!retval && MATCH("auto"))
785 new_params.exposure.expMode = 2;
786 else if (!retval && MATCH("manual")) {
787 if (new_params.exposure.expMode == 2)
788 new_params.exposure.expMode = 3;
789 new_params.flickerControl.flickerMode = 0;
790 command_flags |= COMMAND_SETFLICKERCTRL;
791 } else
792 retval = -EINVAL;
793
794 command_flags |= COMMAND_SETEXPOSURE;
795 } else if (MATCH("centre_weight")) {
796 if (!retval && MATCH("on"))
797 new_params.exposure.centreWeight = 1;
798 else if (!retval && MATCH("off"))
799 new_params.exposure.centreWeight = 2;
800 else
801 retval = -EINVAL;
802
803 command_flags |= COMMAND_SETEXPOSURE;
804 } else if (MATCH("gain")) {
805 if (!retval)
806 val = VALUE;
807
808 if (!retval) {
809 switch(val) {
810 case 1:
811 new_params.exposure.gain = 0;
812 new_params.exposure.expMode = 1;
813 new_params.flickerControl.flickerMode = 0;
814 command_flags |= COMMAND_SETFLICKERCTRL;
815 break;
816 case 2:
817 new_params.exposure.gain = 1;
818 new_params.exposure.expMode = 1;
819 new_params.flickerControl.flickerMode = 0;
820 command_flags |= COMMAND_SETFLICKERCTRL;
821 break;
822 case 4:
823 new_params.exposure.gain = 2;
824 new_params.exposure.expMode = 1;
825 new_params.flickerControl.flickerMode = 0;
826 command_flags |= COMMAND_SETFLICKERCTRL;
827 break;
828 case 8:
829 new_params.exposure.gain = 3;
830 new_params.exposure.expMode = 1;
831 new_params.flickerControl.flickerMode = 0;
832 command_flags |= COMMAND_SETFLICKERCTRL;
833 break;
834 default:
835 retval = -EINVAL;
836 break;
837 }
838 command_flags |= COMMAND_SETEXPOSURE;
839 if (new_params.exposure.gain >
840 new_params.exposure.gainMode-1)
841 retval = -EINVAL;
842 }
843 } else if (MATCH("fine_exp")) {
844 if (!retval)
845 val = VALUE;
846
847 if (!retval) {
848 if (val < 256) {
849 /* 1-02 firmware limits fineExp to 127*/
850 if (FIRMWARE_VERSION(1,2) && val > 127)
851 val = 127;
852 new_params.exposure.fineExp = val;
853 new_params.exposure.expMode = 1;
854 command_flags |= COMMAND_SETEXPOSURE;
855 new_params.flickerControl.flickerMode = 0;
856 command_flags |= COMMAND_SETFLICKERCTRL;
857 } else
858 retval = -EINVAL;
859 }
860 } else if (MATCH("coarse_exp")) {
861 if (!retval)
862 val = VALUE;
863
864 if (!retval) {
865 if (val < 65536) {
866 /* 1-02 firmware limits
867 * coarseExp to 255 */
868 if (FIRMWARE_VERSION(1,2) && val > 255)
869 val = 255;
870 new_params.exposure.coarseExpLo =
871 val & 0xff;
872 new_params.exposure.coarseExpHi =
873 val >> 8;
874 new_params.exposure.expMode = 1;
875 command_flags |= COMMAND_SETEXPOSURE;
876 new_params.flickerControl.flickerMode = 0;
877 command_flags |= COMMAND_SETFLICKERCTRL;
878 } else
879 retval = -EINVAL;
880 }
881 } else if (MATCH("red_comp")) {
882 if (!retval)
883 val = VALUE;
884
885 if (!retval) {
886 if (val >= 220 && val <= 255) {
887 new_params.exposure.redComp = val;
888 command_flags |= COMMAND_SETEXPOSURE;
889 } else
890 retval = -EINVAL;
891 }
892 } else if (MATCH("green1_comp")) {
893 if (!retval)
894 val = VALUE;
895
896 if (!retval) {
897 if (val >= 214 && val <= 255) {
898 new_params.exposure.green1Comp = val;
899 command_flags |= COMMAND_SETEXPOSURE;
900 } else
901 retval = -EINVAL;
902 }
903 } else if (MATCH("green2_comp")) {
904 if (!retval)
905 val = VALUE;
906
907 if (!retval) {
908 if (val >= 214 && val <= 255) {
909 new_params.exposure.green2Comp = val;
910 command_flags |= COMMAND_SETEXPOSURE;
911 } else
912 retval = -EINVAL;
913 }
914 } else if (MATCH("blue_comp")) {
915 if (!retval)
916 val = VALUE;
917
918 if (!retval) {
919 if (val >= 230 && val <= 255) {
920 new_params.exposure.blueComp = val;
921 command_flags |= COMMAND_SETEXPOSURE;
922 } else
923 retval = -EINVAL;
924 }
925 } else if (MATCH("apcor_gain1")) {
926 if (!retval)
927 val = VALUE;
928
929 if (!retval) {
930 command_flags |= COMMAND_SETAPCOR;
931 if (val <= 0xff)
932 new_params.apcor.gain1 = val;
933 else
934 retval = -EINVAL;
935 }
936 } else if (MATCH("apcor_gain2")) {
937 if (!retval)
938 val = VALUE;
939
940 if (!retval) {
941 command_flags |= COMMAND_SETAPCOR;
942 if (val <= 0xff)
943 new_params.apcor.gain2 = val;
944 else
945 retval = -EINVAL;
946 }
947 } else if (MATCH("apcor_gain4")) {
948 if (!retval)
949 val = VALUE;
950
951 if (!retval) {
952 command_flags |= COMMAND_SETAPCOR;
953 if (val <= 0xff)
954 new_params.apcor.gain4 = val;
955 else
956 retval = -EINVAL;
957 }
958 } else if (MATCH("apcor_gain8")) {
959 if (!retval)
960 val = VALUE;
961
962 if (!retval) {
963 command_flags |= COMMAND_SETAPCOR;
964 if (val <= 0xff)
965 new_params.apcor.gain8 = val;
966 else
967 retval = -EINVAL;
968 }
969 } else if (MATCH("vl_offset_gain1")) {
970 if (!retval)
971 val = VALUE;
972
973 if (!retval) {
974 if (val <= 0xff)
975 new_params.vlOffset.gain1 = val;
976 else
977 retval = -EINVAL;
978 }
979 command_flags |= COMMAND_SETVLOFFSET;
980 } else if (MATCH("vl_offset_gain2")) {
981 if (!retval)
982 val = VALUE;
983
984 if (!retval) {
985 if (val <= 0xff)
986 new_params.vlOffset.gain2 = val;
987 else
988 retval = -EINVAL;
989 }
990 command_flags |= COMMAND_SETVLOFFSET;
991 } else if (MATCH("vl_offset_gain4")) {
992 if (!retval)
993 val = VALUE;
994
995 if (!retval) {
996 if (val <= 0xff)
997 new_params.vlOffset.gain4 = val;
998 else
999 retval = -EINVAL;
1000 }
1001 command_flags |= COMMAND_SETVLOFFSET;
1002 } else if (MATCH("vl_offset_gain8")) {
1003 if (!retval)
1004 val = VALUE;
1005
1006 if (!retval) {
1007 if (val <= 0xff)
1008 new_params.vlOffset.gain8 = val;
1009 else
1010 retval = -EINVAL;
1011 }
1012 command_flags |= COMMAND_SETVLOFFSET;
1013 } else if (MATCH("flicker_control")) {
1014 if (!retval && MATCH("on")) {
1015 new_params.flickerControl.flickerMode = 1;
1016 new_params.exposure.expMode = 2;
1017 command_flags |= COMMAND_SETEXPOSURE;
1018 } else if (!retval && MATCH("off"))
1019 new_params.flickerControl.flickerMode = 0;
1020 else
1021 retval = -EINVAL;
1022
1023 command_flags |= COMMAND_SETFLICKERCTRL;
1024 } else if (MATCH("mains_frequency")) {
1025 if (!retval && MATCH("50")) {
1026 new_mains = 0;
1027 new_params.flickerControl.coarseJump =
1028 flicker_jumps[new_mains]
1029 [new_params.sensorFps.baserate]
1030 [new_params.sensorFps.divisor];
1031 if (new_params.flickerControl.flickerMode)
1032 command_flags |= COMMAND_SETFLICKERCTRL;
1033 } else if (!retval && MATCH("60")) {
1034 new_mains = 1;
1035 new_params.flickerControl.coarseJump =
1036 flicker_jumps[new_mains]
1037 [new_params.sensorFps.baserate]
1038 [new_params.sensorFps.divisor];
1039 if (new_params.flickerControl.flickerMode)
1040 command_flags |= COMMAND_SETFLICKERCTRL;
1041 } else
1042 retval = -EINVAL;
1043 } else if (MATCH("allowable_overexposure")) {
1044 if (!retval)
1045 val = VALUE;
1046
1047 if (!retval) {
1048 if (val <= 0xff) {
1049 new_params.flickerControl.
1050 allowableOverExposure = val;
1051 command_flags |= COMMAND_SETFLICKERCTRL;
1052 } else
1053 retval = -EINVAL;
1054 }
1055 } else if (MATCH("compression_mode")) {
1056 if (!retval && MATCH("none"))
1057 new_params.compression.mode =
1058 CPIA_COMPRESSION_NONE;
1059 else if (!retval && MATCH("auto"))
1060 new_params.compression.mode =
1061 CPIA_COMPRESSION_AUTO;
1062 else if (!retval && MATCH("manual"))
1063 new_params.compression.mode =
1064 CPIA_COMPRESSION_MANUAL;
1065 else
1066 retval = -EINVAL;
1067
1068 command_flags |= COMMAND_SETCOMPRESSION;
1069 } else if (MATCH("decimation_enable")) {
1070 if (!retval && MATCH("off"))
1071 new_params.compression.decimation = 0;
1072 else
1073 retval = -EINVAL;
1074
1075 command_flags |= COMMAND_SETCOMPRESSION;
1076 } else if (MATCH("compression_target")) {
1077 if (!retval && MATCH("quality"))
1078 new_params.compressionTarget.frTargeting =
1079 CPIA_COMPRESSION_TARGET_QUALITY;
1080 else if (!retval && MATCH("framerate"))
1081 new_params.compressionTarget.frTargeting =
1082 CPIA_COMPRESSION_TARGET_FRAMERATE;
1083 else
1084 retval = -EINVAL;
1085
1086 command_flags |= COMMAND_SETCOMPRESSIONTARGET;
1087 } else if (MATCH("target_framerate")) {
1088 if (!retval)
1089 val = VALUE;
1090
1091 if (!retval)
1092 new_params.compressionTarget.targetFR = val;
1093 command_flags |= COMMAND_SETCOMPRESSIONTARGET;
1094 } else if (MATCH("target_quality")) {
1095 if (!retval)
1096 val = VALUE;
1097
1098 if (!retval)
1099 new_params.compressionTarget.targetQ = val;
1100
1101 command_flags |= COMMAND_SETCOMPRESSIONTARGET;
1102 } else if (MATCH("y_threshold")) {
1103 if (!retval)
1104 val = VALUE;
1105
1106 if (!retval) {
1107 if (val < 32)
1108 new_params.yuvThreshold.yThreshold = val;
1109 else
1110 retval = -EINVAL;
1111 }
1112 command_flags |= COMMAND_SETYUVTHRESH;
1113 } else if (MATCH("uv_threshold")) {
1114 if (!retval)
1115 val = VALUE;
1116
1117 if (!retval) {
1118 if (val < 32)
1119 new_params.yuvThreshold.uvThreshold = val;
1120 else
1121 retval = -EINVAL;
1122 }
1123 command_flags |= COMMAND_SETYUVTHRESH;
1124 } else if (MATCH("hysteresis")) {
1125 if (!retval)
1126 val = VALUE;
1127
1128 if (!retval) {
1129 if (val <= 0xff)
1130 new_params.compressionParams.hysteresis = val;
1131 else
1132 retval = -EINVAL;
1133 }
1134 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1135 } else if (MATCH("threshold_max")) {
1136 if (!retval)
1137 val = VALUE;
1138
1139 if (!retval) {
1140 if (val <= 0xff)
1141 new_params.compressionParams.threshMax = val;
1142 else
1143 retval = -EINVAL;
1144 }
1145 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1146 } else if (MATCH("small_step")) {
1147 if (!retval)
1148 val = VALUE;
1149
1150 if (!retval) {
1151 if (val <= 0xff)
1152 new_params.compressionParams.smallStep = val;
1153 else
1154 retval = -EINVAL;
1155 }
1156 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1157 } else if (MATCH("large_step")) {
1158 if (!retval)
1159 val = VALUE;
1160
1161 if (!retval) {
1162 if (val <= 0xff)
1163 new_params.compressionParams.largeStep = val;
1164 else
1165 retval = -EINVAL;
1166 }
1167 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1168 } else if (MATCH("decimation_hysteresis")) {
1169 if (!retval)
1170 val = VALUE;
1171
1172 if (!retval) {
1173 if (val <= 0xff)
1174 new_params.compressionParams.decimationHysteresis = val;
1175 else
1176 retval = -EINVAL;
1177 }
1178 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1179 } else if (MATCH("fr_diff_step_thresh")) {
1180 if (!retval)
1181 val = VALUE;
1182
1183 if (!retval) {
1184 if (val <= 0xff)
1185 new_params.compressionParams.frDiffStepThresh = val;
1186 else
1187 retval = -EINVAL;
1188 }
1189 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1190 } else if (MATCH("q_diff_step_thresh")) {
1191 if (!retval)
1192 val = VALUE;
1193
1194 if (!retval) {
1195 if (val <= 0xff)
1196 new_params.compressionParams.qDiffStepThresh = val;
1197 else
1198 retval = -EINVAL;
1199 }
1200 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1201 } else if (MATCH("decimation_thresh_mod")) {
1202 if (!retval)
1203 val = VALUE;
1204
1205 if (!retval) {
1206 if (val <= 0xff)
1207 new_params.compressionParams.decimationThreshMod = val;
1208 else
1209 retval = -EINVAL;
1210 }
1211 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1212 } else {
1213 DBG("No match found\n");
1214 retval = -EINVAL;
1215 }
1216
1217 if (!retval) {
1218 while (count && isspace(*buffer) && *buffer != '\n') {
1219 --count;
1220 ++buffer;
1221 }
1222 if (count) {
1223 if (*buffer != '\n' && *buffer != ';')
1224 retval = -EINVAL;
1225 else {
1226 --count;
1227 ++buffer;
1228 }
1229 }
1230 }
1231 }
1232 #undef MATCH
1233 #undef FIRMWARE_VERSION
1234 #undef VALUE
1235 #undef FIND_VALUE
1236 #undef FIND_END
1237 if (!retval) {
1238 if (command_flags & COMMAND_SETCOLOURPARAMS) {
1239 /* Adjust cam->vp to reflect these changes */
1240 cam->vp.brightness =
1241 new_params.colourParams.brightness*65535/100;
1242 cam->vp.contrast =
1243 new_params.colourParams.contrast*65535/100;
1244 cam->vp.colour =
1245 new_params.colourParams.saturation*65535/100;
1246 }
1247
1248 memcpy(&cam->params, &new_params, sizeof(struct cam_params));
1249 cam->mainsFreq = new_mains;
1250 cam->cmd_queue |= command_flags;
1251 retval = size;
1252 } else
1253 DBG("error: %d\n", retval);
1254
1255 up(&cam->param_lock);
1256
1257 return retval;
1258 #endif
1259 }
1260
1261 static void create_proc_cpia_cam(struct cam_data *cam)
1262 {
1263 char name[7];
1264 struct proc_dir_entry *ent;
1265
1266 if (!cpia_proc_root || !cam)
1267 return;
1268
1269 sprintf(name, "video%d", cam->vdev.minor);
1270
1271 ent = create_proc_entry(name, S_IFREG|S_IRUGO|S_IWUSR, cpia_proc_root);
1272 if (!ent)
1273 return;
1274
1275 ent->data = cam;
1276 ent->read_proc = cpia_read_proc;
1277 ent->write_proc = cpia_write_proc;
1278 ent->size = 3626;
1279 cam->proc_entry = ent;
1280 }
1281
1282 static void destroy_proc_cpia_cam(struct cam_data *cam)
1283 {
1284 char name[7];
1285
1286 if (!cam || !cam->proc_entry)
1287 return;
1288
1289 sprintf(name, "video%d", cam->vdev.minor);
1290 remove_proc_entry(name, cpia_proc_root);
1291 cam->proc_entry = NULL;
1292 }
1293
1294 static void proc_cpia_create(void)
1295 {
1296 cpia_proc_root = create_proc_entry("cpia", S_IFDIR, 0);
1297
1298 if (cpia_proc_root)
1299 cpia_proc_root->owner = THIS_MODULE;
1300 else
1301 LOG("Unable to initialise /proc/cpia\n");
1302 }
1303
1304 static void proc_cpia_destroy(void)
1305 {
1306 remove_proc_entry("cpia", 0);
1307 }
1308 #endif /* CONFIG_PROC_FS */
1309
1310 /* ----------------------- debug functions ---------------------- */
1311
1312 #define printstatus(cam) \
1313 DBG("%02x %02x %02x %02x %02x %02x %02x %02x\n",\
1314 cam->params.status.systemState, cam->params.status.grabState, \
1315 cam->params.status.streamState, cam->params.status.fatalError, \
1316 cam->params.status.cmdError, cam->params.status.debugFlags, \
1317 cam->params.status.vpStatus, cam->params.status.errorCode);
1318
1319 /* ----------------------- v4l helpers -------------------------- */
1320
1321 /* supported frame palettes and depths */
1322 static inline int valid_mode(u16 palette, u16 depth)
1323 {
1324 return (palette == VIDEO_PALETTE_GREY && depth == 8) ||
1325 (palette == VIDEO_PALETTE_RGB555 && depth == 16) ||
1326 (palette == VIDEO_PALETTE_RGB565 && depth == 16) ||
1327 (palette == VIDEO_PALETTE_RGB24 && depth == 24) ||
1328 (palette == VIDEO_PALETTE_RGB32 && depth == 32) ||
1329 (palette == VIDEO_PALETTE_YUV422 && depth == 16) ||
1330 (palette == VIDEO_PALETTE_YUYV && depth == 16) ||
1331 (palette == VIDEO_PALETTE_UYVY && depth == 16);
1332 }
1333
1334 static int match_videosize( int width, int height )
1335 {
1336 /* return the best match, where 'best' is as always
1337 * the largest that is not bigger than what is requested. */
1338 if (width>=352 && height>=288)
1339 return VIDEOSIZE_352_288; /* CIF */
1340
1341 if (width>=320 && height>=240)
1342 return VIDEOSIZE_320_240; /* SIF */
1343
1344 if (width>=288 && height>=216)
1345 return VIDEOSIZE_288_216;
1346
1347 if (width>=256 && height>=192)
1348 return VIDEOSIZE_256_192;
1349
1350 if (width>=224 && height>=168)
1351 return VIDEOSIZE_224_168;
1352
1353 if (width>=192 && height>=144)
1354 return VIDEOSIZE_192_144;
1355
1356 if (width>=176 && height>=144)
1357 return VIDEOSIZE_176_144; /* QCIF */
1358
1359 if (width>=160 && height>=120)
1360 return VIDEOSIZE_160_120; /* QSIF */
1361
1362 if (width>=128 && height>=96)
1363 return VIDEOSIZE_128_96;
1364
1365 if (width>=88 && height>=72)
1366 return VIDEOSIZE_88_72;
1367
1368 if (width>=64 && height>=48)
1369 return VIDEOSIZE_64_48;
1370
1371 if (width>=48 && height>=48)
1372 return VIDEOSIZE_48_48;
1373
1374 return -1;
1375 }
1376
1377 /* these are the capture sizes we support */
1378 static void set_vw_size(struct cam_data *cam)
1379 {
1380 /* the col/row/start/end values are the result of simple math */
1381 /* study the SetROI-command in cpia developers guide p 2-22 */
1382 /* streamStartLine is set to the recommended value in the cpia */
1383 /* developers guide p 3-37 */
1384 switch(cam->video_size) {
1385 case VIDEOSIZE_CIF:
1386 cam->vw.width = 352;
1387 cam->vw.height = 288;
1388 cam->params.format.videoSize=VIDEOSIZE_CIF;
1389 cam->params.roi.colStart=0;
1390 cam->params.roi.colEnd=44;
1391 cam->params.roi.rowStart=0;
1392 cam->params.roi.rowEnd=72;
1393 cam->params.streamStartLine = 120;
1394 break;
1395 case VIDEOSIZE_SIF:
1396 cam->vw.width = 320;
1397 cam->vw.height = 240;
1398 cam->params.format.videoSize=VIDEOSIZE_CIF;
1399 cam->params.roi.colStart=2;
1400 cam->params.roi.colEnd=42;
1401 cam->params.roi.rowStart=6;
1402 cam->params.roi.rowEnd=66;
1403 cam->params.streamStartLine = 120;
1404 break;
1405 case VIDEOSIZE_288_216:
1406 cam->vw.width = 288;
1407 cam->vw.height = 216;
1408 cam->params.format.videoSize=VIDEOSIZE_CIF;
1409 cam->params.roi.colStart=4;
1410 cam->params.roi.colEnd=40;
1411 cam->params.roi.rowStart=9;
1412 cam->params.roi.rowEnd=63;
1413 cam->params.streamStartLine = 120;
1414 break;
1415 case VIDEOSIZE_256_192:
1416 cam->vw.width = 256;
1417 cam->vw.height = 192;
1418 cam->params.format.videoSize=VIDEOSIZE_CIF;
1419 cam->params.roi.colStart=6;
1420 cam->params.roi.colEnd=38;
1421 cam->params.roi.rowStart=12;
1422 cam->params.roi.rowEnd=60;
1423 cam->params.streamStartLine = 120;
1424 break;
1425 case VIDEOSIZE_224_168:
1426 cam->vw.width = 224;
1427 cam->vw.height = 168;
1428 cam->params.format.videoSize=VIDEOSIZE_CIF;
1429 cam->params.roi.colStart=8;
1430 cam->params.roi.colEnd=36;
1431 cam->params.roi.rowStart=15;
1432 cam->params.roi.rowEnd=57;
1433 cam->params.streamStartLine = 120;
1434 break;
1435 case VIDEOSIZE_192_144:
1436 cam->vw.width = 192;
1437 cam->vw.height = 144;
1438 cam->params.format.videoSize=VIDEOSIZE_CIF;
1439 cam->params.roi.colStart=10;
1440 cam->params.roi.colEnd=34;
1441 cam->params.roi.rowStart=18;
1442 cam->params.roi.rowEnd=54;
1443 cam->params.streamStartLine = 120;
1444 break;
1445 case VIDEOSIZE_QCIF:
1446 cam->vw.width = 176;
1447 cam->vw.height = 144;
1448 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1449 cam->params.roi.colStart=0;
1450 cam->params.roi.colEnd=22;
1451 cam->params.roi.rowStart=0;
1452 cam->params.roi.rowEnd=36;
1453 cam->params.streamStartLine = 60;
1454 break;
1455 case VIDEOSIZE_QSIF:
1456 cam->vw.width = 160;
1457 cam->vw.height = 120;
1458 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1459 cam->params.roi.colStart=1;
1460 cam->params.roi.colEnd=21;
1461 cam->params.roi.rowStart=3;
1462 cam->params.roi.rowEnd=33;
1463 cam->params.streamStartLine = 60;
1464 break;
1465 case VIDEOSIZE_128_96:
1466 cam->vw.width = 128;
1467 cam->vw.height = 96;
1468 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1469 cam->params.roi.colStart=3;
1470 cam->params.roi.colEnd=19;
1471 cam->params.roi.rowStart=6;
1472 cam->params.roi.rowEnd=30;
1473 cam->params.streamStartLine = 60;
1474 break;
1475 case VIDEOSIZE_88_72:
1476 cam->vw.width = 88;
1477 cam->vw.height = 72;
1478 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1479 cam->params.roi.colStart=5;
1480 cam->params.roi.colEnd=16;
1481 cam->params.roi.rowStart=9;
1482 cam->params.roi.rowEnd=27;
1483 cam->params.streamStartLine = 60;
1484 break;
1485 case VIDEOSIZE_64_48:
1486 cam->vw.width = 64;
1487 cam->vw.height = 48;
1488 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1489 cam->params.roi.colStart=7;
1490 cam->params.roi.colEnd=15;
1491 cam->params.roi.rowStart=12;
1492 cam->params.roi.rowEnd=24;
1493 cam->params.streamStartLine = 60;
1494 break;
1495 case VIDEOSIZE_48_48:
1496 cam->vw.width = 48;
1497 cam->vw.height = 48;
1498 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1499 cam->params.roi.colStart=8;
1500 cam->params.roi.colEnd=14;
1501 cam->params.roi.rowStart=6;
1502 cam->params.roi.rowEnd=30;
1503 cam->params.streamStartLine = 60;
1504 break;
1505 default:
1506 LOG("bad videosize value: %d\n", cam->video_size);
1507 }
1508
1509 return;
1510 }
1511
1512 static int allocate_frame_buf(struct cam_data *cam)
1513 {
1514 int i;
1515
1516 cam->frame_buf = rvmalloc(FRAME_NUM * CPIA_MAX_FRAME_SIZE);
1517 if (!cam->frame_buf)
1518 return -ENOBUFS;
1519
1520 for (i = 0; i < FRAME_NUM; i++)
1521 cam->frame[i].data = cam->frame_buf + i * CPIA_MAX_FRAME_SIZE;
1522
1523 return 0;
1524 }
1525
1526 static int free_frame_buf(struct cam_data *cam)
1527 {
1528 int i;
1529
1530 rvfree(cam->frame_buf, FRAME_NUM*CPIA_MAX_FRAME_SIZE);
1531 cam->frame_buf = 0;
1532 for (i=0; i < FRAME_NUM; i++)
1533 cam->frame[i].data = NULL;
1534
1535 return 0;
1536 }
1537
1538
1539 static void inline free_frames(struct cpia_frame frame[FRAME_NUM])
1540 {
1541 int i;
1542
1543 for (i=0; i < FRAME_NUM; i++)
1544 frame[i].state = FRAME_UNUSED;
1545 return;
1546 }
1547
1548 /**********************************************************************
1549 *
1550 * General functions
1551 *
1552 **********************************************************************/
1553 /* send an arbitrary command to the camera */
1554 static int do_command(struct cam_data *cam, u16 command, u8 a, u8 b, u8 c, u8 d)
1555 {
1556 int retval, datasize;
1557 u8 cmd[8], data[8];
1558
1559 switch(command) {
1560 case CPIA_COMMAND_GetCPIAVersion:
1561 case CPIA_COMMAND_GetPnPID:
1562 case CPIA_COMMAND_GetCameraStatus:
1563 case CPIA_COMMAND_GetVPVersion:
1564 datasize=8;
1565 break;
1566 case CPIA_COMMAND_GetColourParams:
1567 case CPIA_COMMAND_GetColourBalance:
1568 case CPIA_COMMAND_GetExposure:
1569 down(&cam->param_lock);
1570 datasize=8;
1571 break;
1572 default:
1573 datasize=0;
1574 break;
1575 }
1576
1577 cmd[0] = command>>8;
1578 cmd[1] = command&0xff;
1579 cmd[2] = a;
1580 cmd[3] = b;
1581 cmd[4] = c;
1582 cmd[5] = d;
1583 cmd[6] = datasize;
1584 cmd[7] = 0;
1585
1586 retval = cam->ops->transferCmd(cam->lowlevel_data, cmd, data);
1587 if (retval) {
1588 DBG("%x - failed, retval=%d\n", command, retval);
1589 if (command == CPIA_COMMAND_GetColourParams ||
1590 command == CPIA_COMMAND_GetColourBalance ||
1591 command == CPIA_COMMAND_GetExposure)
1592 up(&cam->param_lock);
1593 } else {
1594 switch(command) {
1595 case CPIA_COMMAND_GetCPIAVersion:
1596 cam->params.version.firmwareVersion = data[0];
1597 cam->params.version.firmwareRevision = data[1];
1598 cam->params.version.vcVersion = data[2];
1599 cam->params.version.vcRevision = data[3];
1600 break;
1601 case CPIA_COMMAND_GetPnPID:
1602 cam->params.pnpID.vendor = data[0]+(((u16)data[1])<<8);
1603 cam->params.pnpID.product = data[2]+(((u16)data[3])<<8);
1604 cam->params.pnpID.deviceRevision =
1605 data[4]+(((u16)data[5])<<8);
1606 break;
1607 case CPIA_COMMAND_GetCameraStatus:
1608 cam->params.status.systemState = data[0];
1609 cam->params.status.grabState = data[1];
1610 cam->params.status.streamState = data[2];
1611 cam->params.status.fatalError = data[3];
1612 cam->params.status.cmdError = data[4];
1613 cam->params.status.debugFlags = data[5];
1614 cam->params.status.vpStatus = data[6];
1615 cam->params.status.errorCode = data[7];
1616 break;
1617 case CPIA_COMMAND_GetVPVersion:
1618 cam->params.vpVersion.vpVersion = data[0];
1619 cam->params.vpVersion.vpRevision = data[1];
1620 cam->params.vpVersion.cameraHeadID =
1621 data[2]+(((u16)data[3])<<8);
1622 break;
1623 case CPIA_COMMAND_GetColourParams:
1624 cam->params.colourParams.brightness = data[0];
1625 cam->params.colourParams.contrast = data[1];
1626 cam->params.colourParams.saturation = data[2];
1627 up(&cam->param_lock);
1628 break;
1629 case CPIA_COMMAND_GetColourBalance:
1630 cam->params.colourBalance.redGain = data[0];
1631 cam->params.colourBalance.greenGain = data[1];
1632 cam->params.colourBalance.blueGain = data[2];
1633 up(&cam->param_lock);
1634 break;
1635 case CPIA_COMMAND_GetExposure:
1636 cam->params.exposure.gain = data[0];
1637 cam->params.exposure.fineExp = data[1];
1638 cam->params.exposure.coarseExpLo = data[2];
1639 cam->params.exposure.coarseExpHi = data[3];
1640 cam->params.exposure.redComp = data[4];
1641 cam->params.exposure.green1Comp = data[5];
1642 cam->params.exposure.green2Comp = data[6];
1643 cam->params.exposure.blueComp = data[7];
1644 /* If the *Comp parameters are wacko, generate
1645 * a warning, and reset them back to default
1646 * values. - rich@annexia.org
1647 */
1648 if (cam->params.exposure.redComp < 220 ||
1649 cam->params.exposure.redComp > 255 ||
1650 cam->params.exposure.green1Comp < 214 ||
1651 cam->params.exposure.green1Comp > 255 ||
1652 cam->params.exposure.green2Comp < 214 ||
1653 cam->params.exposure.green2Comp > 255 ||
1654 cam->params.exposure.blueComp < 230 ||
1655 cam->params.exposure.blueComp > 255)
1656 {
1657 printk (KERN_WARNING "*_comp parameters have gone AWOL (%d/%d/%d/%d) - reseting them\n",
1658 cam->params.exposure.redComp,
1659 cam->params.exposure.green1Comp,
1660 cam->params.exposure.green2Comp,
1661 cam->params.exposure.blueComp);
1662 cam->params.exposure.redComp = 220;
1663 cam->params.exposure.green1Comp = 214;
1664 cam->params.exposure.green2Comp = 214;
1665 cam->params.exposure.blueComp = 230;
1666 }
1667 up(&cam->param_lock);
1668 break;
1669 default:
1670 break;
1671 }
1672 }
1673 return retval;
1674 }
1675
1676 /* send a command to the camera with an additional data transaction */
1677 static int do_command_extended(struct cam_data *cam, u16 command,
1678 u8 a, u8 b, u8 c, u8 d,
1679 u8 e, u8 f, u8 g, u8 h,
1680 u8 i, u8 j, u8 k, u8 l)
1681 {
1682 int retval;
1683 u8 cmd[8], data[8];
1684
1685 cmd[0] = command>>8;
1686 cmd[1] = command&0xff;
1687 cmd[2] = a;
1688 cmd[3] = b;
1689 cmd[4] = c;
1690 cmd[5] = d;
1691 cmd[6] = 8;
1692 cmd[7] = 0;
1693 data[0] = e;
1694 data[1] = f;
1695 data[2] = g;
1696 data[3] = h;
1697 data[4] = i;
1698 data[5] = j;
1699 data[6] = k;
1700 data[7] = l;
1701
1702 retval = cam->ops->transferCmd(cam->lowlevel_data, cmd, data);
1703 if (retval)
1704 LOG("%x - failed\n", command);
1705
1706 return retval;
1707 }
1708
1709 /**********************************************************************
1710 *
1711 * Colorspace conversion
1712 *
1713 **********************************************************************/
1714 #define LIMIT(x) ((((x)>0xffffff)?0xff0000:(((x)<=0xffff)?0:(x)&0xff0000))>>16)
1715
1716 static int yuvconvert(unsigned char *yuv, unsigned char *rgb, int out_fmt,
1717 int in_uyvy, int mmap_kludge)
1718 {
1719 int y, u, v, r, g, b, y1;
1720
1721 switch(out_fmt) {
1722 case VIDEO_PALETTE_RGB555:
1723 case VIDEO_PALETTE_RGB565:
1724 case VIDEO_PALETTE_RGB24:
1725 case VIDEO_PALETTE_RGB32:
1726 if (in_uyvy) {
1727 u = *yuv++ - 128;
1728 y = (*yuv++ - 16) * 76310;
1729 v = *yuv++ - 128;
1730 y1 = (*yuv - 16) * 76310;
1731 } else {
1732 y = (*yuv++ - 16) * 76310;
1733 u = *yuv++ - 128;
1734 y1 = (*yuv++ - 16) * 76310;
1735 v = *yuv - 128;
1736 }
1737 r = 104635 * v;
1738 g = -25690 * u + -53294 * v;
1739 b = 132278 * u;
1740 break;
1741 default:
1742 y = *yuv++;
1743 u = *yuv++;
1744 y1 = *yuv++;
1745 v = *yuv;
1746 /* Just to avoid compiler warnings */
1747 r = 0;
1748 g = 0;
1749 b = 0;
1750 break;
1751 }
1752 switch(out_fmt) {
1753 case VIDEO_PALETTE_RGB555:
1754 *rgb++ = ((LIMIT(g+y) & 0xf8) << 2) | (LIMIT(b+y) >> 3);
1755 *rgb++ = ((LIMIT(r+y) & 0xf8) >> 1) | (LIMIT(g+y) >> 6);
1756 *rgb++ = ((LIMIT(g+y1) & 0xf8) << 2) | (LIMIT(b+y1) >> 3);
1757 *rgb = ((LIMIT(r+y1) & 0xf8) >> 1) | (LIMIT(g+y1) >> 6);
1758 return 4;
1759 case VIDEO_PALETTE_RGB565:
1760 *rgb++ = ((LIMIT(g+y) & 0xfc) << 3) | (LIMIT(b+y) >> 3);
1761 *rgb++ = (LIMIT(r+y) & 0xf8) | (LIMIT(g+y) >> 5);
1762 *rgb++ = ((LIMIT(g+y1) & 0xfc) << 3) | (LIMIT(b+y1) >> 3);
1763 *rgb = (LIMIT(r+y1) & 0xf8) | (LIMIT(g+y1) >> 5);
1764 return 4;
1765 case VIDEO_PALETTE_RGB24:
1766 if (mmap_kludge) {
1767 *rgb++ = LIMIT(b+y);
1768 *rgb++ = LIMIT(g+y);
1769 *rgb++ = LIMIT(r+y);
1770 *rgb++ = LIMIT(b+y1);
1771 *rgb++ = LIMIT(g+y1);
1772 *rgb = LIMIT(r+y1);
1773 } else {
1774 *rgb++ = LIMIT(r+y);
1775 *rgb++ = LIMIT(g+y);
1776 *rgb++ = LIMIT(b+y);
1777 *rgb++ = LIMIT(r+y1);
1778 *rgb++ = LIMIT(g+y1);
1779 *rgb = LIMIT(b+y1);
1780 }
1781 return 6;
1782 case VIDEO_PALETTE_RGB32:
1783 if (mmap_kludge) {
1784 *rgb++ = LIMIT(b+y);
1785 *rgb++ = LIMIT(g+y);
1786 *rgb++ = LIMIT(r+y);
1787 rgb++;
1788 *rgb++ = LIMIT(b+y1);
1789 *rgb++ = LIMIT(g+y1);
1790 *rgb = LIMIT(r+y1);
1791 } else {
1792 *rgb++ = LIMIT(r+y);
1793 *rgb++ = LIMIT(g+y);
1794 *rgb++ = LIMIT(b+y);
1795 rgb++;
1796 *rgb++ = LIMIT(r+y1);
1797 *rgb++ = LIMIT(g+y1);
1798 *rgb = LIMIT(b+y1);
1799 }
1800 return 8;
1801 case VIDEO_PALETTE_GREY:
1802 *rgb++ = y;
1803 *rgb = y1;
1804 return 2;
1805 case VIDEO_PALETTE_YUV422:
1806 case VIDEO_PALETTE_YUYV:
1807 *rgb++ = y;
1808 *rgb++ = u;
1809 *rgb++ = y1;
1810 *rgb = v;
1811 return 4;
1812 case VIDEO_PALETTE_UYVY:
1813 *rgb++ = u;
1814 *rgb++ = y;
1815 *rgb++ = v;
1816 *rgb = y1;
1817 return 4;
1818 default:
1819 DBG("Empty: %d\n", out_fmt);
1820 return 0;
1821 }
1822 }
1823
1824 static int skipcount(int count, int fmt)
1825 {
1826 switch(fmt) {
1827 case VIDEO_PALETTE_GREY:
1828 case VIDEO_PALETTE_RGB555:
1829 case VIDEO_PALETTE_RGB565:
1830 case VIDEO_PALETTE_YUV422:
1831 case VIDEO_PALETTE_YUYV:
1832 case VIDEO_PALETTE_UYVY:
1833 return 2*count;
1834 case VIDEO_PALETTE_RGB24:
1835 return 3*count;
1836 case VIDEO_PALETTE_RGB32:
1837 return 4*count;
1838 default:
1839 return 0;
1840 }
1841 }
1842
1843 static int parse_picture(struct cam_data *cam, int size)
1844 {
1845 u8 *obuf, *ibuf, *end_obuf;
1846 int ll, in_uyvy, compressed, origsize, out_fmt;
1847
1848 /* make sure params don't change while we are decoding */
1849 down(&cam->param_lock);
1850
1851 obuf = cam->decompressed_frame.data;
1852 end_obuf = obuf+CPIA_MAX_FRAME_SIZE;
1853 ibuf = cam->raw_image;
1854 origsize = size;
1855 out_fmt = cam->vp.palette;
1856
1857 if ((ibuf[0] != MAGIC_0) || (ibuf[1] != MAGIC_1)) {
1858 LOG("header not found\n");
1859 up(&cam->param_lock);
1860 return -1;
1861 }
1862
1863 if ((ibuf[16] != VIDEOSIZE_QCIF) && (ibuf[16] != VIDEOSIZE_CIF)) {
1864 LOG("wrong video size\n");
1865 up(&cam->param_lock);
1866 return -1;
1867 }
1868
1869 if (ibuf[17] != SUBSAMPLE_422) {
1870 LOG("illegal subtype %d\n",ibuf[17]);
1871 up(&cam->param_lock);
1872 return -1;
1873 }
1874
1875 if (ibuf[18] != YUVORDER_YUYV && ibuf[18] != YUVORDER_UYVY) {
1876 LOG("illegal yuvorder %d\n",ibuf[18]);
1877 up(&cam->param_lock);
1878 return -1;
1879 }
1880 in_uyvy = ibuf[18] == YUVORDER_UYVY;
1881
1882 #if 0
1883 /* FIXME: ROI mismatch occurs when switching capture sizes */
1884 if ((ibuf[24] != cam->params.roi.colStart) ||
1885 (ibuf[25] != cam->params.roi.colEnd) ||
1886 (ibuf[26] != cam->params.roi.rowStart) ||
1887 (ibuf[27] != cam->params.roi.rowEnd)) {
1888 LOG("ROI mismatch\n");
1889 up(&cam->param_lock);
1890 return -1;
1891 }
1892 #endif
1893
1894 if ((ibuf[28] != NOT_COMPRESSED) && (ibuf[28] != COMPRESSED)) {
1895 LOG("illegal compression %d\n",ibuf[28]);
1896 up(&cam->param_lock);
1897 return -1;
1898 }
1899 compressed = (ibuf[28] == COMPRESSED);
1900
1901 if (ibuf[29] != NO_DECIMATION) {
1902 LOG("decimation not supported\n");
1903 up(&cam->param_lock);
1904 return -1;
1905 }
1906
1907 cam->params.yuvThreshold.yThreshold = ibuf[30];
1908 cam->params.yuvThreshold.uvThreshold = ibuf[31];
1909 cam->params.status.systemState = ibuf[32];
1910 cam->params.status.grabState = ibuf[33];
1911 cam->params.status.streamState = ibuf[34];
1912 cam->params.status.fatalError = ibuf[35];
1913 cam->params.status.cmdError = ibuf[36];
1914 cam->params.status.debugFlags = ibuf[37];
1915 cam->params.status.vpStatus = ibuf[38];
1916 cam->params.status.errorCode = ibuf[39];
1917 cam->fps = ibuf[41];
1918 up(&cam->param_lock);
1919
1920 ibuf += FRAME_HEADER_SIZE;
1921 size -= FRAME_HEADER_SIZE;
1922 ll = ibuf[0] | (ibuf[1] << 8);
1923 ibuf += 2;
1924
1925 while (size > 0) {
1926 size -= (ll+2);
1927 if (size < 0) {
1928 LOG("Insufficient data in buffer\n");
1929 return -1;
1930 }
1931
1932 while (ll > 1) {
1933 if (!compressed || (compressed && !(*ibuf & 1))) {
1934 obuf += yuvconvert(ibuf, obuf, out_fmt,
1935 in_uyvy, cam->mmap_kludge);
1936 ibuf += 4;
1937 ll -= 4;
1938 } else {
1939 /*skip compressed interval from previous frame*/
1940 int skipsize = skipcount(*ibuf >> 1, out_fmt);
1941 obuf += skipsize;
1942 if (obuf > end_obuf) {
1943 LOG("Insufficient data in buffer\n");
1944 return -1;
1945 }
1946 ++ibuf;
1947 ll--;
1948 }
1949 }
1950 if (ll == 1) {
1951 if (*ibuf != EOL) {
1952 LOG("EOL not found giving up after %d/%d"
1953 " bytes\n", origsize-size, origsize);
1954 return -1;
1955 }
1956
1957 ibuf++; /* skip over EOL */
1958
1959 if ((size > 3) && (ibuf[0] == EOI) && (ibuf[1] == EOI) &&
1960 (ibuf[2] == EOI) && (ibuf[3] == EOI)) {
1961 size -= 4;
1962 break;
1963 }
1964
1965 if (size > 1) {
1966 ll = ibuf[0] | (ibuf[1] << 8);
1967 ibuf += 2; /* skip over line length */
1968 }
1969 } else {
1970 LOG("line length was not 1 but %d after %d/%d bytes\n",
1971 ll, origsize-size, origsize);
1972 return -1;
1973 }
1974 }
1975
1976 cam->decompressed_frame.count = obuf-cam->decompressed_frame.data;
1977
1978 return cam->decompressed_frame.count;
1979 }
1980
1981 /* InitStreamCap wrapper to select correct start line */
1982 static inline int init_stream_cap(struct cam_data *cam)
1983 {
1984 return do_command(cam, CPIA_COMMAND_InitStreamCap,
1985 0, cam->params.streamStartLine, 0, 0);
1986 }
1987
1988 /* update various camera modes and settings */
1989 static void dispatch_commands(struct cam_data *cam)
1990 {
1991 down(&cam->param_lock);
1992 if (cam->cmd_queue==COMMAND_NONE) {
1993 up(&cam->param_lock);
1994 return;
1995 }
1996 DEB_BYTE(cam->cmd_queue);
1997 DEB_BYTE(cam->cmd_queue>>8);
1998 if (cam->cmd_queue & COMMAND_SETCOLOURPARAMS)
1999 do_command(cam, CPIA_COMMAND_SetColourParams,
2000 cam->params.colourParams.brightness,
2001 cam->params.colourParams.contrast,
2002 cam->params.colourParams.saturation, 0);
2003
2004 if (cam->cmd_queue & COMMAND_SETCOMPRESSION)
2005 do_command(cam, CPIA_COMMAND_SetCompression,
2006 cam->params.compression.mode,
2007 cam->params.compression.decimation, 0, 0);
2008
2009 if (cam->cmd_queue & COMMAND_SETFORMAT) {
2010 do_command(cam, CPIA_COMMAND_SetFormat,
2011 cam->params.format.videoSize,
2012 cam->params.format.subSample,
2013 cam->params.format.yuvOrder, 0);
2014 do_command(cam, CPIA_COMMAND_SetROI,
2015 cam->params.roi.colStart, cam->params.roi.colEnd,
2016 cam->params.roi.rowStart, cam->params.roi.rowEnd);
2017 cam->first_frame = 1;
2018 }
2019
2020 if (cam->cmd_queue & COMMAND_SETCOMPRESSIONTARGET)
2021 do_command(cam, CPIA_COMMAND_SetCompressionTarget,
2022 cam->params.compressionTarget.frTargeting,
2023 cam->params.compressionTarget.targetFR,
2024 cam->params.compressionTarget.targetQ, 0);
2025
2026 if (cam->cmd_queue & COMMAND_SETYUVTHRESH)
2027 do_command(cam, CPIA_COMMAND_SetYUVThresh,
2028 cam->params.yuvThreshold.yThreshold,
2029 cam->params.yuvThreshold.uvThreshold, 0, 0);
2030
2031 if (cam->cmd_queue & COMMAND_SETECPTIMING)
2032 do_command(cam, CPIA_COMMAND_SetECPTiming,
2033 cam->params.ecpTiming, 0, 0, 0);
2034
2035 if (cam->cmd_queue & COMMAND_SETCOMPRESSIONPARAMS)
2036 do_command_extended(cam, CPIA_COMMAND_SetCompressionParams,
2037 0, 0, 0, 0,
2038 cam->params.compressionParams.hysteresis,
2039 cam->params.compressionParams.threshMax,
2040 cam->params.compressionParams.smallStep,
2041 cam->params.compressionParams.largeStep,
2042 cam->params.compressionParams.decimationHysteresis,
2043 cam->params.compressionParams.frDiffStepThresh,
2044 cam->params.compressionParams.qDiffStepThresh,
2045 cam->params.compressionParams.decimationThreshMod);
2046
2047 if (cam->cmd_queue & COMMAND_SETEXPOSURE)
2048 do_command_extended(cam, CPIA_COMMAND_SetExposure,
2049 cam->params.exposure.gainMode,
2050 cam->params.exposure.expMode,
2051 cam->params.exposure.compMode,
2052 cam->params.exposure.centreWeight,
2053 cam->params.exposure.gain,
2054 cam->params.exposure.fineExp,
2055 cam->params.exposure.coarseExpLo,
2056 cam->params.exposure.coarseExpHi,
2057 cam->params.exposure.redComp,
2058 cam->params.exposure.green1Comp,
2059 cam->params.exposure.green2Comp,
2060 cam->params.exposure.blueComp);
2061
2062 if (cam->cmd_queue & COMMAND_SETCOLOURBALANCE) {
2063 if (cam->params.colourBalance.balanceModeIsAuto) {
2064 do_command(cam, CPIA_COMMAND_SetColourBalance,
2065 2, 0, 0, 0);
2066 } else {
2067 do_command(cam, CPIA_COMMAND_SetColourBalance,
2068 1,
2069 cam->params.colourBalance.redGain,
2070 cam->params.colourBalance.greenGain,
2071 cam->params.colourBalance.blueGain);
2072 do_command(cam, CPIA_COMMAND_SetColourBalance,
2073 3, 0, 0, 0);
2074 }
2075 }
2076
2077 if (cam->cmd_queue & COMMAND_SETSENSORFPS)
2078 do_command(cam, CPIA_COMMAND_SetSensorFPS,
2079 cam->params.sensorFps.divisor,
2080 cam->params.sensorFps.baserate, 0, 0);
2081
2082 if (cam->cmd_queue & COMMAND_SETAPCOR)
2083 do_command(cam, CPIA_COMMAND_SetApcor,
2084 cam->params.apcor.gain1,
2085 cam->params.apcor.gain2,
2086 cam->params.apcor.gain4,
2087 cam->params.apcor.gain8);
2088
2089 if (cam->cmd_queue & COMMAND_SETFLICKERCTRL)
2090 do_command(cam, CPIA_COMMAND_SetFlickerCtrl,
2091 cam->params.flickerControl.flickerMode,
2092 cam->params.flickerControl.coarseJump,
2093 cam->params.flickerControl.allowableOverExposure, 0);
2094
2095 if (cam->cmd_queue & COMMAND_SETVLOFFSET)
2096 do_command(cam, CPIA_COMMAND_SetVLOffset,
2097 cam->params.vlOffset.gain1,
2098 cam->params.vlOffset.gain2,
2099 cam->params.vlOffset.gain4,
2100 cam->params.vlOffset.gain8);
2101
2102 if (cam->cmd_queue & COMMAND_PAUSE)
2103 do_command(cam, CPIA_COMMAND_EndStreamCap, 0, 0, 0, 0);
2104
2105 if (cam->cmd_queue & COMMAND_RESUME)
2106 init_stream_cap(cam);
2107
2108 up(&cam->param_lock);
2109 cam->cmd_queue = COMMAND_NONE;
2110 return;
2111 }
2112
2113 /* kernel thread function to read image from camera */
2114 static void fetch_frame(void *data)
2115 {
2116 int image_size, retry;
2117 struct cam_data *cam = (struct cam_data *)data;
2118 unsigned long oldjif, rate, diff;
2119
2120 /* Allow up to two bad images in a row to be read and
2121 * ignored before an error is reported */
2122 for (retry = 0; retry < 3; ++retry) {
2123 if (retry)
2124 DBG("retry=%d\n", retry);
2125
2126 if (!cam->ops)
2127 continue;
2128
2129 /* load first frame always uncompressed */
2130 if (cam->first_frame &&
2131 cam->params.compression.mode != CPIA_COMPRESSION_NONE)
2132 do_command(cam, CPIA_COMMAND_SetCompression,
2133 CPIA_COMPRESSION_NONE,
2134 NO_DECIMATION, 0, 0);
2135
2136 /* init camera upload */
2137 if (do_command(cam, CPIA_COMMAND_SetGrabMode,
2138 CPIA_GRAB_CONTINUOUS, 0, 0, 0))
2139 continue;
2140
2141 if (do_command(cam, CPIA_COMMAND_GrabFrame, 0,
2142 cam->params.streamStartLine, 0, 0))
2143 continue;
2144
2145 if (cam->ops->wait_for_stream_ready) {
2146 /* loop until image ready */
2147 do_command(cam, CPIA_COMMAND_GetCameraStatus,0,0,0,0);
2148 while (cam->params.status.streamState != STREAM_READY) {
2149 if (current->need_resched)
2150 schedule();
2151
2152 current->state = TASK_INTERRUPTIBLE;
2153
2154 /* sleep for 10 ms, hopefully ;) */
2155 schedule_timeout(10*HZ/1000);
2156 if (signal_pending(current))
2157 return;
2158
2159 do_command(cam, CPIA_COMMAND_GetCameraStatus,
2160 0, 0, 0, 0);
2161 }
2162 }
2163
2164 /* grab image from camera */
2165 if (current->need_resched)
2166 schedule();
2167
2168 oldjif = jiffies;
2169 image_size = cam->ops->streamRead(cam->lowlevel_data,
2170 cam->raw_image, 0);
2171 if (image_size <= 0) {
2172 DBG("streamRead failed: %d\n", image_size);
2173 continue;
2174 }
2175
2176 rate = image_size * HZ / 1024;
2177 diff = jiffies-oldjif;
2178 cam->transfer_rate = diff==0 ? rate : rate/diff;
2179 /* diff==0 ? unlikely but possible */
2180
2181 /* camera idle now so dispatch queued commands */
2182 dispatch_commands(cam);
2183
2184 /* Update our knowledge of the camera state - FIXME: necessary? */
2185 do_command(cam, CPIA_COMMAND_GetColourBalance, 0, 0, 0, 0);
2186 do_command(cam, CPIA_COMMAND_GetExposure, 0, 0, 0, 0);
2187
2188 /* decompress and convert image to by copying it from
2189 * raw_image to decompressed_frame
2190 */
2191 if (current->need_resched)
2192 schedule();
2193
2194 cam->image_size = parse_picture(cam, image_size);
2195 if (cam->image_size <= 0)
2196 DBG("parse_picture failed %d\n", cam->image_size);
2197 else
2198 break;
2199 }
2200
2201 if (retry < 3) {
2202 /* FIXME: this only works for double buffering */
2203 if (cam->frame[cam->curframe].state == FRAME_READY) {
2204 memcpy(cam->frame[cam->curframe].data,
2205 cam->decompressed_frame.data,
2206 cam->decompressed_frame.count);
2207 cam->frame[cam->curframe].state = FRAME_DONE;
2208 } else
2209 cam->decompressed_frame.state = FRAME_DONE;
2210
2211 #if 0
2212 if (cam->first_frame &&
2213 cam->params.compression.mode != CPIA_COMPRESSION_NONE) {
2214 cam->first_frame = 0;
2215 cam->cmd_queue |= COMMAND_SETCOMPRESSION;
2216 }
2217 #else
2218 if (cam->first_frame) {
2219 cam->first_frame = 0;
2220 cam->cmd_queue |= COMMAND_SETCOMPRESSION;
2221 cam->cmd_queue |= COMMAND_SETEXPOSURE;
2222 }
2223 #endif
2224 }
2225 }
2226
2227 static int capture_frame(struct cam_data *cam, struct video_mmap *vm)
2228 {
2229 int retval = 0;
2230
2231 if (!cam->frame_buf) {
2232 /* we do lazy allocation */
2233 if ((retval = allocate_frame_buf(cam)))
2234 return retval;
2235 }
2236
2237 /* FIXME: the first frame seems to be captured by the camera
2238 without regards to any initial settings, so we throw away
2239 that one, the next one is generated with our settings
2240 (exposure, color balance, ...)
2241 */
2242 if (cam->first_frame) {
2243 cam->curframe = vm->frame;
2244 cam->frame[cam->curframe].state = FRAME_READY;
2245 fetch_frame(cam);
2246 if (cam->frame[cam->curframe].state != FRAME_DONE)
2247 retval = -EIO;
2248 }
2249 cam->curframe = vm->frame;
2250 cam->frame[cam->curframe].state = FRAME_READY;
2251 fetch_frame(cam);
2252 if (cam->frame[cam->curframe].state != FRAME_DONE)
2253 retval=-EIO;
2254
2255 return retval;
2256 }
2257
2258 static int goto_high_power(struct cam_data *cam)
2259 {
2260 if (do_command(cam, CPIA_COMMAND_GotoHiPower, 0, 0, 0, 0))
2261 return -1;
2262 mdelay(100); /* windows driver does it too */
2263 if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0))
2264 return -1;
2265 if (cam->params.status.systemState == HI_POWER_STATE) {
2266 DBG("camera now in HIGH power state\n");
2267 return 0;
2268 }
2269 printstatus(cam);
2270 return -1;
2271 }
2272
2273 static int goto_low_power(struct cam_data *cam)
2274 {
2275 if (do_command(cam, CPIA_COMMAND_GotoLoPower, 0, 0, 0, 0))
2276 return -1;
2277 if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0))
2278 return -1;
2279 if (cam->params.status.systemState == LO_POWER_STATE) {
2280 DBG("camera now in LOW power state\n");
2281 return 0;
2282 }
2283 printstatus(cam);
2284 return -1;
2285 }
2286
2287 static void save_camera_state(struct cam_data *cam)
2288 {
2289 do_command(cam, CPIA_COMMAND_GetColourBalance, 0, 0, 0, 0);
2290 do_command(cam, CPIA_COMMAND_GetExposure, 0, 0, 0, 0);
2291
2292 DBG("%d/%d/%d/%d/%d/%d/%d/%d\n",
2293 cam->params.exposure.gain,
2294 cam->params.exposure.fineExp,
2295 cam->params.exposure.coarseExpLo,
2296 cam->params.exposure.coarseExpHi,
2297 cam->params.exposure.redComp,
2298 cam->params.exposure.green1Comp,
2299 cam->params.exposure.green2Comp,
2300 cam->params.exposure.blueComp);
2301 DBG("%d/%d/%d\n",
2302 cam->params.colourBalance.redGain,
2303 cam->params.colourBalance.greenGain,
2304 cam->params.colourBalance.blueGain);
2305 }
2306
2307 static void set_camera_state(struct cam_data *cam)
2308 {
2309 if(cam->params.colourBalance.balanceModeIsAuto) {
2310 do_command(cam, CPIA_COMMAND_SetColourBalance,
2311 2, 0, 0, 0);
2312 } else {
2313 do_command(cam, CPIA_COMMAND_SetColourBalance,
2314 1,
2315 cam->params.colourBalance.redGain,
2316 cam->params.colourBalance.greenGain,
2317 cam->params.colourBalance.blueGain);
2318 do_command(cam, CPIA_COMMAND_SetColourBalance,
2319 3, 0, 0, 0);
2320 }
2321
2322
2323 do_command_extended(cam, CPIA_COMMAND_SetExposure,
2324 cam->params.exposure.gainMode, 1, 1,
2325 cam->params.exposure.centreWeight,
2326 cam->params.exposure.gain,
2327 cam->params.exposure.fineExp,
2328 cam->params.exposure.coarseExpLo,
2329 cam->params.exposure.coarseExpHi,
2330 cam->params.exposure.redComp,
2331 cam->params.exposure.green1Comp,
2332 cam->params.exposure.green2Comp,
2333 cam->params.exposure.blueComp);
2334 do_command_extended(cam, CPIA_COMMAND_SetExposure,
2335 0, 3, 0, 0,
2336 0, 0, 0, 0, 0, 0, 0, 0);
2337
2338 if (!cam->params.exposure.gainMode)
2339 cam->params.exposure.gainMode = 2;
2340 if (!cam->params.exposure.expMode)
2341 cam->params.exposure.expMode = 2;
2342 if (!cam->params.exposure.centreWeight)
2343 cam->params.exposure.centreWeight = 1;
2344
2345 cam->cmd_queue = COMMAND_SETCOMPRESSION |
2346 COMMAND_SETCOMPRESSIONTARGET |
2347 COMMAND_SETCOLOURPARAMS |
2348 COMMAND_SETFORMAT |
2349 COMMAND_SETYUVTHRESH |
2350 COMMAND_SETECPTIMING |
2351 COMMAND_SETCOMPRESSIONPARAMS |
2352 #if 0
2353 COMMAND_SETEXPOSURE |
2354 #endif
2355 COMMAND_SETCOLOURBALANCE |
2356 COMMAND_SETSENSORFPS |
2357 COMMAND_SETAPCOR |
2358 COMMAND_SETFLICKERCTRL |
2359 COMMAND_SETVLOFFSET;
2360 dispatch_commands(cam);
2361 save_camera_state(cam);
2362
2363 return;
2364 }
2365
2366 static void get_version_information(struct cam_data *cam)
2367 {
2368 /* GetCPIAVersion */
2369 do_command(cam, CPIA_COMMAND_GetCPIAVersion, 0, 0, 0, 0);
2370
2371 /* GetPnPID */
2372 do_command(cam, CPIA_COMMAND_GetPnPID, 0, 0, 0, 0);
2373 }
2374
2375 /* initialize camera */
2376 static int reset_camera(struct cam_data *cam)
2377 {
2378 /* Start the camera in low power mode */
2379 if (goto_low_power(cam)) {
2380 if (cam->params.status.systemState != WARM_BOOT_STATE)
2381 return -ENODEV;
2382
2383 /* FIXME: this is just dirty trial and error */
2384 reset_camera_struct(cam);
2385 goto_high_power(cam);
2386 do_command(cam, CPIA_COMMAND_DiscardFrame, 0, 0, 0, 0);
2387 if (goto_low_power(cam))
2388 return -NODEV;
2389 }
2390
2391 /* procedure described in developer's guide p3-28 */
2392
2393 /* Check the firmware version FIXME: should we check PNPID? */
2394 cam->params.version.firmwareVersion = 0;
2395 get_version_information(cam);
2396 if (cam->params.version.firmwareVersion != 1)
2397 return -ENODEV;
2398
2399 /* The fatal error checking should be done after
2400 * the camera powers up (developer's guide p 3-38) */
2401
2402 /* Set streamState before transition to high power to avoid bug
2403 * in firmware 1-02 */
2404 do_command(cam, CPIA_COMMAND_ModifyCameraStatus, STREAMSTATE, 0,
2405 STREAM_NOT_READY, 0);
2406
2407 /* GotoHiPower */
2408 if (goto_high_power(cam))
2409 return -ENODEV;
2410
2411 /* Check the camera status */
2412 if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0))
2413 return -EIO;
2414
2415 if (cam->params.status.fatalError) {
2416 DBG("fatal_error: %#04x\n",
2417 cam->params.status.fatalError);
2418 DBG("vp_status: %#04x\n",
2419 cam->params.status.vpStatus);
2420 if (cam->params.status.fatalError & ~(COM_FLAG|CPIA_FLAG)) {
2421 /* Fatal error in camera */
2422 return -EIO;
2423 } else if (cam->params.status.fatalError & (COM_FLAG|CPIA_FLAG)) {
2424 /* Firmware 1-02 may do this for parallel port cameras,
2425 * just clear the flags (developer's guide p 3-38) */
2426 do_command(cam, CPIA_COMMAND_ModifyCameraStatus,
2427 FATALERROR, ~(COM_FLAG|CPIA_FLAG), 0, 0);
2428 }
2429 }
2430
2431 /* Check the camera status again */
2432 if (cam->params.status.fatalError) {
2433 if (cam->params.status.fatalError)
2434 return -EIO;
2435 }
2436
2437 /* VPVersion can't be retrieved before the camera is in HiPower,
2438 * so get it here instead of in get_version_information. */
2439 do_command(cam, CPIA_COMMAND_GetVPVersion, 0, 0, 0, 0);
2440
2441 /* set camera to a known state */
2442 set_camera_state(cam);
2443
2444 return 0;
2445 }
2446
2447 /* ------------------------- V4L interface --------------------- */
2448 static int cpia_open(struct video_device *dev, int flags)
2449 {
2450 int i;
2451 struct cam_data *cam = dev->priv;
2452
2453 if (!cam) {
2454 DBG("Internal error, cam_data not found!\n");
2455 return -EBUSY;
2456 }
2457
2458 if (cam->open_count > 0) {
2459 DBG("Camera already open\n");
2460 return -EBUSY;
2461 }
2462
2463 if (!cam->raw_image) {
2464 cam->raw_image = rvmalloc(CPIA_MAX_IMAGE_SIZE);
2465 if (!cam->raw_image)
2466 return -ENOMEM;
2467 }
2468
2469 if (!cam->decompressed_frame.data) {
2470 cam->decompressed_frame.data = rvmalloc(CPIA_MAX_FRAME_SIZE);
2471 if (!cam->decompressed_frame.data) {
2472 rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
2473 cam->raw_image = NULL;
2474 return -ENOMEM;
2475 }
2476 }
2477
2478 /* open cpia */
2479 if (cam->ops->open(cam->lowlevel_data)) {
2480 rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE);
2481 cam->decompressed_frame.data = NULL;
2482 rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
2483 cam->raw_image = NULL;
2484 return -ENODEV;
2485 }
2486
2487 /* reset the camera */
2488 if ((i = reset_camera(cam)) != 0) {
2489 cam->ops->close(cam->lowlevel_data);
2490 rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE);
2491 cam->decompressed_frame.data = NULL;
2492 rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
2493 cam->raw_image = NULL;
2494 return i;
2495 }
2496
2497 /* Set ownership of /proc/cpia/videoX to current user */
2498 if(cam->proc_entry)
2499 cam->proc_entry->uid = current->uid;
2500
2501 /* set mark for loading first frame uncompressed */
2502 cam->first_frame = 1;
2503
2504 /* init it to something */
2505 cam->mmap_kludge = 0;
2506
2507 ++cam->open_count;
2508 return 0;
2509 }
2510
2511 static void cpia_close(struct video_device *dev)
2512 {
2513 struct cam_data *cam;
2514
2515 cam = dev->priv;
2516
2517 if (cam->ops) {
2518 /* Return ownership of /proc/cpia/videoX to root */
2519 if(cam->proc_entry)
2520 cam->proc_entry->uid = 0;
2521
2522 /* save camera state for later open (developers guide ch 3.5.3) */
2523 save_camera_state(cam);
2524
2525 /* GotoLoPower */
2526 goto_low_power(cam);
2527
2528 /* Update the camera ststus */
2529 do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0);
2530
2531 /* cleanup internal state stuff */
2532 free_frames(cam->frame);
2533
2534 /* close cpia */
2535 cam->ops->close(cam->lowlevel_data);
2536 }
2537
2538 if (--cam->open_count == 0) {
2539 /* clean up capture-buffers */
2540 if (cam->raw_image) {
2541 rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
2542 cam->raw_image = NULL;
2543 }
2544
2545 if (cam->decompressed_frame.data) {
2546 rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE);
2547 cam->decompressed_frame.data = NULL;
2548 }
2549
2550 if (cam->frame_buf)
2551 free_frame_buf(cam);
2552
2553 if (!cam->ops) {
2554 video_unregister_device(dev);
2555 kfree(cam);
2556 }
2557 }
2558
2559
2560 return;
2561 }
2562
2563 static long cpia_read(struct video_device *dev, char *buf,
2564 unsigned long count, int noblock)
2565 {
2566 struct cam_data *cam = dev->priv;
2567
2568 /* make this _really_ smp and multithredi-safe */
2569 if (down_interruptible(&cam->busy_lock))
2570 return -EINTR;
2571
2572 if (!buf) {
2573 DBG("buf NULL\n");
2574 up(&cam->busy_lock);
2575 return -EINVAL;
2576 }
2577
2578 if (!count) {
2579 DBG("count 0\n");
2580 up(&cam->busy_lock);
2581 return 0;
2582 }
2583
2584 if (!cam->ops) {
2585 DBG("ops NULL\n");
2586 up(&cam->busy_lock);
2587 return -ENODEV;
2588 }
2589
2590 /* upload frame */
2591 cam->decompressed_frame.state = FRAME_READY;
2592 cam->mmap_kludge=0;
2593 fetch_frame(cam);
2594 if (cam->decompressed_frame.state != FRAME_DONE) {
2595 DBG("upload failed %d/%d\n", cam->decompressed_frame.count,
2596 cam->decompressed_frame.state);
2597 up(&cam->busy_lock);
2598 return -EIO;
2599 }
2600 cam->decompressed_frame.state = FRAME_UNUSED;
2601
2602 /* copy data to user space */
2603 if (cam->decompressed_frame.count > count) {
2604 DBG("count wrong: %d, %lu\n", cam->decompressed_frame.count,
2605 count);
2606 up(&cam->busy_lock);
2607 return -EFAULT;
2608 }
2609 if (copy_to_user(buf, cam->decompressed_frame.data,
2610 cam->decompressed_frame.count)) {
2611 DBG("copy_to_user failed\n");
2612 up(&cam->busy_lock);
2613 return -EFAULT;
2614 }
2615
2616 up(&cam->busy_lock);
2617 return cam->decompressed_frame.count;
2618 }
2619
2620 static int cpia_ioctl(struct video_device *dev, unsigned int ioctlnr, void *arg)
2621 {
2622 struct cam_data *cam = dev->priv;
2623 int retval = 0;
2624
2625 if (!cam || !cam->ops)
2626 return -ENODEV;
2627
2628 /* make this _really_ smp-safe */
2629 if (down_interruptible(&cam->busy_lock))
2630 return -EINTR;
2631
2632 //DBG("cpia_ioctl: %u\n", ioctlnr);
2633
2634 switch (ioctlnr) {
2635 /* query capabilites */
2636 case VIDIOCGCAP:
2637 {
2638 struct video_capability b;
2639
2640 DBG("VIDIOCGCAP\n");
2641 strcpy(b.name, "CPiA Camera");
2642 b.type = VID_TYPE_CAPTURE;
2643 b.channels = 1;
2644 b.audios = 0;
2645 b.maxwidth = 352; /* VIDEOSIZE_CIF */
2646 b.maxheight = 288;
2647 b.minwidth = 48; /* VIDEOSIZE_48_48 */
2648 b.minheight = 48;
2649
2650 if (copy_to_user(arg, &b, sizeof(b)))
2651 retval = -EFAULT;
2652
2653 break;
2654 }
2655
2656 /* get/set video source - we are a camera and nothing else */
2657 case VIDIOCGCHAN:
2658 {
2659 struct video_channel v;
2660
2661 DBG("VIDIOCGCHAN\n");
2662 if (copy_from_user(&v, arg, sizeof(v))) {
2663 retval = -EFAULT;
2664 break;
2665 }
2666 if (v.channel != 0) {
2667 retval = -EINVAL;
2668 break;
2669 }
2670
2671 v.channel = 0;
2672 strcpy(v.name, "Camera");
2673 v.tuners = 0;
2674 v.flags = 0;
2675 v.type = VIDEO_TYPE_CAMERA;
2676 v.norm = 0;
2677
2678 if (copy_to_user(arg, &v, sizeof(v)))
2679 retval = -EFAULT;
2680 break;
2681 }
2682
2683 case VIDIOCSCHAN:
2684 {
2685 int v;
2686
2687 DBG("VIDIOCSCHAN\n");
2688 if (copy_from_user(&v, arg, sizeof(v)))
2689 retval = -EFAULT;
2690
2691 if (retval == 0 && v != 0)
2692 retval = -EINVAL;
2693
2694 break;
2695 }
2696
2697 /* image properties */
2698 case VIDIOCGPICT:
2699 DBG("VIDIOCGPICT\n");
2700 if (copy_to_user(arg, &cam->vp, sizeof(struct video_picture)))
2701 retval = -EFAULT;
2702 break;
2703
2704 case VIDIOCSPICT:
2705 {
2706 struct video_picture vp;
2707
2708 DBG("VIDIOCSPICT\n");
2709
2710 /* copy_from_user */
2711 if (copy_from_user(&vp, arg, sizeof(vp))) {
2712 retval = -EFAULT;
2713 break;
2714 }
2715
2716 /* check validity */
2717 DBG("palette: %d\n", vp.palette);
2718 DBG("depth: %d\n", vp.depth);
2719 if (!valid_mode(vp.palette, vp.depth)) {
2720 retval = -EINVAL;
2721 break;
2722 }
2723
2724 down(&cam->param_lock);
2725 /* brightness, colour, contrast need no check 0-65535 */
2726 memcpy( &cam->vp, &vp, sizeof(vp) );
2727 /* update cam->params.colourParams */
2728 cam->params.colourParams.brightness = vp.brightness*100/65535;
2729 cam->params.colourParams.contrast = vp.contrast*100/65535;
2730 cam->params.colourParams.saturation = vp.colour*100/65535;
2731 /* contrast is in steps of 8, so round */
2732 cam->params.colourParams.contrast =
2733 ((cam->params.colourParams.contrast + 3) / 8) * 8;
2734 if (cam->params.version.firmwareVersion == 1 &&
2735 cam->params.version.firmwareRevision == 2 &&
2736 cam->params.colourParams.contrast > 80) {
2737 /* 1-02 firmware limits contrast to 80 */
2738 cam->params.colourParams.contrast = 80;
2739 }
2740
2741 /* queue command to update camera */
2742 cam->cmd_queue |= COMMAND_SETCOLOURPARAMS;
2743 up(&cam->param_lock);
2744 DBG("VIDIOCSPICT: %d / %d // %d / %d / %d / %d\n",
2745 vp.depth, vp.palette, vp.brightness, vp.hue, vp.colour,
2746 vp.contrast);
2747 break;
2748 }
2749
2750 /* get/set capture window */
2751 case VIDIOCGWIN:
2752 DBG("VIDIOCGWIN\n");
2753
2754 if (copy_to_user(arg, &cam->vw, sizeof(struct video_window)))
2755 retval = -EFAULT;
2756 break;
2757
2758 case VIDIOCSWIN:
2759 {
2760 /* copy_from_user, check validity, copy to internal structure */
2761 struct video_window vw;
2762 DBG("VIDIOCSWIN\n");
2763 if (copy_from_user(&vw, arg, sizeof(vw))) {
2764 retval = -EFAULT;
2765 break;
2766 }
2767
2768 if (vw.clipcount != 0) { /* clipping not supported */
2769 retval = -EINVAL;
2770 break;
2771 }
2772 if (vw.clips != NULL) { /* clipping not supported */
2773 retval = -EINVAL;
2774 break;
2775 }
2776
2777 /* we set the video window to something smaller or equal to what
2778 * is requested by the user???
2779 */
2780 down(&cam->param_lock);
2781 if (vw.width != cam->vw.width || vw.height != cam->vw.height) {
2782 int video_size = match_videosize(vw.width, vw.height);
2783
2784 if (video_size < 0) {
2785 retval = -EINVAL;
2786 up(&cam->param_lock);
2787 break;
2788 }
2789 cam->video_size = video_size;
2790 set_vw_size(cam);
2791 DBG("%d / %d\n", cam->vw.width, cam->vw.height);
2792 cam->cmd_queue |= COMMAND_SETFORMAT;
2793 }
2794
2795 // FIXME needed??? memcpy(&cam->vw, &vw, sizeof(vw));
2796 up(&cam->param_lock);
2797
2798 /* setformat ignored by camera during streaming,
2799 * so stop/dispatch/start */
2800 if (cam->cmd_queue & COMMAND_SETFORMAT) {
2801 DBG("\n");
2802 dispatch_commands(cam);
2803 }
2804 DBG("%d/%d:%d\n", cam->video_size,
2805 cam->vw.width, cam->vw.height);
2806 break;
2807 }
2808
2809 /* mmap interface */
2810 case VIDIOCGMBUF:
2811 {
2812 struct video_mbuf vm;
2813 int i;
2814
2815 DBG("VIDIOCGMBUF\n");
2816 memset(&vm, 0, sizeof(vm));
2817 vm.size = CPIA_MAX_FRAME_SIZE*FRAME_NUM;
2818 vm.frames = FRAME_NUM;
2819 for (i = 0; i < FRAME_NUM; i++)
2820 vm.offsets[i] = CPIA_MAX_FRAME_SIZE * i;
2821
2822 if (copy_to_user((void *)arg, (void *)&vm, sizeof(vm)))
2823 retval = -EFAULT;
2824
2825 break;
2826 }
2827
2828 case VIDIOCMCAPTURE:
2829 {
2830 struct video_mmap vm;
2831 int video_size;
2832
2833 if (copy_from_user((void *)&vm, (void *)arg, sizeof(vm))) {
2834 retval = -EFAULT;
2835 break;
2836 }
2837 #if 1
2838 DBG("VIDIOCMCAPTURE: %d / %d / %dx%d\n", vm.format, vm.frame,
2839 vm.width, vm.height);
2840 #endif
2841 if (vm.frame<0||vm.frame>=FRAME_NUM) {
2842 retval = -EINVAL;
2843 break;
2844 }
2845
2846 /* set video format */
2847 cam->vp.palette = vm.format;
2848 switch(vm.format) {
2849 case VIDEO_PALETTE_GREY:
2850 case VIDEO_PALETTE_RGB555:
2851 case VIDEO_PALETTE_RGB565:
2852 case VIDEO_PALETTE_YUV422:
2853 case VIDEO_PALETTE_YUYV:
2854 case VIDEO_PALETTE_UYVY:
2855 cam->vp.depth = 16;
2856 break;
2857 case VIDEO_PALETTE_RGB24:
2858 cam->vp.depth = 24;
2859 break;
2860 case VIDEO_PALETTE_RGB32:
2861 cam->vp.depth = 32;
2862 break;
2863 default:
2864 retval = -EINVAL;
2865 break;
2866 }
2867 if (retval)
2868 break;
2869
2870 /* set video size */
2871 video_size = match_videosize(vm.width, vm.height);
2872 if (cam->video_size < 0) {
2873 retval = -EINVAL;
2874 break;
2875 }
2876 if (video_size != cam->video_size) {
2877 cam->video_size = video_size;
2878 set_vw_size(cam);
2879 cam->cmd_queue |= COMMAND_SETFORMAT;
2880 dispatch_commands(cam);
2881 }
2882 #if 0
2883 DBG("VIDIOCMCAPTURE: %d / %d/%d\n", cam->video_size,
2884 cam->vw.width, cam->vw.height);
2885 #endif
2886 /* according to v4l-spec we must start streaming here */
2887 cam->mmap_kludge = 1;
2888 retval = capture_frame(cam, &vm);
2889
2890 break;
2891 }
2892
2893 case VIDIOCSYNC:
2894 {
2895 int frame;
2896
2897 if (copy_from_user((void *)&frame, arg, sizeof(int))) {
2898 retval = -EFAULT;
2899 break;
2900 }
2901 //DBG("VIDIOCSYNC: %d\n", frame);
2902
2903 if (frame<0 || frame >= FRAME_NUM) {
2904 retval = -EINVAL;
2905 break;
2906 }
2907
2908 switch (cam->frame[frame].state) {
2909 case FRAME_UNUSED:
2910 case FRAME_READY:
2911 case FRAME_GRABBING:
2912 DBG("sync to unused frame %d\n", frame);
2913 retval = -EINVAL;
2914 break;
2915
2916 case FRAME_DONE:
2917 cam->frame[frame].state = FRAME_UNUSED;
2918 //DBG("VIDIOCSYNC: %d synced\n", frame);
2919 break;
2920 }
2921 if (retval == -EINTR) {
2922 /* FIXME - xawtv does not handle this nice */
2923 retval = 0;
2924 }
2925 break;
2926 }
2927
2928 /* pointless to implement overlay with this camera */
2929 case VIDIOCCAPTURE:
2930 retval = -EINVAL;
2931 break;
2932 case VIDIOCGFBUF:
2933 retval = -EINVAL;
2934 break;
2935 case VIDIOCSFBUF:
2936 retval = -EINVAL;
2937 break;
2938 case VIDIOCKEY:
2939 retval = -EINVAL;
2940 break;
2941
2942 /* tuner interface - we have none */
2943 case VIDIOCGTUNER:
2944 retval = -EINVAL;
2945 break;
2946 case VIDIOCSTUNER:
2947 retval = -EINVAL;
2948 break;
2949 case VIDIOCGFREQ:
2950 retval = -EINVAL;
2951 break;
2952 case VIDIOCSFREQ:
2953 retval = -EINVAL;
2954 break;