initial commit with v2.6.9
[linux-2.6.9-moxart.git] / drivers / media / video / cpia.c
blob21db4b39027700ec829f1e4ec3dc72fe738c2f36
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 <johannes@erdfelt.com>
9 * (C) Copyright 2000 STMicroelectronics
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 /* define _CPIA_DEBUG_ for verbose debug output (see cpia.h) */
27 /* #define _CPIA_DEBUG_ 1 */
29 #include <linux/config.h>
31 #include <linux/module.h>
32 #include <linux/moduleparam.h>
33 #include <linux/init.h>
34 #include <linux/fs.h>
35 #include <linux/vmalloc.h>
36 #include <linux/slab.h>
37 #include <linux/proc_fs.h>
38 #include <linux/ctype.h>
39 #include <linux/pagemap.h>
40 #include <asm/io.h>
41 #include <asm/semaphore.h>
43 #ifdef CONFIG_KMOD
44 #include <linux/kmod.h>
45 #endif
47 #include "cpia.h"
49 #ifdef CONFIG_VIDEO_CPIA_PP
50 extern int cpia_pp_init(void);
51 #endif
52 #ifdef CONFIG_VIDEO_CPIA_USB
53 extern int cpia_usb_init(void);
54 #endif
56 static int video_nr = -1;
58 #ifdef MODULE
59 MODULE_PARM(video_nr,"i");
60 MODULE_AUTHOR("Scott J. Bertin <sbertin@securenym.net> & Peter Pregler <Peter_Pregler@email.com> & Johannes Erdfelt <johannes@erdfeld.com>");
61 MODULE_DESCRIPTION("V4L-driver for Vision CPiA based cameras");
62 MODULE_LICENSE("GPL");
63 MODULE_SUPPORTED_DEVICE("video");
64 #endif
66 static unsigned short colorspace_conv = 0;
67 module_param(colorspace_conv, ushort, 0444);
68 MODULE_PARM_DESC(colorspace_conv,
69 "\n<n> Colorspace conversion:"
70 "\n0 = disable"
71 "\n1 = enable"
72 "\nDefault value is 0"
73 "\n");
75 #define ABOUT "V4L-Driver for Vision CPiA based cameras"
77 #ifndef VID_HARDWARE_CPIA
78 #define VID_HARDWARE_CPIA 24 /* FIXME -> from linux/videodev.h */
79 #endif
81 #define CPIA_MODULE_CPIA (0<<5)
82 #define CPIA_MODULE_SYSTEM (1<<5)
83 #define CPIA_MODULE_VP_CTRL (5<<5)
84 #define CPIA_MODULE_CAPTURE (6<<5)
85 #define CPIA_MODULE_DEBUG (7<<5)
87 #define INPUT (DATA_IN << 8)
88 #define OUTPUT (DATA_OUT << 8)
90 #define CPIA_COMMAND_GetCPIAVersion (INPUT | CPIA_MODULE_CPIA | 1)
91 #define CPIA_COMMAND_GetPnPID (INPUT | CPIA_MODULE_CPIA | 2)
92 #define CPIA_COMMAND_GetCameraStatus (INPUT | CPIA_MODULE_CPIA | 3)
93 #define CPIA_COMMAND_GotoHiPower (OUTPUT | CPIA_MODULE_CPIA | 4)
94 #define CPIA_COMMAND_GotoLoPower (OUTPUT | CPIA_MODULE_CPIA | 5)
95 #define CPIA_COMMAND_GotoSuspend (OUTPUT | CPIA_MODULE_CPIA | 7)
96 #define CPIA_COMMAND_GotoPassThrough (OUTPUT | CPIA_MODULE_CPIA | 8)
97 #define CPIA_COMMAND_ModifyCameraStatus (OUTPUT | CPIA_MODULE_CPIA | 10)
99 #define CPIA_COMMAND_ReadVCRegs (INPUT | CPIA_MODULE_SYSTEM | 1)
100 #define CPIA_COMMAND_WriteVCReg (OUTPUT | CPIA_MODULE_SYSTEM | 2)
101 #define CPIA_COMMAND_ReadMCPorts (INPUT | CPIA_MODULE_SYSTEM | 3)
102 #define CPIA_COMMAND_WriteMCPort (OUTPUT | CPIA_MODULE_SYSTEM | 4)
103 #define CPIA_COMMAND_SetBaudRate (OUTPUT | CPIA_MODULE_SYSTEM | 5)
104 #define CPIA_COMMAND_SetECPTiming (OUTPUT | CPIA_MODULE_SYSTEM | 6)
105 #define CPIA_COMMAND_ReadIDATA (INPUT | CPIA_MODULE_SYSTEM | 7)
106 #define CPIA_COMMAND_WriteIDATA (OUTPUT | CPIA_MODULE_SYSTEM | 8)
107 #define CPIA_COMMAND_GenericCall (OUTPUT | CPIA_MODULE_SYSTEM | 9)
108 #define CPIA_COMMAND_I2CStart (OUTPUT | CPIA_MODULE_SYSTEM | 10)
109 #define CPIA_COMMAND_I2CStop (OUTPUT | CPIA_MODULE_SYSTEM | 11)
110 #define CPIA_COMMAND_I2CWrite (OUTPUT | CPIA_MODULE_SYSTEM | 12)
111 #define CPIA_COMMAND_I2CRead (INPUT | CPIA_MODULE_SYSTEM | 13)
113 #define CPIA_COMMAND_GetVPVersion (INPUT | CPIA_MODULE_VP_CTRL | 1)
114 #define CPIA_COMMAND_ResetFrameCounter (INPUT | CPIA_MODULE_VP_CTRL | 2)
115 #define CPIA_COMMAND_SetColourParams (OUTPUT | CPIA_MODULE_VP_CTRL | 3)
116 #define CPIA_COMMAND_SetExposure (OUTPUT | CPIA_MODULE_VP_CTRL | 4)
117 #define CPIA_COMMAND_SetColourBalance (OUTPUT | CPIA_MODULE_VP_CTRL | 6)
118 #define CPIA_COMMAND_SetSensorFPS (OUTPUT | CPIA_MODULE_VP_CTRL | 7)
119 #define CPIA_COMMAND_SetVPDefaults (OUTPUT | CPIA_MODULE_VP_CTRL | 8)
120 #define CPIA_COMMAND_SetApcor (OUTPUT | CPIA_MODULE_VP_CTRL | 9)
121 #define CPIA_COMMAND_SetFlickerCtrl (OUTPUT | CPIA_MODULE_VP_CTRL | 10)
122 #define CPIA_COMMAND_SetVLOffset (OUTPUT | CPIA_MODULE_VP_CTRL | 11)
123 #define CPIA_COMMAND_GetColourParams (INPUT | CPIA_MODULE_VP_CTRL | 16)
124 #define CPIA_COMMAND_GetColourBalance (INPUT | CPIA_MODULE_VP_CTRL | 17)
125 #define CPIA_COMMAND_GetExposure (INPUT | CPIA_MODULE_VP_CTRL | 18)
126 #define CPIA_COMMAND_SetSensorMatrix (OUTPUT | CPIA_MODULE_VP_CTRL | 19)
127 #define CPIA_COMMAND_ColourBars (OUTPUT | CPIA_MODULE_VP_CTRL | 25)
128 #define CPIA_COMMAND_ReadVPRegs (INPUT | CPIA_MODULE_VP_CTRL | 30)
129 #define CPIA_COMMAND_WriteVPReg (OUTPUT | CPIA_MODULE_VP_CTRL | 31)
131 #define CPIA_COMMAND_GrabFrame (OUTPUT | CPIA_MODULE_CAPTURE | 1)
132 #define CPIA_COMMAND_UploadFrame (OUTPUT | CPIA_MODULE_CAPTURE | 2)
133 #define CPIA_COMMAND_SetGrabMode (OUTPUT | CPIA_MODULE_CAPTURE | 3)
134 #define CPIA_COMMAND_InitStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 4)
135 #define CPIA_COMMAND_FiniStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 5)
136 #define CPIA_COMMAND_StartStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 6)
137 #define CPIA_COMMAND_EndStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 7)
138 #define CPIA_COMMAND_SetFormat (OUTPUT | CPIA_MODULE_CAPTURE | 8)
139 #define CPIA_COMMAND_SetROI (OUTPUT | CPIA_MODULE_CAPTURE | 9)
140 #define CPIA_COMMAND_SetCompression (OUTPUT | CPIA_MODULE_CAPTURE | 10)
141 #define CPIA_COMMAND_SetCompressionTarget (OUTPUT | CPIA_MODULE_CAPTURE | 11)
142 #define CPIA_COMMAND_SetYUVThresh (OUTPUT | CPIA_MODULE_CAPTURE | 12)
143 #define CPIA_COMMAND_SetCompressionParams (OUTPUT | CPIA_MODULE_CAPTURE | 13)
144 #define CPIA_COMMAND_DiscardFrame (OUTPUT | CPIA_MODULE_CAPTURE | 14)
145 #define CPIA_COMMAND_GrabReset (OUTPUT | CPIA_MODULE_CAPTURE | 15)
147 #define CPIA_COMMAND_OutputRS232 (OUTPUT | CPIA_MODULE_DEBUG | 1)
148 #define CPIA_COMMAND_AbortProcess (OUTPUT | CPIA_MODULE_DEBUG | 4)
149 #define CPIA_COMMAND_SetDramPage (OUTPUT | CPIA_MODULE_DEBUG | 5)
150 #define CPIA_COMMAND_StartDramUpload (OUTPUT | CPIA_MODULE_DEBUG | 6)
151 #define CPIA_COMMAND_StartDummyDtream (OUTPUT | CPIA_MODULE_DEBUG | 8)
152 #define CPIA_COMMAND_AbortStream (OUTPUT | CPIA_MODULE_DEBUG | 9)
153 #define CPIA_COMMAND_DownloadDRAM (OUTPUT | CPIA_MODULE_DEBUG | 10)
154 #define CPIA_COMMAND_Null (OUTPUT | CPIA_MODULE_DEBUG | 11)
156 enum {
157 FRAME_READY, /* Ready to grab into */
158 FRAME_GRABBING, /* In the process of being grabbed into */
159 FRAME_DONE, /* Finished grabbing, but not been synced yet */
160 FRAME_UNUSED, /* Unused (no MCAPTURE) */
163 #define COMMAND_NONE 0x0000
164 #define COMMAND_SETCOMPRESSION 0x0001
165 #define COMMAND_SETCOMPRESSIONTARGET 0x0002
166 #define COMMAND_SETCOLOURPARAMS 0x0004
167 #define COMMAND_SETFORMAT 0x0008
168 #define COMMAND_PAUSE 0x0010
169 #define COMMAND_RESUME 0x0020
170 #define COMMAND_SETYUVTHRESH 0x0040
171 #define COMMAND_SETECPTIMING 0x0080
172 #define COMMAND_SETCOMPRESSIONPARAMS 0x0100
173 #define COMMAND_SETEXPOSURE 0x0200
174 #define COMMAND_SETCOLOURBALANCE 0x0400
175 #define COMMAND_SETSENSORFPS 0x0800
176 #define COMMAND_SETAPCOR 0x1000
177 #define COMMAND_SETFLICKERCTRL 0x2000
178 #define COMMAND_SETVLOFFSET 0x4000
179 #define COMMAND_SETLIGHTS 0x8000
181 #define ROUND_UP_EXP_FOR_FLICKER 15
183 /* Constants for automatic frame rate adjustment */
184 #define MAX_EXP 302
185 #define MAX_EXP_102 255
186 #define LOW_EXP 140
187 #define VERY_LOW_EXP 70
188 #define TC 94
189 #define EXP_ACC_DARK 50
190 #define EXP_ACC_LIGHT 90
191 #define HIGH_COMP_102 160
192 #define MAX_COMP 239
193 #define DARK_TIME 3
194 #define LIGHT_TIME 3
196 /* Maximum number of 10ms loops to wait for the stream to become ready */
197 #define READY_TIMEOUT 100
199 /* Developer's Guide Table 5 p 3-34
200 * indexed by [mains][sensorFps.baserate][sensorFps.divisor]*/
201 static u8 flicker_jumps[2][2][4] =
202 { { { 76, 38, 19, 9 }, { 92, 46, 23, 11 } },
203 { { 64, 32, 16, 8 }, { 76, 38, 19, 9} }
206 /* forward declaration of local function */
207 static void reset_camera_struct(struct cam_data *cam);
208 static int find_over_exposure(int brightness);
209 static void set_flicker(struct cam_params *params, volatile u32 *command_flags,
210 int on);
213 /**********************************************************************
215 * Memory management
217 **********************************************************************/
219 /* Here we want the physical address of the memory.
220 * This is used when initializing the contents of the area.
222 static inline unsigned long kvirt_to_pa(unsigned long adr)
224 unsigned long kva, ret;
226 kva = (unsigned long) page_address(vmalloc_to_page((void *)adr));
227 kva |= adr & (PAGE_SIZE-1); /* restore the offset */
228 ret = __pa(kva);
229 return ret;
232 static void *rvmalloc(unsigned long size)
234 void *mem;
235 unsigned long adr;
237 size = PAGE_ALIGN(size);
238 mem = vmalloc_32(size);
239 if (!mem)
240 return NULL;
242 memset(mem, 0, size); /* Clear the ram out, no junk to the user */
243 adr = (unsigned long) mem;
244 while (size > 0) {
245 SetPageReserved(vmalloc_to_page((void *)adr));
246 adr += PAGE_SIZE;
247 size -= PAGE_SIZE;
250 return mem;
253 static void rvfree(void *mem, unsigned long size)
255 unsigned long adr;
257 if (!mem)
258 return;
260 adr = (unsigned long) mem;
261 while ((long) size > 0) {
262 ClearPageReserved(vmalloc_to_page((void *)adr));
263 adr += PAGE_SIZE;
264 size -= PAGE_SIZE;
266 vfree(mem);
269 /**********************************************************************
271 * /proc interface
273 **********************************************************************/
274 #ifdef CONFIG_PROC_FS
275 static struct proc_dir_entry *cpia_proc_root=NULL;
277 static int cpia_read_proc(char *page, char **start, off_t off,
278 int count, int *eof, void *data)
280 char *out = page;
281 int len, tmp;
282 struct cam_data *cam = data;
283 char tmpstr[29];
285 /* IMPORTANT: This output MUST be kept under PAGE_SIZE
286 * or we need to get more sophisticated. */
288 out += sprintf(out, "read-only\n-----------------------\n");
289 out += sprintf(out, "V4L Driver version: %d.%d.%d\n",
290 CPIA_MAJ_VER, CPIA_MIN_VER, CPIA_PATCH_VER);
291 out += sprintf(out, "CPIA Version: %d.%02d (%d.%d)\n",
292 cam->params.version.firmwareVersion,
293 cam->params.version.firmwareRevision,
294 cam->params.version.vcVersion,
295 cam->params.version.vcRevision);
296 out += sprintf(out, "CPIA PnP-ID: %04x:%04x:%04x\n",
297 cam->params.pnpID.vendor, cam->params.pnpID.product,
298 cam->params.pnpID.deviceRevision);
299 out += sprintf(out, "VP-Version: %d.%d %04x\n",
300 cam->params.vpVersion.vpVersion,
301 cam->params.vpVersion.vpRevision,
302 cam->params.vpVersion.cameraHeadID);
304 out += sprintf(out, "system_state: %#04x\n",
305 cam->params.status.systemState);
306 out += sprintf(out, "grab_state: %#04x\n",
307 cam->params.status.grabState);
308 out += sprintf(out, "stream_state: %#04x\n",
309 cam->params.status.streamState);
310 out += sprintf(out, "fatal_error: %#04x\n",
311 cam->params.status.fatalError);
312 out += sprintf(out, "cmd_error: %#04x\n",
313 cam->params.status.cmdError);
314 out += sprintf(out, "debug_flags: %#04x\n",
315 cam->params.status.debugFlags);
316 out += sprintf(out, "vp_status: %#04x\n",
317 cam->params.status.vpStatus);
318 out += sprintf(out, "error_code: %#04x\n",
319 cam->params.status.errorCode);
320 /* QX3 specific entries */
321 if (cam->params.qx3.qx3_detected) {
322 out += sprintf(out, "button: %4d\n",
323 cam->params.qx3.button);
324 out += sprintf(out, "cradled: %4d\n",
325 cam->params.qx3.cradled);
327 out += sprintf(out, "video_size: %s\n",
328 cam->params.format.videoSize == VIDEOSIZE_CIF ?
329 "CIF " : "QCIF");
330 out += sprintf(out, "roi: (%3d, %3d) to (%3d, %3d)\n",
331 cam->params.roi.colStart*8,
332 cam->params.roi.rowStart*4,
333 cam->params.roi.colEnd*8,
334 cam->params.roi.rowEnd*4);
335 out += sprintf(out, "actual_fps: %3d\n", cam->fps);
336 out += sprintf(out, "transfer_rate: %4dkB/s\n",
337 cam->transfer_rate);
339 out += sprintf(out, "\nread-write\n");
340 out += sprintf(out, "----------------------- current min"
341 " max default comment\n");
342 out += sprintf(out, "brightness: %8d %8d %8d %8d\n",
343 cam->params.colourParams.brightness, 0, 100, 50);
344 if (cam->params.version.firmwareVersion == 1 &&
345 cam->params.version.firmwareRevision == 2)
346 /* 1-02 firmware limits contrast to 80 */
347 tmp = 80;
348 else
349 tmp = 96;
351 out += sprintf(out, "contrast: %8d %8d %8d %8d"
352 " steps of 8\n",
353 cam->params.colourParams.contrast, 0, tmp, 48);
354 out += sprintf(out, "saturation: %8d %8d %8d %8d\n",
355 cam->params.colourParams.saturation, 0, 100, 50);
356 tmp = (25000+5000*cam->params.sensorFps.baserate)/
357 (1<<cam->params.sensorFps.divisor);
358 out += sprintf(out, "sensor_fps: %4d.%03d %8d %8d %8d\n",
359 tmp/1000, tmp%1000, 3, 30, 15);
360 out += sprintf(out, "stream_start_line: %8d %8d %8d %8d\n",
361 2*cam->params.streamStartLine, 0,
362 cam->params.format.videoSize == VIDEOSIZE_CIF ? 288:144,
363 cam->params.format.videoSize == VIDEOSIZE_CIF ? 240:120);
364 out += sprintf(out, "sub_sample: %8s %8s %8s %8s\n",
365 cam->params.format.subSample == SUBSAMPLE_420 ?
366 "420" : "422", "420", "422", "422");
367 out += sprintf(out, "yuv_order: %8s %8s %8s %8s\n",
368 cam->params.format.yuvOrder == YUVORDER_YUYV ?
369 "YUYV" : "UYVY", "YUYV" , "UYVY", "YUYV");
370 out += sprintf(out, "ecp_timing: %8s %8s %8s %8s\n",
371 cam->params.ecpTiming ? "slow" : "normal", "slow",
372 "normal", "normal");
374 if (cam->params.colourBalance.balanceMode == 2) {
375 sprintf(tmpstr, "auto");
376 } else {
377 sprintf(tmpstr, "manual");
379 out += sprintf(out, "color_balance_mode: %8s %8s %8s"
380 " %8s\n", tmpstr, "manual", "auto", "auto");
381 out += sprintf(out, "red_gain: %8d %8d %8d %8d\n",
382 cam->params.colourBalance.redGain, 0, 212, 32);
383 out += sprintf(out, "green_gain: %8d %8d %8d %8d\n",
384 cam->params.colourBalance.greenGain, 0, 212, 6);
385 out += sprintf(out, "blue_gain: %8d %8d %8d %8d\n",
386 cam->params.colourBalance.blueGain, 0, 212, 92);
388 if (cam->params.version.firmwareVersion == 1 &&
389 cam->params.version.firmwareRevision == 2)
390 /* 1-02 firmware limits gain to 2 */
391 sprintf(tmpstr, "%8d %8d %8d", 1, 2, 2);
392 else
393 sprintf(tmpstr, "%8d %8d %8d", 1, 8, 2);
395 if (cam->params.exposure.gainMode == 0)
396 out += sprintf(out, "max_gain: unknown %28s"
397 " powers of 2\n", tmpstr);
398 else
399 out += sprintf(out, "max_gain: %8d %28s"
400 " 1,2,4 or 8 \n",
401 1<<(cam->params.exposure.gainMode-1), tmpstr);
403 switch(cam->params.exposure.expMode) {
404 case 1:
405 case 3:
406 sprintf(tmpstr, "manual");
407 break;
408 case 2:
409 sprintf(tmpstr, "auto");
410 break;
411 default:
412 sprintf(tmpstr, "unknown");
413 break;
415 out += sprintf(out, "exposure_mode: %8s %8s %8s"
416 " %8s\n", tmpstr, "manual", "auto", "auto");
417 out += sprintf(out, "centre_weight: %8s %8s %8s %8s\n",
418 (2-cam->params.exposure.centreWeight) ? "on" : "off",
419 "off", "on", "on");
420 out += sprintf(out, "gain: %8d %8d max_gain %8d 1,2,4,8 possible\n",
421 1<<cam->params.exposure.gain, 1, 1);
422 if (cam->params.version.firmwareVersion == 1 &&
423 cam->params.version.firmwareRevision == 2)
424 /* 1-02 firmware limits fineExp/2 to 127 */
425 tmp = 254;
426 else
427 tmp = 510;
429 out += sprintf(out, "fine_exp: %8d %8d %8d %8d\n",
430 cam->params.exposure.fineExp*2, 0, tmp, 0);
431 if (cam->params.version.firmwareVersion == 1 &&
432 cam->params.version.firmwareRevision == 2)
433 /* 1-02 firmware limits coarseExpHi to 0 */
434 tmp = MAX_EXP_102;
435 else
436 tmp = MAX_EXP;
438 out += sprintf(out, "coarse_exp: %8d %8d %8d"
439 " %8d\n", cam->params.exposure.coarseExpLo+
440 256*cam->params.exposure.coarseExpHi, 0, tmp, 185);
441 out += sprintf(out, "red_comp: %8d %8d %8d %8d\n",
442 cam->params.exposure.redComp, COMP_RED, 255, COMP_RED);
443 out += sprintf(out, "green1_comp: %8d %8d %8d %8d\n",
444 cam->params.exposure.green1Comp, COMP_GREEN1, 255,
445 COMP_GREEN1);
446 out += sprintf(out, "green2_comp: %8d %8d %8d %8d\n",
447 cam->params.exposure.green2Comp, COMP_GREEN2, 255,
448 COMP_GREEN2);
449 out += sprintf(out, "blue_comp: %8d %8d %8d %8d\n",
450 cam->params.exposure.blueComp, COMP_BLUE, 255, COMP_BLUE);
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 if(cam->params.flickerControl.allowableOverExposure < 0)
475 out += sprintf(out, "allowable_overexposure: %4dauto auto %8d auto\n",
476 -cam->params.flickerControl.allowableOverExposure,
477 255);
478 else
479 out += sprintf(out, "allowable_overexposure: %8d auto %8d auto\n",
480 cam->params.flickerControl.allowableOverExposure,
481 255);
482 out += sprintf(out, "compression_mode: ");
483 switch(cam->params.compression.mode) {
484 case CPIA_COMPRESSION_NONE:
485 out += sprintf(out, "%8s", "none");
486 break;
487 case CPIA_COMPRESSION_AUTO:
488 out += sprintf(out, "%8s", "auto");
489 break;
490 case CPIA_COMPRESSION_MANUAL:
491 out += sprintf(out, "%8s", "manual");
492 break;
493 default:
494 out += sprintf(out, "%8s", "unknown");
495 break;
497 out += sprintf(out, " none,auto,manual auto\n");
498 out += sprintf(out, "decimation_enable: %8s %8s %8s %8s\n",
499 cam->params.compression.decimation ==
500 DECIMATION_ENAB ? "on":"off", "off", "on",
501 "off");
502 out += sprintf(out, "compression_target: %9s %9s %9s %9s\n",
503 cam->params.compressionTarget.frTargeting ==
504 CPIA_COMPRESSION_TARGET_FRAMERATE ?
505 "framerate":"quality",
506 "framerate", "quality", "quality");
507 out += sprintf(out, "target_framerate: %8d %8d %8d %8d\n",
508 cam->params.compressionTarget.targetFR, 1, 30, 15);
509 out += sprintf(out, "target_quality: %8d %8d %8d %8d\n",
510 cam->params.compressionTarget.targetQ, 1, 64, 5);
511 out += sprintf(out, "y_threshold: %8d %8d %8d %8d\n",
512 cam->params.yuvThreshold.yThreshold, 0, 31, 6);
513 out += sprintf(out, "uv_threshold: %8d %8d %8d %8d\n",
514 cam->params.yuvThreshold.uvThreshold, 0, 31, 6);
515 out += sprintf(out, "hysteresis: %8d %8d %8d %8d\n",
516 cam->params.compressionParams.hysteresis, 0, 255, 3);
517 out += sprintf(out, "threshold_max: %8d %8d %8d %8d\n",
518 cam->params.compressionParams.threshMax, 0, 255, 11);
519 out += sprintf(out, "small_step: %8d %8d %8d %8d\n",
520 cam->params.compressionParams.smallStep, 0, 255, 1);
521 out += sprintf(out, "large_step: %8d %8d %8d %8d\n",
522 cam->params.compressionParams.largeStep, 0, 255, 3);
523 out += sprintf(out, "decimation_hysteresis: %8d %8d %8d %8d\n",
524 cam->params.compressionParams.decimationHysteresis,
525 0, 255, 2);
526 out += sprintf(out, "fr_diff_step_thresh: %8d %8d %8d %8d\n",
527 cam->params.compressionParams.frDiffStepThresh,
528 0, 255, 5);
529 out += sprintf(out, "q_diff_step_thresh: %8d %8d %8d %8d\n",
530 cam->params.compressionParams.qDiffStepThresh,
531 0, 255, 3);
532 out += sprintf(out, "decimation_thresh_mod: %8d %8d %8d %8d\n",
533 cam->params.compressionParams.decimationThreshMod,
534 0, 255, 2);
535 /* QX3 specific entries */
536 if (cam->params.qx3.qx3_detected) {
537 out += sprintf(out, "toplight: %8s %8s %8s %8s\n",
538 cam->params.qx3.toplight ? "on" : "off",
539 "off", "on", "off");
540 out += sprintf(out, "bottomlight: %8s %8s %8s %8s\n",
541 cam->params.qx3.bottomlight ? "on" : "off",
542 "off", "on", "off");
545 len = out - page;
546 len -= off;
547 if (len < count) {
548 *eof = 1;
549 if (len <= 0) return 0;
550 } else
551 len = count;
553 *start = page + off;
554 return len;
558 static int match(char *checkstr, char **buffer, unsigned long *count,
559 int *find_colon, int *err)
561 int ret, colon_found = 1;
562 int len = strlen(checkstr);
563 ret = (len <= *count && strncmp(*buffer, checkstr, len) == 0);
564 if (ret) {
565 *buffer += len;
566 *count -= len;
567 if (*find_colon) {
568 colon_found = 0;
569 while (*count && (**buffer == ' ' || **buffer == '\t' ||
570 (!colon_found && **buffer == ':'))) {
571 if (**buffer == ':')
572 colon_found = 1;
573 --*count;
574 ++*buffer;
576 if (!*count || !colon_found)
577 *err = -EINVAL;
578 *find_colon = 0;
581 return ret;
584 static unsigned long int value(char **buffer, unsigned long *count, int *err)
586 char *p;
587 unsigned long int ret;
588 ret = simple_strtoul(*buffer, &p, 0);
589 if (p == *buffer)
590 *err = -EINVAL;
591 else {
592 *count -= p - *buffer;
593 *buffer = p;
595 return ret;
598 static int cpia_write_proc(struct file *file, const char __user *buf,
599 unsigned long count, void *data)
601 struct cam_data *cam = data;
602 struct cam_params new_params;
603 char *page, *buffer;
604 int retval, find_colon;
605 int size = count;
606 unsigned long val = 0;
607 u32 command_flags = 0;
608 u8 new_mains;
611 * This code to copy from buf to page is shamelessly copied
612 * from the comx driver
614 if (count > PAGE_SIZE) {
615 printk(KERN_ERR "count is %lu > %d!!!\n", count, (int)PAGE_SIZE);
616 return -ENOSPC;
619 if (!(page = (char *)__get_free_page(GFP_KERNEL))) return -ENOMEM;
621 if(copy_from_user(page, buf, count))
623 retval = -EFAULT;
624 goto out;
627 if (page[count-1] == '\n')
628 page[count-1] = '\0';
629 else if (count < PAGE_SIZE)
630 page[count] = '\0';
631 else if (page[count]) {
632 retval = -EINVAL;
633 goto out;
636 buffer = page;
638 if (down_interruptible(&cam->param_lock))
639 return -ERESTARTSYS;
642 * Skip over leading whitespace
644 while (count && isspace(*buffer)) {
645 --count;
646 ++buffer;
649 memcpy(&new_params, &cam->params, sizeof(struct cam_params));
650 new_mains = cam->mainsFreq;
652 #define MATCH(x) (match(x, &buffer, &count, &find_colon, &retval))
653 #define VALUE (value(&buffer,&count, &retval))
654 #define FIRMWARE_VERSION(x,y) (new_params.version.firmwareVersion == (x) && \
655 new_params.version.firmwareRevision == (y))
657 retval = 0;
658 while (count && !retval) {
659 find_colon = 1;
660 if (MATCH("brightness")) {
661 if (!retval)
662 val = VALUE;
664 if (!retval) {
665 if (val <= 100)
666 new_params.colourParams.brightness = val;
667 else
668 retval = -EINVAL;
670 command_flags |= COMMAND_SETCOLOURPARAMS;
671 if(new_params.flickerControl.allowableOverExposure < 0)
672 new_params.flickerControl.allowableOverExposure =
673 -find_over_exposure(new_params.colourParams.brightness);
674 if(new_params.flickerControl.flickerMode != 0)
675 command_flags |= COMMAND_SETFLICKERCTRL;
677 } else if (MATCH("contrast")) {
678 if (!retval)
679 val = VALUE;
681 if (!retval) {
682 if (val <= 100) {
683 /* contrast is in steps of 8, so round*/
684 val = ((val + 3) / 8) * 8;
685 /* 1-02 firmware limits contrast to 80*/
686 if (FIRMWARE_VERSION(1,2) && val > 80)
687 val = 80;
689 new_params.colourParams.contrast = val;
690 } else
691 retval = -EINVAL;
693 command_flags |= COMMAND_SETCOLOURPARAMS;
694 } else if (MATCH("saturation")) {
695 if (!retval)
696 val = VALUE;
698 if (!retval) {
699 if (val <= 100)
700 new_params.colourParams.saturation = val;
701 else
702 retval = -EINVAL;
704 command_flags |= COMMAND_SETCOLOURPARAMS;
705 } else if (MATCH("sensor_fps")) {
706 if (!retval)
707 val = VALUE;
709 if (!retval) {
710 /* find values so that sensorFPS is minimized,
711 * but >= val */
712 if (val > 30)
713 retval = -EINVAL;
714 else if (val > 25) {
715 new_params.sensorFps.divisor = 0;
716 new_params.sensorFps.baserate = 1;
717 } else if (val > 15) {
718 new_params.sensorFps.divisor = 0;
719 new_params.sensorFps.baserate = 0;
720 } else if (val > 12) {
721 new_params.sensorFps.divisor = 1;
722 new_params.sensorFps.baserate = 1;
723 } else if (val > 7) {
724 new_params.sensorFps.divisor = 1;
725 new_params.sensorFps.baserate = 0;
726 } else if (val > 6) {
727 new_params.sensorFps.divisor = 2;
728 new_params.sensorFps.baserate = 1;
729 } else if (val > 3) {
730 new_params.sensorFps.divisor = 2;
731 new_params.sensorFps.baserate = 0;
732 } else {
733 new_params.sensorFps.divisor = 3;
734 /* Either base rate would work here */
735 new_params.sensorFps.baserate = 1;
737 new_params.flickerControl.coarseJump =
738 flicker_jumps[new_mains]
739 [new_params.sensorFps.baserate]
740 [new_params.sensorFps.divisor];
741 if (new_params.flickerControl.flickerMode)
742 command_flags |= COMMAND_SETFLICKERCTRL;
744 command_flags |= COMMAND_SETSENSORFPS;
745 cam->exposure_status = EXPOSURE_NORMAL;
746 } else if (MATCH("stream_start_line")) {
747 if (!retval)
748 val = VALUE;
750 if (!retval) {
751 int max_line = 288;
753 if (new_params.format.videoSize == VIDEOSIZE_QCIF)
754 max_line = 144;
755 if (val <= max_line)
756 new_params.streamStartLine = val/2;
757 else
758 retval = -EINVAL;
760 } else if (MATCH("sub_sample")) {
761 if (!retval && MATCH("420"))
762 new_params.format.subSample = SUBSAMPLE_420;
763 else if (!retval && MATCH("422"))
764 new_params.format.subSample = SUBSAMPLE_422;
765 else
766 retval = -EINVAL;
768 command_flags |= COMMAND_SETFORMAT;
769 } else if (MATCH("yuv_order")) {
770 if (!retval && MATCH("YUYV"))
771 new_params.format.yuvOrder = YUVORDER_YUYV;
772 else if (!retval && MATCH("UYVY"))
773 new_params.format.yuvOrder = YUVORDER_UYVY;
774 else
775 retval = -EINVAL;
777 command_flags |= COMMAND_SETFORMAT;
778 } else if (MATCH("ecp_timing")) {
779 if (!retval && MATCH("normal"))
780 new_params.ecpTiming = 0;
781 else if (!retval && MATCH("slow"))
782 new_params.ecpTiming = 1;
783 else
784 retval = -EINVAL;
786 command_flags |= COMMAND_SETECPTIMING;
787 } else if (MATCH("color_balance_mode")) {
788 if (!retval && MATCH("manual"))
789 new_params.colourBalance.balanceMode = 3;
790 else if (!retval && MATCH("auto"))
791 new_params.colourBalance.balanceMode = 2;
792 else
793 retval = -EINVAL;
795 command_flags |= COMMAND_SETCOLOURBALANCE;
796 } else if (MATCH("red_gain")) {
797 if (!retval)
798 val = VALUE;
800 if (!retval) {
801 if (val <= 212) {
802 new_params.colourBalance.redGain = val;
803 new_params.colourBalance.balanceMode = 1;
804 } else
805 retval = -EINVAL;
807 command_flags |= COMMAND_SETCOLOURBALANCE;
808 } else if (MATCH("green_gain")) {
809 if (!retval)
810 val = VALUE;
812 if (!retval) {
813 if (val <= 212) {
814 new_params.colourBalance.greenGain = val;
815 new_params.colourBalance.balanceMode = 1;
816 } else
817 retval = -EINVAL;
819 command_flags |= COMMAND_SETCOLOURBALANCE;
820 } else if (MATCH("blue_gain")) {
821 if (!retval)
822 val = VALUE;
824 if (!retval) {
825 if (val <= 212) {
826 new_params.colourBalance.blueGain = val;
827 new_params.colourBalance.balanceMode = 1;
828 } else
829 retval = -EINVAL;
831 command_flags |= COMMAND_SETCOLOURBALANCE;
832 } else if (MATCH("max_gain")) {
833 if (!retval)
834 val = VALUE;
836 if (!retval) {
837 /* 1-02 firmware limits gain to 2 */
838 if (FIRMWARE_VERSION(1,2) && val > 2)
839 val = 2;
840 switch(val) {
841 case 1:
842 new_params.exposure.gainMode = 1;
843 break;
844 case 2:
845 new_params.exposure.gainMode = 2;
846 break;
847 case 4:
848 new_params.exposure.gainMode = 3;
849 break;
850 case 8:
851 new_params.exposure.gainMode = 4;
852 break;
853 default:
854 retval = -EINVAL;
855 break;
858 command_flags |= COMMAND_SETEXPOSURE;
859 } else if (MATCH("exposure_mode")) {
860 if (!retval && MATCH("auto"))
861 new_params.exposure.expMode = 2;
862 else if (!retval && MATCH("manual")) {
863 if (new_params.exposure.expMode == 2)
864 new_params.exposure.expMode = 3;
865 if(new_params.flickerControl.flickerMode != 0)
866 command_flags |= COMMAND_SETFLICKERCTRL;
867 new_params.flickerControl.flickerMode = 0;
868 } else
869 retval = -EINVAL;
871 command_flags |= COMMAND_SETEXPOSURE;
872 } else if (MATCH("centre_weight")) {
873 if (!retval && MATCH("on"))
874 new_params.exposure.centreWeight = 1;
875 else if (!retval && MATCH("off"))
876 new_params.exposure.centreWeight = 2;
877 else
878 retval = -EINVAL;
880 command_flags |= COMMAND_SETEXPOSURE;
881 } else if (MATCH("gain")) {
882 if (!retval)
883 val = VALUE;
885 if (!retval) {
886 switch(val) {
887 case 1:
888 new_params.exposure.gain = 0;
889 break;
890 case 2:
891 new_params.exposure.gain = 1;
892 break;
893 case 4:
894 new_params.exposure.gain = 2;
895 break;
896 case 8:
897 new_params.exposure.gain = 3;
898 break;
899 default:
900 retval = -EINVAL;
901 break;
903 new_params.exposure.expMode = 1;
904 if(new_params.flickerControl.flickerMode != 0)
905 command_flags |= COMMAND_SETFLICKERCTRL;
906 new_params.flickerControl.flickerMode = 0;
907 command_flags |= COMMAND_SETEXPOSURE;
908 if (new_params.exposure.gain >
909 new_params.exposure.gainMode-1)
910 retval = -EINVAL;
912 } else if (MATCH("fine_exp")) {
913 if (!retval)
914 val = VALUE/2;
916 if (!retval) {
917 if (val < 256) {
918 /* 1-02 firmware limits fineExp/2 to 127*/
919 if (FIRMWARE_VERSION(1,2) && val > 127)
920 val = 127;
921 new_params.exposure.fineExp = val;
922 new_params.exposure.expMode = 1;
923 command_flags |= COMMAND_SETEXPOSURE;
924 if(new_params.flickerControl.flickerMode != 0)
925 command_flags |= COMMAND_SETFLICKERCTRL;
926 new_params.flickerControl.flickerMode = 0;
927 command_flags |= COMMAND_SETFLICKERCTRL;
928 } else
929 retval = -EINVAL;
931 } else if (MATCH("coarse_exp")) {
932 if (!retval)
933 val = VALUE;
935 if (!retval) {
936 if (val <= MAX_EXP) {
937 if (FIRMWARE_VERSION(1,2) &&
938 val > MAX_EXP_102)
939 val = MAX_EXP_102;
940 new_params.exposure.coarseExpLo =
941 val & 0xff;
942 new_params.exposure.coarseExpHi =
943 val >> 8;
944 new_params.exposure.expMode = 1;
945 command_flags |= COMMAND_SETEXPOSURE;
946 if(new_params.flickerControl.flickerMode != 0)
947 command_flags |= COMMAND_SETFLICKERCTRL;
948 new_params.flickerControl.flickerMode = 0;
949 command_flags |= COMMAND_SETFLICKERCTRL;
950 } else
951 retval = -EINVAL;
953 } else if (MATCH("red_comp")) {
954 if (!retval)
955 val = VALUE;
957 if (!retval) {
958 if (val >= COMP_RED && val <= 255) {
959 new_params.exposure.redComp = val;
960 new_params.exposure.compMode = 1;
961 command_flags |= COMMAND_SETEXPOSURE;
962 } else
963 retval = -EINVAL;
965 } else if (MATCH("green1_comp")) {
966 if (!retval)
967 val = VALUE;
969 if (!retval) {
970 if (val >= COMP_GREEN1 && val <= 255) {
971 new_params.exposure.green1Comp = val;
972 new_params.exposure.compMode = 1;
973 command_flags |= COMMAND_SETEXPOSURE;
974 } else
975 retval = -EINVAL;
977 } else if (MATCH("green2_comp")) {
978 if (!retval)
979 val = VALUE;
981 if (!retval) {
982 if (val >= COMP_GREEN2 && val <= 255) {
983 new_params.exposure.green2Comp = val;
984 new_params.exposure.compMode = 1;
985 command_flags |= COMMAND_SETEXPOSURE;
986 } else
987 retval = -EINVAL;
989 } else if (MATCH("blue_comp")) {
990 if (!retval)
991 val = VALUE;
993 if (!retval) {
994 if (val >= COMP_BLUE && val <= 255) {
995 new_params.exposure.blueComp = val;
996 new_params.exposure.compMode = 1;
997 command_flags |= COMMAND_SETEXPOSURE;
998 } else
999 retval = -EINVAL;
1001 } else if (MATCH("apcor_gain1")) {
1002 if (!retval)
1003 val = VALUE;
1005 if (!retval) {
1006 command_flags |= COMMAND_SETAPCOR;
1007 if (val <= 0xff)
1008 new_params.apcor.gain1 = val;
1009 else
1010 retval = -EINVAL;
1012 } else if (MATCH("apcor_gain2")) {
1013 if (!retval)
1014 val = VALUE;
1016 if (!retval) {
1017 command_flags |= COMMAND_SETAPCOR;
1018 if (val <= 0xff)
1019 new_params.apcor.gain2 = val;
1020 else
1021 retval = -EINVAL;
1023 } else if (MATCH("apcor_gain4")) {
1024 if (!retval)
1025 val = VALUE;
1027 if (!retval) {
1028 command_flags |= COMMAND_SETAPCOR;
1029 if (val <= 0xff)
1030 new_params.apcor.gain4 = val;
1031 else
1032 retval = -EINVAL;
1034 } else if (MATCH("apcor_gain8")) {
1035 if (!retval)
1036 val = VALUE;
1038 if (!retval) {
1039 command_flags |= COMMAND_SETAPCOR;
1040 if (val <= 0xff)
1041 new_params.apcor.gain8 = val;
1042 else
1043 retval = -EINVAL;
1045 } else if (MATCH("vl_offset_gain1")) {
1046 if (!retval)
1047 val = VALUE;
1049 if (!retval) {
1050 if (val <= 0xff)
1051 new_params.vlOffset.gain1 = val;
1052 else
1053 retval = -EINVAL;
1055 command_flags |= COMMAND_SETVLOFFSET;
1056 } else if (MATCH("vl_offset_gain2")) {
1057 if (!retval)
1058 val = VALUE;
1060 if (!retval) {
1061 if (val <= 0xff)
1062 new_params.vlOffset.gain2 = val;
1063 else
1064 retval = -EINVAL;
1066 command_flags |= COMMAND_SETVLOFFSET;
1067 } else if (MATCH("vl_offset_gain4")) {
1068 if (!retval)
1069 val = VALUE;
1071 if (!retval) {
1072 if (val <= 0xff)
1073 new_params.vlOffset.gain4 = val;
1074 else
1075 retval = -EINVAL;
1077 command_flags |= COMMAND_SETVLOFFSET;
1078 } else if (MATCH("vl_offset_gain8")) {
1079 if (!retval)
1080 val = VALUE;
1082 if (!retval) {
1083 if (val <= 0xff)
1084 new_params.vlOffset.gain8 = val;
1085 else
1086 retval = -EINVAL;
1088 command_flags |= COMMAND_SETVLOFFSET;
1089 } else if (MATCH("flicker_control")) {
1090 if (!retval && MATCH("on")) {
1091 set_flicker(&new_params, &command_flags, 1);
1092 } else if (!retval && MATCH("off")) {
1093 set_flicker(&new_params, &command_flags, 0);
1094 } else
1095 retval = -EINVAL;
1097 command_flags |= COMMAND_SETFLICKERCTRL;
1098 } else if (MATCH("mains_frequency")) {
1099 if (!retval && MATCH("50")) {
1100 new_mains = 0;
1101 new_params.flickerControl.coarseJump =
1102 flicker_jumps[new_mains]
1103 [new_params.sensorFps.baserate]
1104 [new_params.sensorFps.divisor];
1105 if (new_params.flickerControl.flickerMode)
1106 command_flags |= COMMAND_SETFLICKERCTRL;
1107 } else if (!retval && MATCH("60")) {
1108 new_mains = 1;
1109 new_params.flickerControl.coarseJump =
1110 flicker_jumps[new_mains]
1111 [new_params.sensorFps.baserate]
1112 [new_params.sensorFps.divisor];
1113 if (new_params.flickerControl.flickerMode)
1114 command_flags |= COMMAND_SETFLICKERCTRL;
1115 } else
1116 retval = -EINVAL;
1117 } else if (MATCH("allowable_overexposure")) {
1118 if (!retval && MATCH("auto")) {
1119 new_params.flickerControl.allowableOverExposure =
1120 -find_over_exposure(new_params.colourParams.brightness);
1121 if(new_params.flickerControl.flickerMode != 0)
1122 command_flags |= COMMAND_SETFLICKERCTRL;
1123 } else {
1124 if (!retval)
1125 val = VALUE;
1127 if (!retval) {
1128 if (val <= 0xff) {
1129 new_params.flickerControl.
1130 allowableOverExposure = val;
1131 if(new_params.flickerControl.flickerMode != 0)
1132 command_flags |= COMMAND_SETFLICKERCTRL;
1133 } else
1134 retval = -EINVAL;
1137 } else if (MATCH("compression_mode")) {
1138 if (!retval && MATCH("none"))
1139 new_params.compression.mode =
1140 CPIA_COMPRESSION_NONE;
1141 else if (!retval && MATCH("auto"))
1142 new_params.compression.mode =
1143 CPIA_COMPRESSION_AUTO;
1144 else if (!retval && MATCH("manual"))
1145 new_params.compression.mode =
1146 CPIA_COMPRESSION_MANUAL;
1147 else
1148 retval = -EINVAL;
1150 command_flags |= COMMAND_SETCOMPRESSION;
1151 } else if (MATCH("decimation_enable")) {
1152 if (!retval && MATCH("off"))
1153 new_params.compression.decimation = 0;
1154 else if (!retval && MATCH("on"))
1155 new_params.compression.decimation = 1;
1156 else
1157 retval = -EINVAL;
1159 command_flags |= COMMAND_SETCOMPRESSION;
1160 } else if (MATCH("compression_target")) {
1161 if (!retval && MATCH("quality"))
1162 new_params.compressionTarget.frTargeting =
1163 CPIA_COMPRESSION_TARGET_QUALITY;
1164 else if (!retval && MATCH("framerate"))
1165 new_params.compressionTarget.frTargeting =
1166 CPIA_COMPRESSION_TARGET_FRAMERATE;
1167 else
1168 retval = -EINVAL;
1170 command_flags |= COMMAND_SETCOMPRESSIONTARGET;
1171 } else if (MATCH("target_framerate")) {
1172 if (!retval)
1173 val = VALUE;
1175 if (!retval) {
1176 if(val > 0 && val <= 30)
1177 new_params.compressionTarget.targetFR = val;
1178 else
1179 retval = -EINVAL;
1181 command_flags |= COMMAND_SETCOMPRESSIONTARGET;
1182 } else if (MATCH("target_quality")) {
1183 if (!retval)
1184 val = VALUE;
1186 if (!retval) {
1187 if(val > 0 && val <= 64)
1188 new_params.compressionTarget.targetQ = val;
1189 else
1190 retval = -EINVAL;
1192 command_flags |= COMMAND_SETCOMPRESSIONTARGET;
1193 } else if (MATCH("y_threshold")) {
1194 if (!retval)
1195 val = VALUE;
1197 if (!retval) {
1198 if (val < 32)
1199 new_params.yuvThreshold.yThreshold = val;
1200 else
1201 retval = -EINVAL;
1203 command_flags |= COMMAND_SETYUVTHRESH;
1204 } else if (MATCH("uv_threshold")) {
1205 if (!retval)
1206 val = VALUE;
1208 if (!retval) {
1209 if (val < 32)
1210 new_params.yuvThreshold.uvThreshold = val;
1211 else
1212 retval = -EINVAL;
1214 command_flags |= COMMAND_SETYUVTHRESH;
1215 } else if (MATCH("hysteresis")) {
1216 if (!retval)
1217 val = VALUE;
1219 if (!retval) {
1220 if (val <= 0xff)
1221 new_params.compressionParams.hysteresis = val;
1222 else
1223 retval = -EINVAL;
1225 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1226 } else if (MATCH("threshold_max")) {
1227 if (!retval)
1228 val = VALUE;
1230 if (!retval) {
1231 if (val <= 0xff)
1232 new_params.compressionParams.threshMax = val;
1233 else
1234 retval = -EINVAL;
1236 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1237 } else if (MATCH("small_step")) {
1238 if (!retval)
1239 val = VALUE;
1241 if (!retval) {
1242 if (val <= 0xff)
1243 new_params.compressionParams.smallStep = val;
1244 else
1245 retval = -EINVAL;
1247 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1248 } else if (MATCH("large_step")) {
1249 if (!retval)
1250 val = VALUE;
1252 if (!retval) {
1253 if (val <= 0xff)
1254 new_params.compressionParams.largeStep = val;
1255 else
1256 retval = -EINVAL;
1258 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1259 } else if (MATCH("decimation_hysteresis")) {
1260 if (!retval)
1261 val = VALUE;
1263 if (!retval) {
1264 if (val <= 0xff)
1265 new_params.compressionParams.decimationHysteresis = val;
1266 else
1267 retval = -EINVAL;
1269 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1270 } else if (MATCH("fr_diff_step_thresh")) {
1271 if (!retval)
1272 val = VALUE;
1274 if (!retval) {
1275 if (val <= 0xff)
1276 new_params.compressionParams.frDiffStepThresh = val;
1277 else
1278 retval = -EINVAL;
1280 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1281 } else if (MATCH("q_diff_step_thresh")) {
1282 if (!retval)
1283 val = VALUE;
1285 if (!retval) {
1286 if (val <= 0xff)
1287 new_params.compressionParams.qDiffStepThresh = val;
1288 else
1289 retval = -EINVAL;
1291 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1292 } else if (MATCH("decimation_thresh_mod")) {
1293 if (!retval)
1294 val = VALUE;
1296 if (!retval) {
1297 if (val <= 0xff)
1298 new_params.compressionParams.decimationThreshMod = val;
1299 else
1300 retval = -EINVAL;
1302 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1303 } else if (MATCH("toplight")) {
1304 if (!retval && MATCH("on"))
1305 new_params.qx3.toplight = 1;
1306 else if (!retval && MATCH("off"))
1307 new_params.qx3.toplight = 0;
1308 else
1309 retval = -EINVAL;
1310 command_flags |= COMMAND_SETLIGHTS;
1311 } else if (MATCH("bottomlight")) {
1312 if (!retval && MATCH("on"))
1313 new_params.qx3.bottomlight = 1;
1314 else if (!retval && MATCH("off"))
1315 new_params.qx3.bottomlight = 0;
1316 else
1317 retval = -EINVAL;
1318 command_flags |= COMMAND_SETLIGHTS;
1319 } else {
1320 DBG("No match found\n");
1321 retval = -EINVAL;
1324 if (!retval) {
1325 while (count && isspace(*buffer) && *buffer != '\n') {
1326 --count;
1327 ++buffer;
1329 if (count) {
1330 if (*buffer == '\0' && count != 1)
1331 retval = -EINVAL;
1332 else if (*buffer != '\n' && *buffer != ';' &&
1333 *buffer != '\0')
1334 retval = -EINVAL;
1335 else {
1336 --count;
1337 ++buffer;
1342 #undef MATCH
1343 #undef VALUE
1344 #undef FIRMWARE_VERSION
1345 if (!retval) {
1346 if (command_flags & COMMAND_SETCOLOURPARAMS) {
1347 /* Adjust cam->vp to reflect these changes */
1348 cam->vp.brightness =
1349 new_params.colourParams.brightness*65535/100;
1350 cam->vp.contrast =
1351 new_params.colourParams.contrast*65535/100;
1352 cam->vp.colour =
1353 new_params.colourParams.saturation*65535/100;
1355 if((command_flags & COMMAND_SETEXPOSURE) &&
1356 new_params.exposure.expMode == 2)
1357 cam->exposure_status = EXPOSURE_NORMAL;
1359 memcpy(&cam->params, &new_params, sizeof(struct cam_params));
1360 cam->mainsFreq = new_mains;
1361 cam->cmd_queue |= command_flags;
1362 retval = size;
1363 } else
1364 DBG("error: %d\n", retval);
1366 up(&cam->param_lock);
1368 out:
1369 free_page((unsigned long)page);
1370 return retval;
1373 static void create_proc_cpia_cam(struct cam_data *cam)
1375 char name[7];
1376 struct proc_dir_entry *ent;
1378 if (!cpia_proc_root || !cam)
1379 return;
1381 sprintf(name, "video%d", cam->vdev.minor);
1383 ent = create_proc_entry(name, S_IFREG|S_IRUGO|S_IWUSR, cpia_proc_root);
1384 if (!ent)
1385 return;
1387 ent->data = cam;
1388 ent->read_proc = cpia_read_proc;
1389 ent->write_proc = cpia_write_proc;
1391 size of the proc entry is 3736 bytes for the standard webcam;
1392 the extra features of the QX3 microscope add 189 bytes.
1393 (we have not yet probed the camera to see which type it is).
1395 ent->size = 3736 + 189;
1396 cam->proc_entry = ent;
1399 static void destroy_proc_cpia_cam(struct cam_data *cam)
1401 char name[7];
1403 if (!cam || !cam->proc_entry)
1404 return;
1406 sprintf(name, "video%d", cam->vdev.minor);
1407 remove_proc_entry(name, cpia_proc_root);
1408 cam->proc_entry = NULL;
1411 static void proc_cpia_create(void)
1413 cpia_proc_root = create_proc_entry("cpia", S_IFDIR, NULL);
1415 if (cpia_proc_root)
1416 cpia_proc_root->owner = THIS_MODULE;
1417 else
1418 LOG("Unable to initialise /proc/cpia\n");
1421 static void __exit proc_cpia_destroy(void)
1423 remove_proc_entry("cpia", NULL);
1425 #endif /* CONFIG_PROC_FS */
1427 /* ----------------------- debug functions ---------------------- */
1429 #define printstatus(cam) \
1430 DBG("%02x %02x %02x %02x %02x %02x %02x %02x\n",\
1431 cam->params.status.systemState, cam->params.status.grabState, \
1432 cam->params.status.streamState, cam->params.status.fatalError, \
1433 cam->params.status.cmdError, cam->params.status.debugFlags, \
1434 cam->params.status.vpStatus, cam->params.status.errorCode);
1436 /* ----------------------- v4l helpers -------------------------- */
1438 /* supported frame palettes and depths */
1439 static inline int valid_mode(u16 palette, u16 depth)
1441 if ((palette == VIDEO_PALETTE_YUV422 && depth == 16) ||
1442 (palette == VIDEO_PALETTE_YUYV && depth == 16))
1443 return 1;
1445 if (colorspace_conv)
1446 return (palette == VIDEO_PALETTE_GREY && depth == 8) ||
1447 (palette == VIDEO_PALETTE_RGB555 && depth == 16) ||
1448 (palette == VIDEO_PALETTE_RGB565 && depth == 16) ||
1449 (palette == VIDEO_PALETTE_RGB24 && depth == 24) ||
1450 (palette == VIDEO_PALETTE_RGB32 && depth == 32) ||
1451 (palette == VIDEO_PALETTE_UYVY && depth == 16);
1453 return 0;
1456 static int match_videosize( int width, int height )
1458 /* return the best match, where 'best' is as always
1459 * the largest that is not bigger than what is requested. */
1460 if (width>=352 && height>=288)
1461 return VIDEOSIZE_352_288; /* CIF */
1463 if (width>=320 && height>=240)
1464 return VIDEOSIZE_320_240; /* SIF */
1466 if (width>=288 && height>=216)
1467 return VIDEOSIZE_288_216;
1469 if (width>=256 && height>=192)
1470 return VIDEOSIZE_256_192;
1472 if (width>=224 && height>=168)
1473 return VIDEOSIZE_224_168;
1475 if (width>=192 && height>=144)
1476 return VIDEOSIZE_192_144;
1478 if (width>=176 && height>=144)
1479 return VIDEOSIZE_176_144; /* QCIF */
1481 if (width>=160 && height>=120)
1482 return VIDEOSIZE_160_120; /* QSIF */
1484 if (width>=128 && height>=96)
1485 return VIDEOSIZE_128_96;
1487 if (width>=88 && height>=72)
1488 return VIDEOSIZE_88_72;
1490 if (width>=64 && height>=48)
1491 return VIDEOSIZE_64_48;
1493 if (width>=48 && height>=48)
1494 return VIDEOSIZE_48_48;
1496 return -1;
1499 /* these are the capture sizes we support */
1500 static void set_vw_size(struct cam_data *cam)
1502 /* the col/row/start/end values are the result of simple math */
1503 /* study the SetROI-command in cpia developers guide p 2-22 */
1504 /* streamStartLine is set to the recommended value in the cpia */
1505 /* developers guide p 3-37 */
1506 switch(cam->video_size) {
1507 case VIDEOSIZE_CIF:
1508 cam->vw.width = 352;
1509 cam->vw.height = 288;
1510 cam->params.format.videoSize=VIDEOSIZE_CIF;
1511 cam->params.roi.colStart=0;
1512 cam->params.roi.rowStart=0;
1513 cam->params.streamStartLine = 120;
1514 break;
1515 case VIDEOSIZE_SIF:
1516 cam->vw.width = 320;
1517 cam->vw.height = 240;
1518 cam->params.format.videoSize=VIDEOSIZE_CIF;
1519 cam->params.roi.colStart=2;
1520 cam->params.roi.rowStart=6;
1521 cam->params.streamStartLine = 120;
1522 break;
1523 case VIDEOSIZE_288_216:
1524 cam->vw.width = 288;
1525 cam->vw.height = 216;
1526 cam->params.format.videoSize=VIDEOSIZE_CIF;
1527 cam->params.roi.colStart=4;
1528 cam->params.roi.rowStart=9;
1529 cam->params.streamStartLine = 120;
1530 break;
1531 case VIDEOSIZE_256_192:
1532 cam->vw.width = 256;
1533 cam->vw.height = 192;
1534 cam->params.format.videoSize=VIDEOSIZE_CIF;
1535 cam->params.roi.colStart=6;
1536 cam->params.roi.rowStart=12;
1537 cam->params.streamStartLine = 120;
1538 break;
1539 case VIDEOSIZE_224_168:
1540 cam->vw.width = 224;
1541 cam->vw.height = 168;
1542 cam->params.format.videoSize=VIDEOSIZE_CIF;
1543 cam->params.roi.colStart=8;
1544 cam->params.roi.rowStart=15;
1545 cam->params.streamStartLine = 120;
1546 break;
1547 case VIDEOSIZE_192_144:
1548 cam->vw.width = 192;
1549 cam->vw.height = 144;
1550 cam->params.format.videoSize=VIDEOSIZE_CIF;
1551 cam->params.roi.colStart=10;
1552 cam->params.roi.rowStart=18;
1553 cam->params.streamStartLine = 120;
1554 break;
1555 case VIDEOSIZE_QCIF:
1556 cam->vw.width = 176;
1557 cam->vw.height = 144;
1558 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1559 cam->params.roi.colStart=0;
1560 cam->params.roi.rowStart=0;
1561 cam->params.streamStartLine = 60;
1562 break;
1563 case VIDEOSIZE_QSIF:
1564 cam->vw.width = 160;
1565 cam->vw.height = 120;
1566 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1567 cam->params.roi.colStart=1;
1568 cam->params.roi.rowStart=3;
1569 cam->params.streamStartLine = 60;
1570 break;
1571 case VIDEOSIZE_128_96:
1572 cam->vw.width = 128;
1573 cam->vw.height = 96;
1574 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1575 cam->params.roi.colStart=3;
1576 cam->params.roi.rowStart=6;
1577 cam->params.streamStartLine = 60;
1578 break;
1579 case VIDEOSIZE_88_72:
1580 cam->vw.width = 88;
1581 cam->vw.height = 72;
1582 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1583 cam->params.roi.colStart=5;
1584 cam->params.roi.rowStart=9;
1585 cam->params.streamStartLine = 60;
1586 break;
1587 case VIDEOSIZE_64_48:
1588 cam->vw.width = 64;
1589 cam->vw.height = 48;
1590 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1591 cam->params.roi.colStart=7;
1592 cam->params.roi.rowStart=12;
1593 cam->params.streamStartLine = 60;
1594 break;
1595 case VIDEOSIZE_48_48:
1596 cam->vw.width = 48;
1597 cam->vw.height = 48;
1598 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1599 cam->params.roi.colStart=8;
1600 cam->params.roi.rowStart=6;
1601 cam->params.streamStartLine = 60;
1602 break;
1603 default:
1604 LOG("bad videosize value: %d\n", cam->video_size);
1605 return;
1608 if(cam->vc.width == 0)
1609 cam->vc.width = cam->vw.width;
1610 if(cam->vc.height == 0)
1611 cam->vc.height = cam->vw.height;
1613 cam->params.roi.colStart += cam->vc.x >> 3;
1614 cam->params.roi.colEnd = cam->params.roi.colStart +
1615 (cam->vc.width >> 3);
1616 cam->params.roi.rowStart += cam->vc.y >> 2;
1617 cam->params.roi.rowEnd = cam->params.roi.rowStart +
1618 (cam->vc.height >> 2);
1620 return;
1623 static int allocate_frame_buf(struct cam_data *cam)
1625 int i;
1627 cam->frame_buf = rvmalloc(FRAME_NUM * CPIA_MAX_FRAME_SIZE);
1628 if (!cam->frame_buf)
1629 return -ENOBUFS;
1631 for (i = 0; i < FRAME_NUM; i++)
1632 cam->frame[i].data = cam->frame_buf + i * CPIA_MAX_FRAME_SIZE;
1634 return 0;
1637 static int free_frame_buf(struct cam_data *cam)
1639 int i;
1641 rvfree(cam->frame_buf, FRAME_NUM*CPIA_MAX_FRAME_SIZE);
1642 cam->frame_buf = NULL;
1643 for (i=0; i < FRAME_NUM; i++)
1644 cam->frame[i].data = NULL;
1646 return 0;
1650 static inline void free_frames(struct cpia_frame frame[FRAME_NUM])
1652 int i;
1654 for (i=0; i < FRAME_NUM; i++)
1655 frame[i].state = FRAME_UNUSED;
1656 return;
1659 /**********************************************************************
1661 * General functions
1663 **********************************************************************/
1664 /* send an arbitrary command to the camera */
1665 static int do_command(struct cam_data *cam, u16 command, u8 a, u8 b, u8 c, u8 d)
1667 int retval, datasize;
1668 u8 cmd[8], data[8];
1670 switch(command) {
1671 case CPIA_COMMAND_GetCPIAVersion:
1672 case CPIA_COMMAND_GetPnPID:
1673 case CPIA_COMMAND_GetCameraStatus:
1674 case CPIA_COMMAND_GetVPVersion:
1675 datasize=8;
1676 break;
1677 case CPIA_COMMAND_GetColourParams:
1678 case CPIA_COMMAND_GetColourBalance:
1679 case CPIA_COMMAND_GetExposure:
1680 down(&cam->param_lock);
1681 datasize=8;
1682 break;
1683 case CPIA_COMMAND_ReadMCPorts:
1684 case CPIA_COMMAND_ReadVCRegs:
1685 datasize = 4;
1686 break;
1687 default:
1688 datasize=0;
1689 break;
1692 cmd[0] = command>>8;
1693 cmd[1] = command&0xff;
1694 cmd[2] = a;
1695 cmd[3] = b;
1696 cmd[4] = c;
1697 cmd[5] = d;
1698 cmd[6] = datasize;
1699 cmd[7] = 0;
1701 retval = cam->ops->transferCmd(cam->lowlevel_data, cmd, data);
1702 if (retval) {
1703 DBG("%x - failed, retval=%d\n", command, retval);
1704 if (command == CPIA_COMMAND_GetColourParams ||
1705 command == CPIA_COMMAND_GetColourBalance ||
1706 command == CPIA_COMMAND_GetExposure)
1707 up(&cam->param_lock);
1708 } else {
1709 switch(command) {
1710 case CPIA_COMMAND_GetCPIAVersion:
1711 cam->params.version.firmwareVersion = data[0];
1712 cam->params.version.firmwareRevision = data[1];
1713 cam->params.version.vcVersion = data[2];
1714 cam->params.version.vcRevision = data[3];
1715 break;
1716 case CPIA_COMMAND_GetPnPID:
1717 cam->params.pnpID.vendor = data[0]+(((u16)data[1])<<8);
1718 cam->params.pnpID.product = data[2]+(((u16)data[3])<<8);
1719 cam->params.pnpID.deviceRevision =
1720 data[4]+(((u16)data[5])<<8);
1721 break;
1722 case CPIA_COMMAND_GetCameraStatus:
1723 cam->params.status.systemState = data[0];
1724 cam->params.status.grabState = data[1];
1725 cam->params.status.streamState = data[2];
1726 cam->params.status.fatalError = data[3];
1727 cam->params.status.cmdError = data[4];
1728 cam->params.status.debugFlags = data[5];
1729 cam->params.status.vpStatus = data[6];
1730 cam->params.status.errorCode = data[7];
1731 break;
1732 case CPIA_COMMAND_GetVPVersion:
1733 cam->params.vpVersion.vpVersion = data[0];
1734 cam->params.vpVersion.vpRevision = data[1];
1735 cam->params.vpVersion.cameraHeadID =
1736 data[2]+(((u16)data[3])<<8);
1737 break;
1738 case CPIA_COMMAND_GetColourParams:
1739 cam->params.colourParams.brightness = data[0];
1740 cam->params.colourParams.contrast = data[1];
1741 cam->params.colourParams.saturation = data[2];
1742 up(&cam->param_lock);
1743 break;
1744 case CPIA_COMMAND_GetColourBalance:
1745 cam->params.colourBalance.redGain = data[0];
1746 cam->params.colourBalance.greenGain = data[1];
1747 cam->params.colourBalance.blueGain = data[2];
1748 up(&cam->param_lock);
1749 break;
1750 case CPIA_COMMAND_GetExposure:
1751 cam->params.exposure.gain = data[0];
1752 cam->params.exposure.fineExp = data[1];
1753 cam->params.exposure.coarseExpLo = data[2];
1754 cam->params.exposure.coarseExpHi = data[3];
1755 cam->params.exposure.redComp = data[4];
1756 cam->params.exposure.green1Comp = data[5];
1757 cam->params.exposure.green2Comp = data[6];
1758 cam->params.exposure.blueComp = data[7];
1759 up(&cam->param_lock);
1760 break;
1762 case CPIA_COMMAND_ReadMCPorts:
1763 if (!cam->params.qx3.qx3_detected)
1764 break;
1765 /* test button press */
1766 cam->params.qx3.button = ((data[1] & 0x02) == 0);
1767 if (cam->params.qx3.button) {
1768 /* button pressed - unlock the latch */
1769 do_command(cam,CPIA_COMMAND_WriteMCPort,3,0xDF,0xDF,0);
1770 do_command(cam,CPIA_COMMAND_WriteMCPort,3,0xFF,0xFF,0);
1773 /* test whether microscope is cradled */
1774 cam->params.qx3.cradled = ((data[2] & 0x40) == 0);
1775 break;
1777 default:
1778 break;
1781 return retval;
1784 /* send a command to the camera with an additional data transaction */
1785 static int do_command_extended(struct cam_data *cam, u16 command,
1786 u8 a, u8 b, u8 c, u8 d,
1787 u8 e, u8 f, u8 g, u8 h,
1788 u8 i, u8 j, u8 k, u8 l)
1790 int retval;
1791 u8 cmd[8], data[8];
1793 cmd[0] = command>>8;
1794 cmd[1] = command&0xff;
1795 cmd[2] = a;
1796 cmd[3] = b;
1797 cmd[4] = c;
1798 cmd[5] = d;
1799 cmd[6] = 8;
1800 cmd[7] = 0;
1801 data[0] = e;
1802 data[1] = f;
1803 data[2] = g;
1804 data[3] = h;
1805 data[4] = i;
1806 data[5] = j;
1807 data[6] = k;
1808 data[7] = l;
1810 retval = cam->ops->transferCmd(cam->lowlevel_data, cmd, data);
1811 if (retval)
1812 DBG("%x - failed\n", command);
1814 return retval;
1817 /**********************************************************************
1819 * Colorspace conversion
1821 **********************************************************************/
1822 #define LIMIT(x) ((((x)>0xffffff)?0xff0000:(((x)<=0xffff)?0:(x)&0xff0000))>>16)
1824 static int convert420(unsigned char *yuv, unsigned char *rgb, int out_fmt,
1825 int linesize, int mmap_kludge)
1827 int y, u, v, r, g, b, y1;
1829 /* Odd lines use the same u and v as the previous line.
1830 * Because of compression, it is necessary to get this
1831 * information from the decoded image. */
1832 switch(out_fmt) {
1833 case VIDEO_PALETTE_RGB555:
1834 y = (*yuv++ - 16) * 76310;
1835 y1 = (*yuv - 16) * 76310;
1836 r = ((*(rgb+1-linesize)) & 0x7c) << 1;
1837 g = ((*(rgb-linesize)) & 0xe0) >> 4 |
1838 ((*(rgb+1-linesize)) & 0x03) << 6;
1839 b = ((*(rgb-linesize)) & 0x1f) << 3;
1840 u = (-53294 * r - 104635 * g + 157929 * b) / 5756495;
1841 v = (157968 * r - 132278 * g - 25690 * b) / 5366159;
1842 r = 104635 * v;
1843 g = -25690 * u - 53294 * v;
1844 b = 132278 * u;
1845 *rgb++ = ((LIMIT(g+y) & 0xf8) << 2) | (LIMIT(b+y) >> 3);
1846 *rgb++ = ((LIMIT(r+y) & 0xf8) >> 1) | (LIMIT(g+y) >> 6);
1847 *rgb++ = ((LIMIT(g+y1) & 0xf8) << 2) | (LIMIT(b+y1) >> 3);
1848 *rgb = ((LIMIT(r+y1) & 0xf8) >> 1) | (LIMIT(g+y1) >> 6);
1849 return 4;
1850 case VIDEO_PALETTE_RGB565:
1851 y = (*yuv++ - 16) * 76310;
1852 y1 = (*yuv - 16) * 76310;
1853 r = (*(rgb+1-linesize)) & 0xf8;
1854 g = ((*(rgb-linesize)) & 0xe0) >> 3 |
1855 ((*(rgb+1-linesize)) & 0x07) << 5;
1856 b = ((*(rgb-linesize)) & 0x1f) << 3;
1857 u = (-53294 * r - 104635 * g + 157929 * b) / 5756495;
1858 v = (157968 * r - 132278 * g - 25690 * b) / 5366159;
1859 r = 104635 * v;
1860 g = -25690 * u - 53294 * v;
1861 b = 132278 * u;
1862 *rgb++ = ((LIMIT(g+y) & 0xfc) << 3) | (LIMIT(b+y) >> 3);
1863 *rgb++ = (LIMIT(r+y) & 0xf8) | (LIMIT(g+y) >> 5);
1864 *rgb++ = ((LIMIT(g+y1) & 0xfc) << 3) | (LIMIT(b+y1) >> 3);
1865 *rgb = (LIMIT(r+y1) & 0xf8) | (LIMIT(g+y1) >> 5);
1866 return 4;
1867 break;
1868 case VIDEO_PALETTE_RGB24:
1869 case VIDEO_PALETTE_RGB32:
1870 y = (*yuv++ - 16) * 76310;
1871 y1 = (*yuv - 16) * 76310;
1872 if (mmap_kludge) {
1873 r = *(rgb+2-linesize);
1874 g = *(rgb+1-linesize);
1875 b = *(rgb-linesize);
1876 } else {
1877 r = *(rgb-linesize);
1878 g = *(rgb+1-linesize);
1879 b = *(rgb+2-linesize);
1881 u = (-53294 * r - 104635 * g + 157929 * b) / 5756495;
1882 v = (157968 * r - 132278 * g - 25690 * b) / 5366159;
1883 r = 104635 * v;
1884 g = -25690 * u + -53294 * v;
1885 b = 132278 * u;
1886 if (mmap_kludge) {
1887 *rgb++ = LIMIT(b+y);
1888 *rgb++ = LIMIT(g+y);
1889 *rgb++ = LIMIT(r+y);
1890 if(out_fmt == VIDEO_PALETTE_RGB32)
1891 rgb++;
1892 *rgb++ = LIMIT(b+y1);
1893 *rgb++ = LIMIT(g+y1);
1894 *rgb = LIMIT(r+y1);
1895 } else {
1896 *rgb++ = LIMIT(r+y);
1897 *rgb++ = LIMIT(g+y);
1898 *rgb++ = LIMIT(b+y);
1899 if(out_fmt == VIDEO_PALETTE_RGB32)
1900 rgb++;
1901 *rgb++ = LIMIT(r+y1);
1902 *rgb++ = LIMIT(g+y1);
1903 *rgb = LIMIT(b+y1);
1905 if(out_fmt == VIDEO_PALETTE_RGB32)
1906 return 8;
1907 return 6;
1908 case VIDEO_PALETTE_YUV422:
1909 case VIDEO_PALETTE_YUYV:
1910 y = *yuv++;
1911 u = *(rgb+1-linesize);
1912 y1 = *yuv;
1913 v = *(rgb+3-linesize);
1914 *rgb++ = y;
1915 *rgb++ = u;
1916 *rgb++ = y1;
1917 *rgb = v;
1918 return 4;
1919 case VIDEO_PALETTE_UYVY:
1920 u = *(rgb-linesize);
1921 y = *yuv++;
1922 v = *(rgb+2-linesize);
1923 y1 = *yuv;
1924 *rgb++ = u;
1925 *rgb++ = y;
1926 *rgb++ = v;
1927 *rgb = y1;
1928 return 4;
1929 case VIDEO_PALETTE_GREY:
1930 *rgb++ = *yuv++;
1931 *rgb = *yuv;
1932 return 2;
1933 default:
1934 DBG("Empty: %d\n", out_fmt);
1935 return 0;
1940 static int yuvconvert(unsigned char *yuv, unsigned char *rgb, int out_fmt,
1941 int in_uyvy, int mmap_kludge)
1943 int y, u, v, r, g, b, y1;
1945 switch(out_fmt) {
1946 case VIDEO_PALETTE_RGB555:
1947 case VIDEO_PALETTE_RGB565:
1948 case VIDEO_PALETTE_RGB24:
1949 case VIDEO_PALETTE_RGB32:
1950 if (in_uyvy) {
1951 u = *yuv++ - 128;
1952 y = (*yuv++ - 16) * 76310;
1953 v = *yuv++ - 128;
1954 y1 = (*yuv - 16) * 76310;
1955 } else {
1956 y = (*yuv++ - 16) * 76310;
1957 u = *yuv++ - 128;
1958 y1 = (*yuv++ - 16) * 76310;
1959 v = *yuv - 128;
1961 r = 104635 * v;
1962 g = -25690 * u + -53294 * v;
1963 b = 132278 * u;
1964 break;
1965 default:
1966 y = *yuv++;
1967 u = *yuv++;
1968 y1 = *yuv++;
1969 v = *yuv;
1970 /* Just to avoid compiler warnings */
1971 r = 0;
1972 g = 0;
1973 b = 0;
1974 break;
1976 switch(out_fmt) {
1977 case VIDEO_PALETTE_RGB555:
1978 *rgb++ = ((LIMIT(g+y) & 0xf8) << 2) | (LIMIT(b+y) >> 3);
1979 *rgb++ = ((LIMIT(r+y) & 0xf8) >> 1) | (LIMIT(g+y) >> 6);
1980 *rgb++ = ((LIMIT(g+y1) & 0xf8) << 2) | (LIMIT(b+y1) >> 3);
1981 *rgb = ((LIMIT(r+y1) & 0xf8) >> 1) | (LIMIT(g+y1) >> 6);
1982 return 4;
1983 case VIDEO_PALETTE_RGB565:
1984 *rgb++ = ((LIMIT(g+y) & 0xfc) << 3) | (LIMIT(b+y) >> 3);
1985 *rgb++ = (LIMIT(r+y) & 0xf8) | (LIMIT(g+y) >> 5);
1986 *rgb++ = ((LIMIT(g+y1) & 0xfc) << 3) | (LIMIT(b+y1) >> 3);
1987 *rgb = (LIMIT(r+y1) & 0xf8) | (LIMIT(g+y1) >> 5);
1988 return 4;
1989 case VIDEO_PALETTE_RGB24:
1990 if (mmap_kludge) {
1991 *rgb++ = LIMIT(b+y);
1992 *rgb++ = LIMIT(g+y);
1993 *rgb++ = LIMIT(r+y);
1994 *rgb++ = LIMIT(b+y1);
1995 *rgb++ = LIMIT(g+y1);
1996 *rgb = LIMIT(r+y1);
1997 } else {
1998 *rgb++ = LIMIT(r+y);
1999 *rgb++ = LIMIT(g+y);
2000 *rgb++ = LIMIT(b+y);
2001 *rgb++ = LIMIT(r+y1);
2002 *rgb++ = LIMIT(g+y1);
2003 *rgb = LIMIT(b+y1);
2005 return 6;
2006 case VIDEO_PALETTE_RGB32:
2007 if (mmap_kludge) {
2008 *rgb++ = LIMIT(b+y);
2009 *rgb++ = LIMIT(g+y);
2010 *rgb++ = LIMIT(r+y);
2011 rgb++;
2012 *rgb++ = LIMIT(b+y1);
2013 *rgb++ = LIMIT(g+y1);
2014 *rgb = LIMIT(r+y1);
2015 } else {
2016 *rgb++ = LIMIT(r+y);
2017 *rgb++ = LIMIT(g+y);
2018 *rgb++ = LIMIT(b+y);
2019 rgb++;
2020 *rgb++ = LIMIT(r+y1);
2021 *rgb++ = LIMIT(g+y1);
2022 *rgb = LIMIT(b+y1);
2024 return 8;
2025 case VIDEO_PALETTE_GREY:
2026 *rgb++ = y;
2027 *rgb = y1;
2028 return 2;
2029 case VIDEO_PALETTE_YUV422:
2030 case VIDEO_PALETTE_YUYV:
2031 *rgb++ = y;
2032 *rgb++ = u;
2033 *rgb++ = y1;
2034 *rgb = v;
2035 return 4;
2036 case VIDEO_PALETTE_UYVY:
2037 *rgb++ = u;
2038 *rgb++ = y;
2039 *rgb++ = v;
2040 *rgb = y1;
2041 return 4;
2042 default:
2043 DBG("Empty: %d\n", out_fmt);
2044 return 0;
2048 static int skipcount(int count, int fmt)
2050 switch(fmt) {
2051 case VIDEO_PALETTE_GREY:
2052 return count;
2053 case VIDEO_PALETTE_RGB555:
2054 case VIDEO_PALETTE_RGB565:
2055 case VIDEO_PALETTE_YUV422:
2056 case VIDEO_PALETTE_YUYV:
2057 case VIDEO_PALETTE_UYVY:
2058 return 2*count;
2059 case VIDEO_PALETTE_RGB24:
2060 return 3*count;
2061 case VIDEO_PALETTE_RGB32:
2062 return 4*count;
2063 default:
2064 return 0;
2068 static int parse_picture(struct cam_data *cam, int size)
2070 u8 *obuf, *ibuf, *end_obuf;
2071 int ll, in_uyvy, compressed, decimation, even_line, origsize, out_fmt;
2072 int rows, cols, linesize, subsample_422;
2074 /* make sure params don't change while we are decoding */
2075 down(&cam->param_lock);
2077 obuf = cam->decompressed_frame.data;
2078 end_obuf = obuf+CPIA_MAX_FRAME_SIZE;
2079 ibuf = cam->raw_image;
2080 origsize = size;
2081 out_fmt = cam->vp.palette;
2083 if ((ibuf[0] != MAGIC_0) || (ibuf[1] != MAGIC_1)) {
2084 LOG("header not found\n");
2085 up(&cam->param_lock);
2086 return -1;
2089 if ((ibuf[16] != VIDEOSIZE_QCIF) && (ibuf[16] != VIDEOSIZE_CIF)) {
2090 LOG("wrong video size\n");
2091 up(&cam->param_lock);
2092 return -1;
2095 if (ibuf[17] != SUBSAMPLE_420 && ibuf[17] != SUBSAMPLE_422) {
2096 LOG("illegal subtype %d\n",ibuf[17]);
2097 up(&cam->param_lock);
2098 return -1;
2100 subsample_422 = ibuf[17] == SUBSAMPLE_422;
2102 if (ibuf[18] != YUVORDER_YUYV && ibuf[18] != YUVORDER_UYVY) {
2103 LOG("illegal yuvorder %d\n",ibuf[18]);
2104 up(&cam->param_lock);
2105 return -1;
2107 in_uyvy = ibuf[18] == YUVORDER_UYVY;
2109 if ((ibuf[24] != cam->params.roi.colStart) ||
2110 (ibuf[25] != cam->params.roi.colEnd) ||
2111 (ibuf[26] != cam->params.roi.rowStart) ||
2112 (ibuf[27] != cam->params.roi.rowEnd)) {
2113 LOG("ROI mismatch\n");
2114 up(&cam->param_lock);
2115 return -1;
2117 cols = 8*(ibuf[25] - ibuf[24]);
2118 rows = 4*(ibuf[27] - ibuf[26]);
2121 if ((ibuf[28] != NOT_COMPRESSED) && (ibuf[28] != COMPRESSED)) {
2122 LOG("illegal compression %d\n",ibuf[28]);
2123 up(&cam->param_lock);
2124 return -1;
2126 compressed = (ibuf[28] == COMPRESSED);
2128 if (ibuf[29] != NO_DECIMATION && ibuf[29] != DECIMATION_ENAB) {
2129 LOG("illegal decimation %d\n",ibuf[29]);
2130 up(&cam->param_lock);
2131 return -1;
2133 decimation = (ibuf[29] == DECIMATION_ENAB);
2135 cam->params.yuvThreshold.yThreshold = ibuf[30];
2136 cam->params.yuvThreshold.uvThreshold = ibuf[31];
2137 cam->params.status.systemState = ibuf[32];
2138 cam->params.status.grabState = ibuf[33];
2139 cam->params.status.streamState = ibuf[34];
2140 cam->params.status.fatalError = ibuf[35];
2141 cam->params.status.cmdError = ibuf[36];
2142 cam->params.status.debugFlags = ibuf[37];
2143 cam->params.status.vpStatus = ibuf[38];
2144 cam->params.status.errorCode = ibuf[39];
2145 cam->fps = ibuf[41];
2146 up(&cam->param_lock);
2148 linesize = skipcount(cols, out_fmt);
2149 ibuf += FRAME_HEADER_SIZE;
2150 size -= FRAME_HEADER_SIZE;
2151 ll = ibuf[0] | (ibuf[1] << 8);
2152 ibuf += 2;
2153 even_line = 1;
2155 while (size > 0) {
2156 size -= (ll+2);
2157 if (size < 0) {
2158 LOG("Insufficient data in buffer\n");
2159 return -1;
2162 while (ll > 1) {
2163 if (!compressed || (compressed && !(*ibuf & 1))) {
2164 if(subsample_422 || even_line) {
2165 obuf += yuvconvert(ibuf, obuf, out_fmt,
2166 in_uyvy, cam->mmap_kludge);
2167 ibuf += 4;
2168 ll -= 4;
2169 } else {
2170 /* SUBSAMPLE_420 on an odd line */
2171 obuf += convert420(ibuf, obuf,
2172 out_fmt, linesize,
2173 cam->mmap_kludge);
2174 ibuf += 2;
2175 ll -= 2;
2177 } else {
2178 /*skip compressed interval from previous frame*/
2179 obuf += skipcount(*ibuf >> 1, out_fmt);
2180 if (obuf > end_obuf) {
2181 LOG("Insufficient buffer size\n");
2182 return -1;
2184 ++ibuf;
2185 ll--;
2188 if (ll == 1) {
2189 if (*ibuf != EOL) {
2190 DBG("EOL not found giving up after %d/%d"
2191 " bytes\n", origsize-size, origsize);
2192 return -1;
2195 ++ibuf; /* skip over EOL */
2197 if ((size > 3) && (ibuf[0] == EOI) && (ibuf[1] == EOI) &&
2198 (ibuf[2] == EOI) && (ibuf[3] == EOI)) {
2199 size -= 4;
2200 break;
2203 if(decimation) {
2204 /* skip the odd lines for now */
2205 obuf += linesize;
2208 if (size > 1) {
2209 ll = ibuf[0] | (ibuf[1] << 8);
2210 ibuf += 2; /* skip over line length */
2212 if(!decimation)
2213 even_line = !even_line;
2214 } else {
2215 LOG("line length was not 1 but %d after %d/%d bytes\n",
2216 ll, origsize-size, origsize);
2217 return -1;
2221 if(decimation) {
2222 /* interpolate odd rows */
2223 int i, j;
2224 u8 *prev, *next;
2225 prev = cam->decompressed_frame.data;
2226 obuf = prev+linesize;
2227 next = obuf+linesize;
2228 for(i=1; i<rows-1; i+=2) {
2229 for(j=0; j<linesize; ++j) {
2230 *obuf++ = ((int)*prev++ + *next++) / 2;
2232 prev += linesize;
2233 obuf += linesize;
2234 next += linesize;
2236 /* last row is odd, just copy previous row */
2237 memcpy(obuf, prev, linesize);
2240 cam->decompressed_frame.count = obuf-cam->decompressed_frame.data;
2242 return cam->decompressed_frame.count;
2245 /* InitStreamCap wrapper to select correct start line */
2246 static inline int init_stream_cap(struct cam_data *cam)
2248 return do_command(cam, CPIA_COMMAND_InitStreamCap,
2249 0, cam->params.streamStartLine, 0, 0);
2253 /* find_over_exposure
2254 * Finds a suitable value of OverExposure for use with SetFlickerCtrl
2255 * Some calculation is required because this value changes with the brightness
2256 * set with SetColourParameters
2258 * Parameters: Brightness - last brightness value set with SetColourParameters
2260 * Returns: OverExposure value to use with SetFlickerCtrl
2262 #define FLICKER_MAX_EXPOSURE 250
2263 #define FLICKER_ALLOWABLE_OVER_EXPOSURE 146
2264 #define FLICKER_BRIGHTNESS_CONSTANT 59
2265 static int find_over_exposure(int brightness)
2267 int MaxAllowableOverExposure, OverExposure;
2269 MaxAllowableOverExposure = FLICKER_MAX_EXPOSURE - brightness -
2270 FLICKER_BRIGHTNESS_CONSTANT;
2272 if (MaxAllowableOverExposure < FLICKER_ALLOWABLE_OVER_EXPOSURE) {
2273 OverExposure = MaxAllowableOverExposure;
2274 } else {
2275 OverExposure = FLICKER_ALLOWABLE_OVER_EXPOSURE;
2278 return OverExposure;
2280 #undef FLICKER_MAX_EXPOSURE
2281 #undef FLICKER_ALLOWABLE_OVER_EXPOSURE
2282 #undef FLICKER_BRIGHTNESS_CONSTANT
2284 /* update various camera modes and settings */
2285 static void dispatch_commands(struct cam_data *cam)
2287 down(&cam->param_lock);
2288 if (cam->cmd_queue==COMMAND_NONE) {
2289 up(&cam->param_lock);
2290 return;
2292 DEB_BYTE(cam->cmd_queue);
2293 DEB_BYTE(cam->cmd_queue>>8);
2294 if (cam->cmd_queue & COMMAND_SETFORMAT) {
2295 do_command(cam, CPIA_COMMAND_SetFormat,
2296 cam->params.format.videoSize,
2297 cam->params.format.subSample,
2298 cam->params.format.yuvOrder, 0);
2299 do_command(cam, CPIA_COMMAND_SetROI,
2300 cam->params.roi.colStart, cam->params.roi.colEnd,
2301 cam->params.roi.rowStart, cam->params.roi.rowEnd);
2302 cam->first_frame = 1;
2305 if (cam->cmd_queue & COMMAND_SETCOLOURPARAMS)
2306 do_command(cam, CPIA_COMMAND_SetColourParams,
2307 cam->params.colourParams.brightness,
2308 cam->params.colourParams.contrast,
2309 cam->params.colourParams.saturation, 0);
2311 if (cam->cmd_queue & COMMAND_SETAPCOR)
2312 do_command(cam, CPIA_COMMAND_SetApcor,
2313 cam->params.apcor.gain1,
2314 cam->params.apcor.gain2,
2315 cam->params.apcor.gain4,
2316 cam->params.apcor.gain8);
2318 if (cam->cmd_queue & COMMAND_SETVLOFFSET)
2319 do_command(cam, CPIA_COMMAND_SetVLOffset,
2320 cam->params.vlOffset.gain1,
2321 cam->params.vlOffset.gain2,
2322 cam->params.vlOffset.gain4,
2323 cam->params.vlOffset.gain8);
2325 if (cam->cmd_queue & COMMAND_SETEXPOSURE) {
2326 do_command_extended(cam, CPIA_COMMAND_SetExposure,
2327 cam->params.exposure.gainMode,
2329 cam->params.exposure.compMode,
2330 cam->params.exposure.centreWeight,
2331 cam->params.exposure.gain,
2332 cam->params.exposure.fineExp,
2333 cam->params.exposure.coarseExpLo,
2334 cam->params.exposure.coarseExpHi,
2335 cam->params.exposure.redComp,
2336 cam->params.exposure.green1Comp,
2337 cam->params.exposure.green2Comp,
2338 cam->params.exposure.blueComp);
2339 if(cam->params.exposure.expMode != 1) {
2340 do_command_extended(cam, CPIA_COMMAND_SetExposure,
2342 cam->params.exposure.expMode,
2343 0, 0,
2344 cam->params.exposure.gain,
2345 cam->params.exposure.fineExp,
2346 cam->params.exposure.coarseExpLo,
2347 cam->params.exposure.coarseExpHi,
2348 0, 0, 0, 0);
2352 if (cam->cmd_queue & COMMAND_SETCOLOURBALANCE) {
2353 if (cam->params.colourBalance.balanceMode == 1) {
2354 do_command(cam, CPIA_COMMAND_SetColourBalance,
2356 cam->params.colourBalance.redGain,
2357 cam->params.colourBalance.greenGain,
2358 cam->params.colourBalance.blueGain);
2359 do_command(cam, CPIA_COMMAND_SetColourBalance,
2360 3, 0, 0, 0);
2362 if (cam->params.colourBalance.balanceMode == 2) {
2363 do_command(cam, CPIA_COMMAND_SetColourBalance,
2364 2, 0, 0, 0);
2366 if (cam->params.colourBalance.balanceMode == 3) {
2367 do_command(cam, CPIA_COMMAND_SetColourBalance,
2368 3, 0, 0, 0);
2372 if (cam->cmd_queue & COMMAND_SETCOMPRESSIONTARGET)
2373 do_command(cam, CPIA_COMMAND_SetCompressionTarget,
2374 cam->params.compressionTarget.frTargeting,
2375 cam->params.compressionTarget.targetFR,
2376 cam->params.compressionTarget.targetQ, 0);
2378 if (cam->cmd_queue & COMMAND_SETYUVTHRESH)
2379 do_command(cam, CPIA_COMMAND_SetYUVThresh,
2380 cam->params.yuvThreshold.yThreshold,
2381 cam->params.yuvThreshold.uvThreshold, 0, 0);
2383 if (cam->cmd_queue & COMMAND_SETCOMPRESSIONPARAMS)
2384 do_command_extended(cam, CPIA_COMMAND_SetCompressionParams,
2385 0, 0, 0, 0,
2386 cam->params.compressionParams.hysteresis,
2387 cam->params.compressionParams.threshMax,
2388 cam->params.compressionParams.smallStep,
2389 cam->params.compressionParams.largeStep,
2390 cam->params.compressionParams.decimationHysteresis,
2391 cam->params.compressionParams.frDiffStepThresh,
2392 cam->params.compressionParams.qDiffStepThresh,
2393 cam->params.compressionParams.decimationThreshMod);
2395 if (cam->cmd_queue & COMMAND_SETCOMPRESSION)
2396 do_command(cam, CPIA_COMMAND_SetCompression,
2397 cam->params.compression.mode,
2398 cam->params.compression.decimation, 0, 0);
2400 if (cam->cmd_queue & COMMAND_SETSENSORFPS)
2401 do_command(cam, CPIA_COMMAND_SetSensorFPS,
2402 cam->params.sensorFps.divisor,
2403 cam->params.sensorFps.baserate, 0, 0);
2405 if (cam->cmd_queue & COMMAND_SETFLICKERCTRL)
2406 do_command(cam, CPIA_COMMAND_SetFlickerCtrl,
2407 cam->params.flickerControl.flickerMode,
2408 cam->params.flickerControl.coarseJump,
2409 abs(cam->params.flickerControl.allowableOverExposure),
2412 if (cam->cmd_queue & COMMAND_SETECPTIMING)
2413 do_command(cam, CPIA_COMMAND_SetECPTiming,
2414 cam->params.ecpTiming, 0, 0, 0);
2416 if (cam->cmd_queue & COMMAND_PAUSE)
2417 do_command(cam, CPIA_COMMAND_EndStreamCap, 0, 0, 0, 0);
2419 if (cam->cmd_queue & COMMAND_RESUME)
2420 init_stream_cap(cam);
2422 if (cam->cmd_queue & COMMAND_SETLIGHTS && cam->params.qx3.qx3_detected)
2424 int p1 = (cam->params.qx3.bottomlight == 0) << 1;
2425 int p2 = (cam->params.qx3.toplight == 0) << 3;
2426 do_command(cam, CPIA_COMMAND_WriteVCReg, 0x90, 0x8F, 0x50, 0);
2427 do_command(cam, CPIA_COMMAND_WriteMCPort, 2, 0, (p1|p2|0xE0), 0);
2430 cam->cmd_queue = COMMAND_NONE;
2431 up(&cam->param_lock);
2432 return;
2437 static void set_flicker(struct cam_params *params, volatile u32 *command_flags,
2438 int on)
2440 /* Everything in here is from the Windows driver */
2441 #define FIRMWARE_VERSION(x,y) (params->version.firmwareVersion == (x) && \
2442 params->version.firmwareRevision == (y))
2443 /* define for compgain calculation */
2444 #if 0
2445 #define COMPGAIN(base, curexp, newexp) \
2446 (u8) ((((float) base - 128.0) * ((float) curexp / (float) newexp)) + 128.5)
2447 #define EXP_FROM_COMP(basecomp, curcomp, curexp) \
2448 (u16)((float)curexp * (float)(u8)(curcomp + 128) / (float)(u8)(basecomp - 128))
2449 #else
2450 /* equivalent functions without floating point math */
2451 #define COMPGAIN(base, curexp, newexp) \
2452 (u8)(128 + (((u32)(2*(base-128)*curexp + newexp)) / (2* newexp)) )
2453 #define EXP_FROM_COMP(basecomp, curcomp, curexp) \
2454 (u16)(((u32)(curexp * (u8)(curcomp + 128)) / (u8)(basecomp - 128)))
2455 #endif
2458 int currentexp = params->exposure.coarseExpLo +
2459 params->exposure.coarseExpHi*256;
2460 int startexp;
2461 if (on) {
2462 int cj = params->flickerControl.coarseJump;
2463 params->flickerControl.flickerMode = 1;
2464 params->flickerControl.disabled = 0;
2465 if(params->exposure.expMode != 2)
2466 *command_flags |= COMMAND_SETEXPOSURE;
2467 params->exposure.expMode = 2;
2468 currentexp = currentexp << params->exposure.gain;
2469 params->exposure.gain = 0;
2470 /* round down current exposure to nearest value */
2471 startexp = (currentexp + ROUND_UP_EXP_FOR_FLICKER) / cj;
2472 if(startexp < 1)
2473 startexp = 1;
2474 startexp = (startexp * cj) - 1;
2475 if(FIRMWARE_VERSION(1,2))
2476 while(startexp > MAX_EXP_102)
2477 startexp -= cj;
2478 else
2479 while(startexp > MAX_EXP)
2480 startexp -= cj;
2481 params->exposure.coarseExpLo = startexp & 0xff;
2482 params->exposure.coarseExpHi = startexp >> 8;
2483 if (currentexp > startexp) {
2484 if (currentexp > (2 * startexp))
2485 currentexp = 2 * startexp;
2486 params->exposure.redComp = COMPGAIN (COMP_RED, currentexp, startexp);
2487 params->exposure.green1Comp = COMPGAIN (COMP_GREEN1, currentexp, startexp);
2488 params->exposure.green2Comp = COMPGAIN (COMP_GREEN2, currentexp, startexp);
2489 params->exposure.blueComp = COMPGAIN (COMP_BLUE, currentexp, startexp);
2490 } else {
2491 params->exposure.redComp = COMP_RED;
2492 params->exposure.green1Comp = COMP_GREEN1;
2493 params->exposure.green2Comp = COMP_GREEN2;
2494 params->exposure.blueComp = COMP_BLUE;
2496 if(FIRMWARE_VERSION(1,2))
2497 params->exposure.compMode = 0;
2498 else
2499 params->exposure.compMode = 1;
2501 params->apcor.gain1 = 0x18;
2502 params->apcor.gain2 = 0x18;
2503 params->apcor.gain4 = 0x16;
2504 params->apcor.gain8 = 0x14;
2505 *command_flags |= COMMAND_SETAPCOR;
2506 } else {
2507 params->flickerControl.flickerMode = 0;
2508 params->flickerControl.disabled = 1;
2509 /* Coarse = average of equivalent coarse for each comp channel */
2510 startexp = EXP_FROM_COMP(COMP_RED, params->exposure.redComp, currentexp);
2511 startexp += EXP_FROM_COMP(COMP_GREEN1, params->exposure.green1Comp, currentexp);
2512 startexp += EXP_FROM_COMP(COMP_GREEN2, params->exposure.green2Comp, currentexp);
2513 startexp += EXP_FROM_COMP(COMP_BLUE, params->exposure.blueComp, currentexp);
2514 startexp = startexp >> 2;
2515 while(startexp > MAX_EXP &&
2516 params->exposure.gain < params->exposure.gainMode-1) {
2517 startexp = startexp >> 1;
2518 ++params->exposure.gain;
2520 if(FIRMWARE_VERSION(1,2) && startexp > MAX_EXP_102)
2521 startexp = MAX_EXP_102;
2522 if(startexp > MAX_EXP)
2523 startexp = MAX_EXP;
2524 params->exposure.coarseExpLo = startexp&0xff;
2525 params->exposure.coarseExpHi = startexp >> 8;
2526 params->exposure.redComp = COMP_RED;
2527 params->exposure.green1Comp = COMP_GREEN1;
2528 params->exposure.green2Comp = COMP_GREEN2;
2529 params->exposure.blueComp = COMP_BLUE;
2530 params->exposure.compMode = 1;
2531 *command_flags |= COMMAND_SETEXPOSURE;
2532 params->apcor.gain1 = 0x18;
2533 params->apcor.gain2 = 0x16;
2534 params->apcor.gain4 = 0x24;
2535 params->apcor.gain8 = 0x34;
2536 *command_flags |= COMMAND_SETAPCOR;
2538 params->vlOffset.gain1 = 20;
2539 params->vlOffset.gain2 = 24;
2540 params->vlOffset.gain4 = 26;
2541 params->vlOffset.gain8 = 26;
2542 *command_flags |= COMMAND_SETVLOFFSET;
2543 #undef FIRMWARE_VERSION
2544 #undef EXP_FROM_COMP
2545 #undef COMPGAIN
2548 #define FIRMWARE_VERSION(x,y) (cam->params.version.firmwareVersion == (x) && \
2549 cam->params.version.firmwareRevision == (y))
2550 /* monitor the exposure and adjust the sensor frame rate if needed */
2551 static void monitor_exposure(struct cam_data *cam)
2553 u8 exp_acc, bcomp, gain, coarseL, cmd[8], data[8];
2554 int retval, light_exp, dark_exp, very_dark_exp;
2555 int old_exposure, new_exposure, framerate;
2557 /* get necessary stats and register settings from camera */
2558 /* do_command can't handle this, so do it ourselves */
2559 cmd[0] = CPIA_COMMAND_ReadVPRegs>>8;
2560 cmd[1] = CPIA_COMMAND_ReadVPRegs&0xff;
2561 cmd[2] = 30;
2562 cmd[3] = 4;
2563 cmd[4] = 9;
2564 cmd[5] = 8;
2565 cmd[6] = 8;
2566 cmd[7] = 0;
2567 retval = cam->ops->transferCmd(cam->lowlevel_data, cmd, data);
2568 if (retval) {
2569 LOG("ReadVPRegs(30,4,9,8) - failed, retval=%d\n",
2570 retval);
2571 return;
2573 exp_acc = data[0];
2574 bcomp = data[1];
2575 gain = data[2];
2576 coarseL = data[3];
2578 down(&cam->param_lock);
2579 light_exp = cam->params.colourParams.brightness +
2580 TC - 50 + EXP_ACC_LIGHT;
2581 if(light_exp > 255)
2582 light_exp = 255;
2583 dark_exp = cam->params.colourParams.brightness +
2584 TC - 50 - EXP_ACC_DARK;
2585 if(dark_exp < 0)
2586 dark_exp = 0;
2587 very_dark_exp = dark_exp/2;
2589 old_exposure = cam->params.exposure.coarseExpHi * 256 +
2590 cam->params.exposure.coarseExpLo;
2592 if(!cam->params.flickerControl.disabled) {
2593 /* Flicker control on */
2594 int max_comp = FIRMWARE_VERSION(1,2) ? MAX_COMP : HIGH_COMP_102;
2595 bcomp += 128; /* decode */
2596 if(bcomp >= max_comp && exp_acc < dark_exp) {
2597 /* dark */
2598 if(exp_acc < very_dark_exp) {
2599 /* very dark */
2600 if(cam->exposure_status == EXPOSURE_VERY_DARK)
2601 ++cam->exposure_count;
2602 else {
2603 cam->exposure_status = EXPOSURE_VERY_DARK;
2604 cam->exposure_count = 1;
2606 } else {
2607 /* just dark */
2608 if(cam->exposure_status == EXPOSURE_DARK)
2609 ++cam->exposure_count;
2610 else {
2611 cam->exposure_status = EXPOSURE_DARK;
2612 cam->exposure_count = 1;
2615 } else if(old_exposure <= LOW_EXP || exp_acc > light_exp) {
2616 /* light */
2617 if(old_exposure <= VERY_LOW_EXP) {
2618 /* very light */
2619 if(cam->exposure_status == EXPOSURE_VERY_LIGHT)
2620 ++cam->exposure_count;
2621 else {
2622 cam->exposure_status = EXPOSURE_VERY_LIGHT;
2623 cam->exposure_count = 1;
2625 } else {
2626 /* just light */
2627 if(cam->exposure_status == EXPOSURE_LIGHT)
2628 ++cam->exposure_count;
2629 else {
2630 cam->exposure_status = EXPOSURE_LIGHT;
2631 cam->exposure_count = 1;
2634 } else {
2635 /* not dark or light */
2636 cam->exposure_status = EXPOSURE_NORMAL;
2638 } else {
2639 /* Flicker control off */
2640 if(old_exposure >= MAX_EXP && exp_acc < dark_exp) {
2641 /* dark */
2642 if(exp_acc < very_dark_exp) {
2643 /* very dark */
2644 if(cam->exposure_status == EXPOSURE_VERY_DARK)
2645 ++cam->exposure_count;
2646 else {
2647 cam->exposure_status = EXPOSURE_VERY_DARK;
2648 cam->exposure_count = 1;
2650 } else {
2651 /* just dark */
2652 if(cam->exposure_status == EXPOSURE_DARK)
2653 ++cam->exposure_count;
2654 else {
2655 cam->exposure_status = EXPOSURE_DARK;
2656 cam->exposure_count = 1;
2659 } else if(old_exposure <= LOW_EXP || exp_acc > light_exp) {
2660 /* light */
2661 if(old_exposure <= VERY_LOW_EXP) {
2662 /* very light */
2663 if(cam->exposure_status == EXPOSURE_VERY_LIGHT)
2664 ++cam->exposure_count;
2665 else {
2666 cam->exposure_status = EXPOSURE_VERY_LIGHT;
2667 cam->exposure_count = 1;
2669 } else {
2670 /* just light */
2671 if(cam->exposure_status == EXPOSURE_LIGHT)
2672 ++cam->exposure_count;
2673 else {
2674 cam->exposure_status = EXPOSURE_LIGHT;
2675 cam->exposure_count = 1;
2678 } else {
2679 /* not dark or light */
2680 cam->exposure_status = EXPOSURE_NORMAL;
2684 framerate = cam->fps;
2685 if(framerate > 30 || framerate < 1)
2686 framerate = 1;
2688 if(!cam->params.flickerControl.disabled) {
2689 /* Flicker control on */
2690 if((cam->exposure_status == EXPOSURE_VERY_DARK ||
2691 cam->exposure_status == EXPOSURE_DARK) &&
2692 cam->exposure_count >= DARK_TIME*framerate &&
2693 cam->params.sensorFps.divisor < 3) {
2695 /* dark for too long */
2696 ++cam->params.sensorFps.divisor;
2697 cam->cmd_queue |= COMMAND_SETSENSORFPS;
2699 cam->params.flickerControl.coarseJump =
2700 flicker_jumps[cam->mainsFreq]
2701 [cam->params.sensorFps.baserate]
2702 [cam->params.sensorFps.divisor];
2703 cam->cmd_queue |= COMMAND_SETFLICKERCTRL;
2705 new_exposure = cam->params.flickerControl.coarseJump-1;
2706 while(new_exposure < old_exposure/2)
2707 new_exposure += cam->params.flickerControl.coarseJump;
2708 cam->params.exposure.coarseExpLo = new_exposure & 0xff;
2709 cam->params.exposure.coarseExpHi = new_exposure >> 8;
2710 cam->cmd_queue |= COMMAND_SETEXPOSURE;
2711 cam->exposure_status = EXPOSURE_NORMAL;
2712 LOG("Automatically decreasing sensor_fps\n");
2714 } else if((cam->exposure_status == EXPOSURE_VERY_LIGHT ||
2715 cam->exposure_status == EXPOSURE_LIGHT) &&
2716 cam->exposure_count >= LIGHT_TIME*framerate &&
2717 cam->params.sensorFps.divisor > 0) {
2719 /* light for too long */
2720 int max_exp = FIRMWARE_VERSION(1,2) ? MAX_EXP_102 : MAX_EXP ;
2722 --cam->params.sensorFps.divisor;
2723 cam->cmd_queue |= COMMAND_SETSENSORFPS;
2725 cam->params.flickerControl.coarseJump =
2726 flicker_jumps[cam->mainsFreq]
2727 [cam->params.sensorFps.baserate]
2728 [cam->params.sensorFps.divisor];
2729 cam->cmd_queue |= COMMAND_SETFLICKERCTRL;
2731 new_exposure = cam->params.flickerControl.coarseJump-1;
2732 while(new_exposure < 2*old_exposure &&
2733 new_exposure+
2734 cam->params.flickerControl.coarseJump < max_exp)
2735 new_exposure += cam->params.flickerControl.coarseJump;
2736 cam->params.exposure.coarseExpLo = new_exposure & 0xff;
2737 cam->params.exposure.coarseExpHi = new_exposure >> 8;
2738 cam->cmd_queue |= COMMAND_SETEXPOSURE;
2739 cam->exposure_status = EXPOSURE_NORMAL;
2740 LOG("Automatically increasing sensor_fps\n");
2742 } else {
2743 /* Flicker control off */
2744 if((cam->exposure_status == EXPOSURE_VERY_DARK ||
2745 cam->exposure_status == EXPOSURE_DARK) &&
2746 cam->exposure_count >= DARK_TIME*framerate &&
2747 cam->params.sensorFps.divisor < 3) {
2749 /* dark for too long */
2750 ++cam->params.sensorFps.divisor;
2751 cam->cmd_queue |= COMMAND_SETSENSORFPS;
2753 if(cam->params.exposure.gain > 0) {
2754 --cam->params.exposure.gain;
2755 cam->cmd_queue |= COMMAND_SETEXPOSURE;
2757 cam->exposure_status = EXPOSURE_NORMAL;
2758 LOG("Automatically decreasing sensor_fps\n");
2760 } else if((cam->exposure_status == EXPOSURE_VERY_LIGHT ||
2761 cam->exposure_status == EXPOSURE_LIGHT) &&
2762 cam->exposure_count >= LIGHT_TIME*framerate &&
2763 cam->params.sensorFps.divisor > 0) {
2765 /* light for too long */
2766 --cam->params.sensorFps.divisor;
2767 cam->cmd_queue |= COMMAND_SETSENSORFPS;
2769 if(cam->params.exposure.gain <
2770 cam->params.exposure.gainMode-1) {
2771 ++cam->params.exposure.gain;
2772 cam->cmd_queue |= COMMAND_SETEXPOSURE;
2774 cam->exposure_status = EXPOSURE_NORMAL;
2775 LOG("Automatically increasing sensor_fps\n");
2778 up(&cam->param_lock);
2781 /*-----------------------------------------------------------------*/
2782 /* if flicker is switched off, this function switches it back on.It checks,
2783 however, that conditions are suitable before restarting it.
2784 This should only be called for firmware version 1.2.
2786 It also adjust the colour balance when an exposure step is detected - as
2787 long as flicker is running
2789 static void restart_flicker(struct cam_data *cam)
2791 int cam_exposure, old_exp;
2792 if(!FIRMWARE_VERSION(1,2))
2793 return;
2794 down(&cam->param_lock);
2795 if(cam->params.flickerControl.flickerMode == 0 ||
2796 cam->raw_image[39] == 0) {
2797 up(&cam->param_lock);
2798 return;
2800 cam_exposure = cam->raw_image[39]*2;
2801 old_exp = cam->params.exposure.coarseExpLo +
2802 cam->params.exposure.coarseExpHi*256;
2804 see how far away camera exposure is from a valid
2805 flicker exposure value
2807 cam_exposure %= cam->params.flickerControl.coarseJump;
2808 if(!cam->params.flickerControl.disabled &&
2809 cam_exposure <= cam->params.flickerControl.coarseJump - 3) {
2810 /* Flicker control auto-disabled */
2811 cam->params.flickerControl.disabled = 1;
2814 if(cam->params.flickerControl.disabled &&
2815 cam->params.flickerControl.flickerMode &&
2816 old_exp > cam->params.flickerControl.coarseJump +
2817 ROUND_UP_EXP_FOR_FLICKER) {
2818 /* exposure is now high enough to switch
2819 flicker control back on */
2820 set_flicker(&cam->params, &cam->cmd_queue, 1);
2821 if((cam->cmd_queue & COMMAND_SETEXPOSURE) &&
2822 cam->params.exposure.expMode == 2)
2823 cam->exposure_status = EXPOSURE_NORMAL;
2826 up(&cam->param_lock);
2828 #undef FIRMWARE_VERSION
2830 static int clear_stall(struct cam_data *cam)
2832 /* FIXME: Does this actually work? */
2833 LOG("Clearing stall\n");
2835 cam->ops->streamRead(cam->lowlevel_data, cam->raw_image, 0);
2836 do_command(cam, CPIA_COMMAND_GetCameraStatus,0,0,0,0);
2837 return cam->params.status.streamState != STREAM_PAUSED;
2840 /* kernel thread function to read image from camera */
2841 static int fetch_frame(void *data)
2843 int image_size, retry;
2844 struct cam_data *cam = (struct cam_data *)data;
2845 unsigned long oldjif, rate, diff;
2847 /* Allow up to two bad images in a row to be read and
2848 * ignored before an error is reported */
2849 for (retry = 0; retry < 3; ++retry) {
2850 if (retry)
2851 DBG("retry=%d\n", retry);
2853 if (!cam->ops)
2854 continue;
2856 /* load first frame always uncompressed */
2857 if (cam->first_frame &&
2858 cam->params.compression.mode != CPIA_COMPRESSION_NONE) {
2859 do_command(cam, CPIA_COMMAND_SetCompression,
2860 CPIA_COMPRESSION_NONE,
2861 NO_DECIMATION, 0, 0);
2862 /* Trial & error - Discarding a frame prevents the
2863 first frame from having an error in the data. */
2864 do_command(cam, CPIA_COMMAND_DiscardFrame, 0, 0, 0, 0);
2867 /* init camera upload */
2868 if (do_command(cam, CPIA_COMMAND_GrabFrame, 0,
2869 cam->params.streamStartLine, 0, 0))
2870 continue;
2872 if (cam->ops->wait_for_stream_ready) {
2873 /* loop until image ready */
2874 int count = 0;
2875 do_command(cam, CPIA_COMMAND_GetCameraStatus,0,0,0,0);
2876 while (cam->params.status.streamState != STREAM_READY) {
2877 if(++count > READY_TIMEOUT)
2878 break;
2879 if(cam->params.status.streamState ==
2880 STREAM_PAUSED) {
2881 /* Bad news */
2882 if(!clear_stall(cam))
2883 return -EIO;
2886 cond_resched();
2888 /* sleep for 10 ms, hopefully ;) */
2889 current->state = TASK_INTERRUPTIBLE;
2891 schedule_timeout(10*HZ/1000);
2892 if (signal_pending(current))
2893 return -EINTR;
2895 do_command(cam, CPIA_COMMAND_GetCameraStatus,
2896 0, 0, 0, 0);
2898 if(cam->params.status.streamState != STREAM_READY) {
2899 continue;
2903 cond_resched();
2905 /* grab image from camera */
2906 oldjif = jiffies;
2907 image_size = cam->ops->streamRead(cam->lowlevel_data,
2908 cam->raw_image, 0);
2909 if (image_size <= 0) {
2910 DBG("streamRead failed: %d\n", image_size);
2911 continue;
2914 rate = image_size * HZ / 1024;
2915 diff = jiffies-oldjif;
2916 cam->transfer_rate = diff==0 ? rate : rate/diff;
2917 /* diff==0 ? unlikely but possible */
2919 /* Switch flicker control back on if it got turned off */
2920 restart_flicker(cam);
2922 /* If AEC is enabled, monitor the exposure and
2923 adjust the sensor frame rate if needed */
2924 if(cam->params.exposure.expMode == 2)
2925 monitor_exposure(cam);
2927 /* camera idle now so dispatch queued commands */
2928 dispatch_commands(cam);
2930 /* Update our knowledge of the camera state */
2931 do_command(cam, CPIA_COMMAND_GetColourBalance, 0, 0, 0, 0);
2932 do_command(cam, CPIA_COMMAND_GetExposure, 0, 0, 0, 0);
2933 do_command(cam, CPIA_COMMAND_ReadMCPorts, 0, 0, 0, 0);
2935 /* decompress and convert image to by copying it from
2936 * raw_image to decompressed_frame
2939 cond_resched();
2941 cam->image_size = parse_picture(cam, image_size);
2942 if (cam->image_size <= 0) {
2943 DBG("parse_picture failed %d\n", cam->image_size);
2944 if(cam->params.compression.mode !=
2945 CPIA_COMPRESSION_NONE) {
2946 /* Compression may not work right if we
2947 had a bad frame, get the next one
2948 uncompressed. */
2949 cam->first_frame = 1;
2950 do_command(cam, CPIA_COMMAND_SetGrabMode,
2951 CPIA_GRAB_SINGLE, 0, 0, 0);
2952 /* FIXME: Trial & error - need up to 70ms for
2953 the grab mode change to complete ? */
2954 current->state = TASK_INTERRUPTIBLE;
2955 schedule_timeout(70*HZ / 1000);
2956 if (signal_pending(current))
2957 return -EINTR;
2959 } else
2960 break;
2963 if (retry < 3) {
2964 /* FIXME: this only works for double buffering */
2965 if (cam->frame[cam->curframe].state == FRAME_READY) {
2966 memcpy(cam->frame[cam->curframe].data,
2967 cam->decompressed_frame.data,
2968 cam->decompressed_frame.count);
2969 cam->frame[cam->curframe].state = FRAME_DONE;
2970 } else
2971 cam->decompressed_frame.state = FRAME_DONE;
2973 if (cam->first_frame) {
2974 cam->first_frame = 0;
2975 do_command(cam, CPIA_COMMAND_SetCompression,
2976 cam->params.compression.mode,
2977 cam->params.compression.decimation, 0, 0);
2979 /* Switch from single-grab to continuous grab */
2980 do_command(cam, CPIA_COMMAND_SetGrabMode,
2981 CPIA_GRAB_CONTINUOUS, 0, 0, 0);
2983 return 0;
2985 return -EIO;
2988 static int capture_frame(struct cam_data *cam, struct video_mmap *vm)
2990 if (!cam->frame_buf) {
2991 /* we do lazy allocation */
2992 int err;
2993 if ((err = allocate_frame_buf(cam)))
2994 return err;
2997 cam->curframe = vm->frame;
2998 cam->frame[cam->curframe].state = FRAME_READY;
2999 return fetch_frame(cam);
3002 static int goto_high_power(struct cam_data *cam)
3004 if (do_command(cam, CPIA_COMMAND_GotoHiPower, 0, 0, 0, 0))
3005 return -EIO;
3006 current->state = TASK_INTERRUPTIBLE;
3007 schedule_timeout(40*HZ/1000); /* windows driver does it too */
3008 if(signal_pending(current))
3009 return -EINTR;
3010 if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0))
3011 return -EIO;
3012 if (cam->params.status.systemState == HI_POWER_STATE) {
3013 DBG("camera now in HIGH power state\n");
3014 return 0;
3016 printstatus(cam);
3017 return -EIO;
3020 static int goto_low_power(struct cam_data *cam)
3022 if (do_command(cam, CPIA_COMMAND_GotoLoPower, 0, 0, 0, 0))
3023 return -1;
3024 if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0))
3025 return -1;
3026 if (cam->params.status.systemState == LO_POWER_STATE) {
3027 DBG("camera now in LOW power state\n");
3028 return 0;
3030 printstatus(cam);
3031 return -1;
3034 static void save_camera_state(struct cam_data *cam)
3036 if(!(cam->cmd_queue & COMMAND_SETCOLOURBALANCE))
3037 do_command(cam, CPIA_COMMAND_GetColourBalance, 0, 0, 0, 0);
3038 if(!(cam->cmd_queue & COMMAND_SETEXPOSURE))
3039 do_command(cam, CPIA_COMMAND_GetExposure, 0, 0, 0, 0);
3041 DBG("%d/%d/%d/%d/%d/%d/%d/%d\n",
3042 cam->params.exposure.gain,
3043 cam->params.exposure.fineExp,
3044 cam->params.exposure.coarseExpLo,
3045 cam->params.exposure.coarseExpHi,
3046 cam->params.exposure.redComp,
3047 cam->params.exposure.green1Comp,
3048 cam->params.exposure.green2Comp,
3049 cam->params.exposure.blueComp);
3050 DBG("%d/%d/%d\n",
3051 cam->params.colourBalance.redGain,
3052 cam->params.colourBalance.greenGain,
3053 cam->params.colourBalance.blueGain);
3056 static int set_camera_state(struct cam_data *cam)
3058 cam->cmd_queue = COMMAND_SETCOMPRESSION |
3059 COMMAND_SETCOMPRESSIONTARGET |
3060 COMMAND_SETCOLOURPARAMS |
3061 COMMAND_SETFORMAT |
3062 COMMAND_SETYUVTHRESH |
3063 COMMAND_SETECPTIMING |
3064 COMMAND_SETCOMPRESSIONPARAMS |
3065 COMMAND_SETEXPOSURE |
3066 COMMAND_SETCOLOURBALANCE |
3067 COMMAND_SETSENSORFPS |
3068 COMMAND_SETAPCOR |
3069 COMMAND_SETFLICKERCTRL |
3070 COMMAND_SETVLOFFSET;
3072 do_command(cam, CPIA_COMMAND_SetGrabMode, CPIA_GRAB_SINGLE,0,0,0);
3073 dispatch_commands(cam);
3075 /* Wait 6 frames for the sensor to get all settings and
3076 AEC/ACB to settle */
3077 current->state = TASK_INTERRUPTIBLE;
3078 schedule_timeout((6*(cam->params.sensorFps.baserate ? 33 : 40) *
3079 (1 << cam->params.sensorFps.divisor) + 10) *
3080 HZ / 1000);
3082 if(signal_pending(current))
3083 return -EINTR;
3085 save_camera_state(cam);
3087 return 0;
3090 static void get_version_information(struct cam_data *cam)
3092 /* GetCPIAVersion */
3093 do_command(cam, CPIA_COMMAND_GetCPIAVersion, 0, 0, 0, 0);
3095 /* GetPnPID */
3096 do_command(cam, CPIA_COMMAND_GetPnPID, 0, 0, 0, 0);
3099 /* initialize camera */
3100 static int reset_camera(struct cam_data *cam)
3102 int err;
3103 /* Start the camera in low power mode */
3104 if (goto_low_power(cam)) {
3105 if (cam->params.status.systemState != WARM_BOOT_STATE)
3106 return -ENODEV;
3108 /* FIXME: this is just dirty trial and error */
3109 err = goto_high_power(cam);
3110 if(err)
3111 return err;
3112 do_command(cam, CPIA_COMMAND_DiscardFrame, 0, 0, 0, 0);
3113 if (goto_low_power(cam))
3114 return -ENODEV;
3117 /* procedure described in developer's guide p3-28 */
3119 /* Check the firmware version. */
3120 cam->params.version.firmwareVersion = 0;
3121 get_version_information(cam);
3122 if (cam->params.version.firmwareVersion != 1)
3123 return -ENODEV;
3125 /* A bug in firmware 1-02 limits gainMode to 2 */
3126 if(cam->params.version.firmwareRevision <= 2 &&
3127 cam->params.exposure.gainMode > 2) {
3128 cam->params.exposure.gainMode = 2;
3131 /* set QX3 detected flag */
3132 cam->params.qx3.qx3_detected = (cam->params.pnpID.vendor == 0x0813 &&
3133 cam->params.pnpID.product == 0x0001);
3135 /* The fatal error checking should be done after
3136 * the camera powers up (developer's guide p 3-38) */
3138 /* Set streamState before transition to high power to avoid bug
3139 * in firmware 1-02 */
3140 do_command(cam, CPIA_COMMAND_ModifyCameraStatus, STREAMSTATE, 0,
3141 STREAM_NOT_READY, 0);
3143 /* GotoHiPower */
3144 err = goto_high_power(cam);
3145 if (err)
3146 return err;
3148 /* Check the camera status */
3149 if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0))
3150 return -EIO;
3152 if (cam->params.status.fatalError) {
3153 DBG("fatal_error: %#04x\n",
3154 cam->params.status.fatalError);
3155 DBG("vp_status: %#04x\n",
3156 cam->params.status.vpStatus);
3157 if (cam->params.status.fatalError & ~(COM_FLAG|CPIA_FLAG)) {
3158 /* Fatal error in camera */
3159 return -EIO;
3160 } else if (cam->params.status.fatalError & (COM_FLAG|CPIA_FLAG)) {
3161 /* Firmware 1-02 may do this for parallel port cameras,
3162 * just clear the flags (developer's guide p 3-38) */
3163 do_command(cam, CPIA_COMMAND_ModifyCameraStatus,
3164 FATALERROR, ~(COM_FLAG|CPIA_FLAG), 0, 0);
3168 /* Check the camera status again */
3169 if (cam->params.status.fatalError) {
3170 if (cam->params.status.fatalError)
3171 return -EIO;
3174 /* VPVersion can't be retrieved before the camera is in HiPower,
3175 * so get it here instead of in get_version_information. */
3176 do_command(cam, CPIA_COMMAND_GetVPVersion, 0, 0, 0, 0);
3178 /* set camera to a known state */
3179 return set_camera_state(cam);
3182 static void put_cam(struct cpia_camera_ops* ops)
3184 if (ops->owner)
3185 module_put(ops->owner);
3188 /* ------------------------- V4L interface --------------------- */
3189 static int cpia_open(struct inode *inode, struct file *file)
3191 struct video_device *dev = video_devdata(file);
3192 struct cam_data *cam = dev->priv;
3193 int err;
3195 if (!cam) {
3196 DBG("Internal error, cam_data not found!\n");
3197 return -ENODEV;
3200 if (cam->open_count > 0) {
3201 DBG("Camera already open\n");
3202 return -EBUSY;
3205 if (!try_module_get(cam->ops->owner))
3206 return -ENODEV;
3208 down(&cam->busy_lock);
3209 err = -ENOMEM;
3210 if (!cam->raw_image) {
3211 cam->raw_image = rvmalloc(CPIA_MAX_IMAGE_SIZE);
3212 if (!cam->raw_image)
3213 goto oops;
3216 if (!cam->decompressed_frame.data) {
3217 cam->decompressed_frame.data = rvmalloc(CPIA_MAX_FRAME_SIZE);
3218 if (!cam->decompressed_frame.data)
3219 goto oops;
3222 /* open cpia */
3223 err = -ENODEV;
3224 if (cam->ops->open(cam->lowlevel_data))
3225 goto oops;
3227 /* reset the camera */
3228 if ((err = reset_camera(cam)) != 0) {
3229 cam->ops->close(cam->lowlevel_data);
3230 goto oops;
3233 err = -EINTR;
3234 if(signal_pending(current))
3235 goto oops;
3237 /* Set ownership of /proc/cpia/videoX to current user */
3238 if(cam->proc_entry)
3239 cam->proc_entry->uid = current->uid;
3241 /* set mark for loading first frame uncompressed */
3242 cam->first_frame = 1;
3244 /* init it to something */
3245 cam->mmap_kludge = 0;
3247 ++cam->open_count;
3248 file->private_data = dev;
3249 up(&cam->busy_lock);
3250 return 0;
3252 oops:
3253 if (cam->decompressed_frame.data) {
3254 rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE);
3255 cam->decompressed_frame.data = NULL;
3257 if (cam->raw_image) {
3258 rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
3259 cam->raw_image = NULL;
3261 up(&cam->busy_lock);
3262 put_cam(cam->ops);
3263 return err;
3266 static int cpia_close(struct inode *inode, struct file *file)
3268 struct video_device *dev = file->private_data;
3269 struct cam_data *cam = dev->priv;
3271 if (cam->ops) {
3272 /* Return ownership of /proc/cpia/videoX to root */
3273 if(cam->proc_entry)
3274 cam->proc_entry->uid = 0;
3276 /* save camera state for later open (developers guide ch 3.5.3) */
3277 save_camera_state(cam);
3279 /* GotoLoPower */
3280 goto_low_power(cam);
3282 /* Update the camera status */
3283 do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0);
3285 /* cleanup internal state stuff */
3286 free_frames(cam->frame);
3288 /* close cpia */
3289 cam->ops->close(cam->lowlevel_data);
3291 put_cam(cam->ops);
3294 if (--cam->open_count == 0) {
3295 /* clean up capture-buffers */
3296 if (cam->raw_image) {
3297 rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
3298 cam->raw_image = NULL;
3301 if (cam->decompressed_frame.data) {
3302 rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE);
3303 cam->decompressed_frame.data = NULL;
3306 if (cam->frame_buf)
3307 free_frame_buf(cam);
3309 if (!cam->ops)
3310 kfree(cam);
3312 file->private_data = NULL;
3314 return 0;
3317 static ssize_t cpia_read(struct file *file, char __user *buf,
3318 size_t count, loff_t *ppos)
3320 struct video_device *dev = file->private_data;
3321 struct cam_data *cam = dev->priv;
3322 int err;
3324 /* make this _really_ smp and multithread-safe */
3325 if (down_interruptible(&cam->busy_lock))
3326 return -EINTR;
3328 if (!buf) {
3329 DBG("buf NULL\n");
3330 up(&cam->busy_lock);
3331 return -EINVAL;
3334 if (!count) {
3335 DBG("count 0\n");
3336 up(&cam->busy_lock);
3337 return 0;
3340 if (!cam->ops) {
3341 DBG("ops NULL\n");
3342 up(&cam->busy_lock);
3343 return -ENODEV;
3346 /* upload frame */
3347 cam->decompressed_frame.state = FRAME_READY;
3348 cam->mmap_kludge=0;
3349 if((err = fetch_frame(cam)) != 0) {
3350 DBG("ERROR from fetch_frame: %d\n", err);
3351 up(&cam->busy_lock);
3352 return err;
3354 cam->decompressed_frame.state = FRAME_UNUSED;
3356 /* copy data to user space */
3357 if (cam->decompressed_frame.count > count) {
3358 DBG("count wrong: %d, %lu\n", cam->decompressed_frame.count,
3359 (unsigned long) count);
3360 up(&cam->busy_lock);
3361 return -EFAULT;
3363 if (copy_to_user(buf, cam->decompressed_frame.data,
3364 cam->decompressed_frame.count)) {
3365 DBG("copy_to_user failed\n");
3366 up(&cam->busy_lock);
3367 return -EFAULT;
3370 up(&cam->busy_lock);
3371 return cam->decompressed_frame.count;
3374 static int cpia_do_ioctl(struct inode *inode, struct file *file,
3375 unsigned int ioctlnr, void *arg)
3377 struct video_device *dev = file->private_data;
3378 struct cam_data *cam = dev->priv;
3379 int retval = 0;
3381 if (!cam || !cam->ops)
3382 return -ENODEV;
3384 /* make this _really_ smp-safe */
3385 if (down_interruptible(&cam->busy_lock))
3386 return -EINTR;
3388 //DBG("cpia_ioctl: %u\n", ioctlnr);
3390 switch (ioctlnr) {
3391 /* query capabilites */
3392 case VIDIOCGCAP:
3394 struct video_capability *b = arg;
3396 DBG("VIDIOCGCAP\n");
3397 strcpy(b->name, "CPiA Camera");
3398 b->type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE;
3399 b->channels = 1;
3400 b->audios = 0;
3401 b->maxwidth = 352; /* VIDEOSIZE_CIF */
3402 b->maxheight = 288;
3403 b->minwidth = 48; /* VIDEOSIZE_48_48 */
3404 b->minheight = 48;
3405 break;
3408 /* get/set video source - we are a camera and nothing else */
3409 case VIDIOCGCHAN:
3411 struct video_channel *v = arg;
3413 DBG("VIDIOCGCHAN\n");
3414 if (v->channel != 0) {
3415 retval = -EINVAL;
3416 break;
3419 v->channel = 0;
3420 strcpy(v->name, "Camera");
3421 v->tuners = 0;
3422 v->flags = 0;
3423 v->type = VIDEO_TYPE_CAMERA;
3424 v->norm = 0;
3425 break;
3428 case VIDIOCSCHAN:
3430 struct video_channel *v = arg;
3432 DBG("VIDIOCSCHAN\n");
3433 if (v->channel != 0)
3434 retval = -EINVAL;
3435 break;
3438 /* image properties */
3439 case VIDIOCGPICT:
3441 struct video_picture *pic = arg;
3442 DBG("VIDIOCGPICT\n");
3443 *pic = cam->vp;
3444 break;
3447 case VIDIOCSPICT:
3449 struct video_picture *vp = arg;
3451 DBG("VIDIOCSPICT\n");
3453 /* check validity */
3454 DBG("palette: %d\n", vp->palette);
3455 DBG("depth: %d\n", vp->depth);
3456 if (!valid_mode(vp->palette, vp->depth)) {
3457 retval = -EINVAL;
3458 break;
3461 down(&cam->param_lock);
3462 /* brightness, colour, contrast need no check 0-65535 */
3463 cam->vp = *vp;
3464 /* update cam->params.colourParams */
3465 cam->params.colourParams.brightness = vp->brightness*100/65535;
3466 cam->params.colourParams.contrast = vp->contrast*100/65535;
3467 cam->params.colourParams.saturation = vp->colour*100/65535;
3468 /* contrast is in steps of 8, so round */
3469 cam->params.colourParams.contrast =
3470 ((cam->params.colourParams.contrast + 3) / 8) * 8;
3471 if (cam->params.version.firmwareVersion == 1 &&
3472 cam->params.version.firmwareRevision == 2 &&
3473 cam->params.colourParams.contrast > 80) {
3474 /* 1-02 firmware limits contrast to 80 */
3475 cam->params.colourParams.contrast = 80;
3478 /* Adjust flicker control if necessary */
3479 if(cam->params.flickerControl.allowableOverExposure < 0)
3480 cam->params.flickerControl.allowableOverExposure =
3481 -find_over_exposure(cam->params.colourParams.brightness);
3482 if(cam->params.flickerControl.flickerMode != 0)
3483 cam->cmd_queue |= COMMAND_SETFLICKERCTRL;
3486 /* queue command to update camera */
3487 cam->cmd_queue |= COMMAND_SETCOLOURPARAMS;
3488 up(&cam->param_lock);
3489 DBG("VIDIOCSPICT: %d / %d // %d / %d / %d / %d\n",
3490 vp->depth, vp->palette, vp->brightness, vp->hue, vp->colour,
3491 vp->contrast);
3492 break;
3495 /* get/set capture window */
3496 case VIDIOCGWIN:
3498 struct video_window *vw = arg;
3499 DBG("VIDIOCGWIN\n");
3501 *vw = cam->vw;
3502 break;
3505 case VIDIOCSWIN:
3507 /* copy_from_user, check validity, copy to internal structure */
3508 struct video_window *vw = arg;
3509 DBG("VIDIOCSWIN\n");
3511 if (vw->clipcount != 0) { /* clipping not supported */
3512 retval = -EINVAL;
3513 break;
3515 if (vw->clips != NULL) { /* clipping not supported */
3516 retval = -EINVAL;
3517 break;
3520 /* we set the video window to something smaller or equal to what
3521 * is requested by the user???
3523 down(&cam->param_lock);
3524 if (vw->width != cam->vw.width || vw->height != cam->vw.height) {
3525 int video_size = match_videosize(vw->width, vw->height);
3527 if (video_size < 0) {
3528 retval = -EINVAL;
3529 up(&cam->param_lock);
3530 break;
3532 cam->video_size = video_size;
3534 /* video size is changing, reset the subcapture area */
3535 memset(&cam->vc, 0, sizeof(cam->vc));
3537 set_vw_size(cam);
3538 DBG("%d / %d\n", cam->vw.width, cam->vw.height);
3539 cam->cmd_queue |= COMMAND_SETFORMAT;
3542 up(&cam->param_lock);
3544 /* setformat ignored by camera during streaming,
3545 * so stop/dispatch/start */
3546 if (cam->cmd_queue & COMMAND_SETFORMAT) {
3547 DBG("\n");
3548 dispatch_commands(cam);
3550 DBG("%d/%d:%d\n", cam->video_size,
3551 cam->vw.width, cam->vw.height);
3552 break;
3555 /* mmap interface */
3556 case VIDIOCGMBUF:
3558 struct video_mbuf *vm = arg;
3559 int i;
3561 DBG("VIDIOCGMBUF\n");
3562 memset(vm, 0, sizeof(*vm));
3563 vm->size = CPIA_MAX_FRAME_SIZE*FRAME_NUM;
3564 vm->frames = FRAME_NUM;
3565 for (i = 0; i < FRAME_NUM; i++)
3566 vm->offsets[i] = CPIA_MAX_FRAME_SIZE * i;
3567 break;
3570 case VIDIOCMCAPTURE:
3572 struct video_mmap *vm = arg;
3573 int video_size;
3575 DBG("VIDIOCMCAPTURE: %d / %d / %dx%d\n", vm->format, vm->frame,
3576 vm->width, vm->height);
3577 if (vm->frame<0||vm->frame>=FRAME_NUM) {
3578 retval = -EINVAL;
3579 break;
3582 /* set video format */
3583 cam->vp.palette = vm->format;
3584 switch(vm->format) {
3585 case VIDEO_PALETTE_GREY:
3586 cam->vp.depth=8;
3587 break;
3588 case VIDEO_PALETTE_RGB555:
3589 case VIDEO_PALETTE_RGB565:
3590 case VIDEO_PALETTE_YUV422:
3591 case VIDEO_PALETTE_YUYV:
3592 case VIDEO_PALETTE_UYVY:
3593 cam->vp.depth = 16;
3594 break;
3595 case VIDEO_PALETTE_RGB24:
3596 cam->vp.depth = 24;
3597 break;
3598 case VIDEO_PALETTE_RGB32:
3599 cam->vp.depth = 32;
3600 break;
3601 default:
3602 retval = -EINVAL;
3603 break;
3605 if (retval)
3606 break;
3608 /* set video size */
3609 video_size = match_videosize(vm->width, vm->height);
3610 if (video_size < 0) {
3611 retval = -EINVAL;
3612 break;
3614 if (video_size != cam->video_size) {
3615 cam->video_size = video_size;
3617 /* video size is changing, reset the subcapture area */
3618 memset(&cam->vc, 0, sizeof(cam->vc));
3620 set_vw_size(cam);
3621 cam->cmd_queue |= COMMAND_SETFORMAT;
3622 dispatch_commands(cam);
3624 /* according to v4l-spec we must start streaming here */
3625 cam->mmap_kludge = 1;
3626 retval = capture_frame(cam, vm);
3628 break;
3631 case VIDIOCSYNC:
3633 int *frame = arg;
3635 //DBG("VIDIOCSYNC: %d\n", *frame);
3637 if (*frame<0 || *frame >= FRAME_NUM) {
3638 retval = -EINVAL;
3639 break;
3642 switch (cam->frame[*frame].state) {
3643 case FRAME_UNUSED:
3644 case FRAME_READY:
3645 case FRAME_GRABBING:
3646 DBG("sync to unused frame %d\n", *frame);
3647 retval = -EINVAL;
3648 break;
3650 case FRAME_DONE:
3651 cam->frame[*frame].state = FRAME_UNUSED;
3652 //DBG("VIDIOCSYNC: %d synced\n", *frame);
3653 break;
3655 if (retval == -EINTR) {
3656 /* FIXME - xawtv does not handle this nice */
3657 retval = 0;
3659 break;
3662 case VIDIOCGCAPTURE:
3664 struct video_capture *vc = arg;
3666 DBG("VIDIOCGCAPTURE\n");
3668 *vc = cam->vc;
3670 break;
3673 case VIDIOCSCAPTURE:
3675 struct video_capture *vc = arg;
3677 DBG("VIDIOCSCAPTURE\n");
3679 if (vc->decimation != 0) { /* How should this be used? */
3680 retval = -EINVAL;
3681 break;
3683 if (vc->flags != 0) { /* Even/odd grab not supported */
3684 retval = -EINVAL;
3685 break;
3688 /* Clip to the resolution we can set for the ROI
3689 (every 8 columns and 4 rows) */
3690 vc->x = vc->x & ~(__u32)7;
3691 vc->y = vc->y & ~(__u32)3;
3692 vc->width = vc->width & ~(__u32)7;
3693 vc->height = vc->height & ~(__u32)3;
3695 if(vc->width == 0 || vc->height == 0 ||
3696 vc->x + vc->width > cam->vw.width ||
3697 vc->y + vc->height > cam->vw.height) {
3698 retval = -EINVAL;
3699 break;
3702 DBG("%d,%d/%dx%d\n", vc->x,vc->y,vc->width, vc->height);
3704 down(&cam->param_lock);
3706 cam->vc.x = vc->x;
3707 cam->vc.y = vc->y;
3708 cam->vc.width = vc->width;
3709 cam->vc.height = vc->height;
3711 set_vw_size(cam);
3712 cam->cmd_queue |= COMMAND_SETFORMAT;
3714 up(&cam->param_lock);
3716 /* setformat ignored by camera during streaming,
3717 * so stop/dispatch/start */
3718 dispatch_commands(cam);
3719 break;
3722 case VIDIOCGUNIT:
3724 struct video_unit *vu = arg;
3726 DBG("VIDIOCGUNIT\n");
3728 vu->video = cam->vdev.minor;
3729 vu->vbi = VIDEO_NO_UNIT;
3730 vu->radio = VIDEO_NO_UNIT;
3731 vu->audio = VIDEO_NO_UNIT;
3732 vu->teletext = VIDEO_NO_UNIT;
3734 break;
3738 /* pointless to implement overlay with this camera */
3739 case VIDIOCCAPTURE:
3740 case VIDIOCGFBUF:
3741 case VIDIOCSFBUF:
3742 case VIDIOCKEY:
3743 /* tuner interface - we have none */
3744 case VIDIOCGTUNER:
3745 case VIDIOCSTUNER:
3746 case VIDIOCGFREQ:
3747 case VIDIOCSFREQ:
3748 /* audio interface - we have none */
3749 case VIDIOCGAUDIO:
3750 case VIDIOCSAUDIO:
3751 retval = -EINVAL;
3752 break;
3753 default:
3754 retval = -ENOIOCTLCMD;
3755 break;
3758 up(&cam->busy_lock);
3759 return retval;
3762 static int cpia_ioctl(struct inode *inode, struct file *file,
3763 unsigned int cmd, unsigned long arg)
3765 return video_usercopy(inode, file, cmd, arg, cpia_do_ioctl);
3769 /* FIXME */
3770 static int cpia_mmap(struct file *file, struct vm_area_struct *vma)
3772 struct video_device *dev = file->private_data;
3773 unsigned long start = vma->vm_start;
3774 unsigned long size = vma->vm_end - vma->vm_start;
3775 unsigned long page, pos;
3776 struct cam_data *cam = dev->priv;
3777 int retval;
3779 if (!cam || !cam->ops)
3780 return -ENODEV;
3782 DBG("cpia_mmap: %ld\n", size);
3784 if (size > FRAME_NUM*CPIA_MAX_FRAME_SIZE)
3785 return -EINVAL;
3787 if (!cam || !cam->ops)
3788 return -ENODEV;
3790 /* make this _really_ smp-safe */
3791 if (down_interruptible(&cam->busy_lock))
3792 return -EINTR;
3794 if (!cam->frame_buf) { /* we do lazy allocation */
3795 if ((retval = allocate_frame_buf(cam))) {
3796 up(&cam->busy_lock);
3797 return retval;
3801 pos = (unsigned long)(cam->frame_buf);
3802 while (size > 0) {
3803 page = kvirt_to_pa(pos);
3804 if (remap_page_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
3805 up(&cam->busy_lock);
3806 return -EAGAIN;
3808 start += PAGE_SIZE;
3809 pos += PAGE_SIZE;
3810 if (size > PAGE_SIZE)
3811 size -= PAGE_SIZE;
3812 else
3813 size = 0;
3816 DBG("cpia_mmap: %ld\n", size);
3817 up(&cam->busy_lock);
3819 return 0;
3822 static struct file_operations cpia_fops = {
3823 .owner = THIS_MODULE,
3824 .open = cpia_open,
3825 .release = cpia_close,
3826 .read = cpia_read,
3827 .mmap = cpia_mmap,
3828 .ioctl = cpia_ioctl,
3829 .llseek = no_llseek,
3832 static struct video_device cpia_template = {
3833 .owner = THIS_MODULE,
3834 .name = "CPiA Camera",
3835 .type = VID_TYPE_CAPTURE,
3836 .hardware = VID_HARDWARE_CPIA,
3837 .fops = &cpia_fops,
3840 /* initialise cam_data structure */
3841 static void reset_camera_struct(struct cam_data *cam)
3843 /* The following parameter values are the defaults from
3844 * "Software Developer's Guide for CPiA Cameras". Any changes
3845 * to the defaults are noted in comments. */
3846 cam->params.colourParams.brightness = 50;
3847 cam->params.colourParams.contrast = 48;
3848 cam->params.colourParams.saturation = 50;
3849 cam->params.exposure.gainMode = 4;
3850 cam->params.exposure.expMode = 2; /* AEC */
3851 cam->params.exposure.compMode = 1;
3852 cam->params.exposure.centreWeight = 1;
3853 cam->params.exposure.gain = 0;
3854 cam->params.exposure.fineExp = 0;
3855 cam->params.exposure.coarseExpLo = 185;
3856 cam->params.exposure.coarseExpHi = 0;
3857 cam->params.exposure.redComp = COMP_RED;
3858 cam->params.exposure.green1Comp = COMP_GREEN1;
3859 cam->params.exposure.green2Comp = COMP_GREEN2;
3860 cam->params.exposure.blueComp = COMP_BLUE;
3861 cam->params.colourBalance.balanceMode = 2; /* ACB */
3862 cam->params.colourBalance.redGain = 32;
3863 cam->params.colourBalance.greenGain = 6;
3864 cam->params.colourBalance.blueGain = 92;
3865 cam->params.apcor.gain1 = 0x18;
3866 cam->params.apcor.gain2 = 0x16;
3867 cam->params.apcor.gain4 = 0x24;
3868 cam->params.apcor.gain8 = 0x34;
3869 cam->params.flickerControl.flickerMode = 0;
3870 cam->params.flickerControl.disabled = 1;
3872 cam->params.flickerControl.coarseJump =
3873 flicker_jumps[cam->mainsFreq]
3874 [cam->params.sensorFps.baserate]
3875 [cam->params.sensorFps.divisor];
3876 cam->params.flickerControl.allowableOverExposure =
3877 -find_over_exposure(cam->params.colourParams.brightness);
3878 cam->params.vlOffset.gain1 = 20;
3879 cam->params.vlOffset.gain2 = 24;
3880 cam->params.vlOffset.gain4 = 26;
3881 cam->params.vlOffset.gain8 = 26;
3882 cam->params.compressionParams.hysteresis = 3;
3883 cam->params.compressionParams.threshMax = 11;
3884 cam->params.compressionParams.smallStep = 1;
3885 cam->params.compressionParams.largeStep = 3;
3886 cam->params.compressionParams.decimationHysteresis = 2;
3887 cam->params.compressionParams.frDiffStepThresh = 5;
3888 cam->params.compressionParams.qDiffStepThresh = 3;
3889 cam->params.compressionParams.decimationThreshMod = 2;
3890 /* End of default values from Software Developer's Guide */
3892 cam->transfer_rate = 0;
3893 cam->exposure_status = EXPOSURE_NORMAL;
3895 /* Set Sensor FPS to 15fps. This seems better than 30fps
3896 * for indoor lighting. */
3897 cam->params.sensorFps.divisor = 1;
3898 cam->params.sensorFps.baserate = 1;
3900 cam->params.yuvThreshold.yThreshold = 6; /* From windows driver */
3901 cam->params.yuvThreshold.uvThreshold = 6; /* From windows driver */
3903 cam->params.format.subSample = SUBSAMPLE_422;
3904 cam->params.format.yuvOrder = YUVORDER_YUYV;
3906 cam->params.compression.mode = CPIA_COMPRESSION_AUTO;
3907 cam->params.compressionTarget.frTargeting =
3908 CPIA_COMPRESSION_TARGET_QUALITY;
3909 cam->params.compressionTarget.targetFR = 15; /* From windows driver */
3910 cam->params.compressionTarget.targetQ = 5; /* From windows driver */
3912 cam->params.qx3.qx3_detected = 0;
3913 cam->params.qx3.toplight = 0;
3914 cam->params.qx3.bottomlight = 0;
3915 cam->params.qx3.button = 0;
3916 cam->params.qx3.cradled = 0;
3918 cam->video_size = VIDEOSIZE_CIF;
3920 cam->vp.colour = 32768; /* 50% */
3921 cam->vp.hue = 32768; /* 50% */
3922 cam->vp.brightness = 32768; /* 50% */
3923 cam->vp.contrast = 32768; /* 50% */
3924 cam->vp.whiteness = 0; /* not used -> grayscale only */
3925 cam->vp.depth = 24; /* to be set by user */
3926 cam->vp.palette = VIDEO_PALETTE_RGB24; /* to be set by user */
3928 cam->vc.x = 0;
3929 cam->vc.y = 0;
3930 cam->vc.width = 0;
3931 cam->vc.height = 0;
3933 cam->vw.x = 0;
3934 cam->vw.y = 0;
3935 set_vw_size(cam);
3936 cam->vw.chromakey = 0;
3937 cam->vw.flags = 0;
3938 cam->vw.clipcount = 0;
3939 cam->vw.clips = NULL;
3941 cam->cmd_queue = COMMAND_NONE;
3942 cam->first_frame = 1;
3944 return;
3947 /* initialize cam_data structure */
3948 static void init_camera_struct(struct cam_data *cam,
3949 struct cpia_camera_ops *ops )
3951 int i;
3953 /* Default everything to 0 */
3954 memset(cam, 0, sizeof(struct cam_data));
3956 cam->ops = ops;
3957 init_MUTEX(&cam->param_lock);
3958 init_MUTEX(&cam->busy_lock);
3960 reset_camera_struct(cam);
3962 cam->proc_entry = NULL;
3964 memcpy(&cam->vdev, &cpia_template, sizeof(cpia_template));
3965 cam->vdev.priv = cam;
3967 cam->curframe = 0;
3968 for (i = 0; i < FRAME_NUM; i++) {
3969 cam->frame[i].width = 0;
3970 cam->frame[i].height = 0;
3971 cam->frame[i].state = FRAME_UNUSED;
3972 cam->frame[i].data = NULL;
3974 cam->decompressed_frame.width = 0;
3975 cam->decompressed_frame.height = 0;
3976 cam->decompressed_frame.state = FRAME_UNUSED;
3977 cam->decompressed_frame.data = NULL;
3980 struct cam_data *cpia_register_camera(struct cpia_camera_ops *ops, void *lowlevel)
3982 struct cam_data *camera;
3984 if ((camera = kmalloc(sizeof(struct cam_data), GFP_KERNEL)) == NULL)
3985 return NULL;
3988 init_camera_struct( camera, ops );
3989 camera->lowlevel_data = lowlevel;
3991 /* register v4l device */
3992 if (video_register_device(&camera->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
3993 kfree(camera);
3994 printk(KERN_DEBUG "video_register_device failed\n");
3995 return NULL;
3998 /* get version information from camera: open/reset/close */
4000 /* open cpia */
4001 if (camera->ops->open(camera->lowlevel_data))
4002 return camera;
4004 /* reset the camera */
4005 if (reset_camera(camera) != 0) {
4006 camera->ops->close(camera->lowlevel_data);
4007 return camera;
4010 /* close cpia */
4011 camera->ops->close(camera->lowlevel_data);
4013 #ifdef CONFIG_PROC_FS
4014 create_proc_cpia_cam(camera);
4015 #endif
4017 printk(KERN_INFO " CPiA Version: %d.%02d (%d.%d)\n",
4018 camera->params.version.firmwareVersion,
4019 camera->params.version.firmwareRevision,
4020 camera->params.version.vcVersion,
4021 camera->params.version.vcRevision);
4022 printk(KERN_INFO " CPiA PnP-ID: %04x:%04x:%04x\n",
4023 camera->params.pnpID.vendor,
4024 camera->params.pnpID.product,
4025 camera->params.pnpID.deviceRevision);
4026 printk(KERN_INFO " VP-Version: %d.%d %04x\n",
4027 camera->params.vpVersion.vpVersion,
4028 camera->params.vpVersion.vpRevision,
4029 camera->params.vpVersion.cameraHeadID);
4031 return camera;
4034 void cpia_unregister_camera(struct cam_data *cam)
4036 DBG("unregistering video\n");
4037 video_unregister_device(&cam->vdev);
4038 if (cam->open_count) {
4039 put_cam(cam->ops);
4040 DBG("camera open -- setting ops to NULL\n");
4041 cam->ops = NULL;
4044 #ifdef CONFIG_PROC_FS
4045 DBG("destroying /proc/cpia/video%d\n", cam->vdev.minor);
4046 destroy_proc_cpia_cam(cam);
4047 #endif
4048 if (!cam->open_count) {
4049 DBG("freeing camera\n");
4050 kfree(cam);
4054 static int __init cpia_init(void)
4056 printk(KERN_INFO "%s v%d.%d.%d\n", ABOUT,
4057 CPIA_MAJ_VER, CPIA_MIN_VER, CPIA_PATCH_VER);
4059 printk(KERN_WARNING "Since in-kernel colorspace conversion is not "
4060 "allowed, it is disabled by default now. Users should fix the "
4061 "applications in case they don't work without conversion "
4062 "reenabled by setting the 'colorspace_conv' module "
4063 "parameter to 1");
4065 #ifdef CONFIG_PROC_FS
4066 proc_cpia_create();
4067 #endif
4069 #ifdef CONFIG_KMOD
4070 #ifdef CONFIG_VIDEO_CPIA_PP_MODULE
4071 request_module("cpia_pp");
4072 #endif
4074 #ifdef CONFIG_VIDEO_CPIA_USB_MODULE
4075 request_module("cpia_usb");
4076 #endif
4077 #endif /* CONFIG_KMOD */
4079 #ifdef CONFIG_VIDEO_CPIA_PP
4080 cpia_pp_init();
4081 #endif
4082 #ifdef CONFIG_VIDEO_CPIA_USB
4083 cpia_usb_init();
4084 #endif
4085 return 0;
4088 static void __exit cpia_exit(void)
4090 #ifdef CONFIG_PROC_FS
4091 proc_cpia_destroy();
4092 #endif
4095 module_init(cpia_init);
4096 module_exit(cpia_exit);
4098 /* Exported symbols for modules. */
4100 EXPORT_SYMBOL(cpia_register_camera);
4101 EXPORT_SYMBOL(cpia_unregister_camera);