allow coexistance of N build and AC build.
[tomato.git] / release / src-rt-6.x / linux / linux-2.6 / drivers / media / video / cpia.c
blob78c9699eafbbe46e791cc7c228c413b47182394c
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 */
30 #include <linux/module.h>
31 #include <linux/moduleparam.h>
32 #include <linux/init.h>
33 #include <linux/fs.h>
34 #include <linux/vmalloc.h>
35 #include <linux/slab.h>
36 #include <linux/proc_fs.h>
37 #include <linux/ctype.h>
38 #include <linux/pagemap.h>
39 #include <linux/delay.h>
40 #include <asm/io.h>
41 #include <linux/mutex.h>
43 #ifdef CONFIG_KMOD
44 #include <linux/kmod.h>
45 #endif
47 #include "cpia.h"
49 static int video_nr = -1;
51 #ifdef MODULE
52 module_param(video_nr, int, 0);
53 MODULE_AUTHOR("Scott J. Bertin <sbertin@securenym.net> & Peter Pregler <Peter_Pregler@email.com> & Johannes Erdfelt <johannes@erdfelt.com>");
54 MODULE_DESCRIPTION("V4L-driver for Vision CPiA based cameras");
55 MODULE_LICENSE("GPL");
56 MODULE_SUPPORTED_DEVICE("video");
57 #endif
59 static unsigned short colorspace_conv;
60 module_param(colorspace_conv, ushort, 0444);
61 MODULE_PARM_DESC(colorspace_conv,
62 " Colorspace conversion:"
63 "\n 0 = disable, 1 = enable"
64 "\n Default value is 0"
67 #define ABOUT "V4L-Driver for Vision CPiA based cameras"
69 #ifndef VID_HARDWARE_CPIA
70 #define VID_HARDWARE_CPIA 24 /* FIXME -> from linux/videodev.h */
71 #endif
73 #define CPIA_MODULE_CPIA (0<<5)
74 #define CPIA_MODULE_SYSTEM (1<<5)
75 #define CPIA_MODULE_VP_CTRL (5<<5)
76 #define CPIA_MODULE_CAPTURE (6<<5)
77 #define CPIA_MODULE_DEBUG (7<<5)
79 #define INPUT (DATA_IN << 8)
80 #define OUTPUT (DATA_OUT << 8)
82 #define CPIA_COMMAND_GetCPIAVersion (INPUT | CPIA_MODULE_CPIA | 1)
83 #define CPIA_COMMAND_GetPnPID (INPUT | CPIA_MODULE_CPIA | 2)
84 #define CPIA_COMMAND_GetCameraStatus (INPUT | CPIA_MODULE_CPIA | 3)
85 #define CPIA_COMMAND_GotoHiPower (OUTPUT | CPIA_MODULE_CPIA | 4)
86 #define CPIA_COMMAND_GotoLoPower (OUTPUT | CPIA_MODULE_CPIA | 5)
87 #define CPIA_COMMAND_GotoSuspend (OUTPUT | CPIA_MODULE_CPIA | 7)
88 #define CPIA_COMMAND_GotoPassThrough (OUTPUT | CPIA_MODULE_CPIA | 8)
89 #define CPIA_COMMAND_ModifyCameraStatus (OUTPUT | CPIA_MODULE_CPIA | 10)
91 #define CPIA_COMMAND_ReadVCRegs (INPUT | CPIA_MODULE_SYSTEM | 1)
92 #define CPIA_COMMAND_WriteVCReg (OUTPUT | CPIA_MODULE_SYSTEM | 2)
93 #define CPIA_COMMAND_ReadMCPorts (INPUT | CPIA_MODULE_SYSTEM | 3)
94 #define CPIA_COMMAND_WriteMCPort (OUTPUT | CPIA_MODULE_SYSTEM | 4)
95 #define CPIA_COMMAND_SetBaudRate (OUTPUT | CPIA_MODULE_SYSTEM | 5)
96 #define CPIA_COMMAND_SetECPTiming (OUTPUT | CPIA_MODULE_SYSTEM | 6)
97 #define CPIA_COMMAND_ReadIDATA (INPUT | CPIA_MODULE_SYSTEM | 7)
98 #define CPIA_COMMAND_WriteIDATA (OUTPUT | CPIA_MODULE_SYSTEM | 8)
99 #define CPIA_COMMAND_GenericCall (OUTPUT | CPIA_MODULE_SYSTEM | 9)
100 #define CPIA_COMMAND_I2CStart (OUTPUT | CPIA_MODULE_SYSTEM | 10)
101 #define CPIA_COMMAND_I2CStop (OUTPUT | CPIA_MODULE_SYSTEM | 11)
102 #define CPIA_COMMAND_I2CWrite (OUTPUT | CPIA_MODULE_SYSTEM | 12)
103 #define CPIA_COMMAND_I2CRead (INPUT | CPIA_MODULE_SYSTEM | 13)
105 #define CPIA_COMMAND_GetVPVersion (INPUT | CPIA_MODULE_VP_CTRL | 1)
106 #define CPIA_COMMAND_ResetFrameCounter (INPUT | CPIA_MODULE_VP_CTRL | 2)
107 #define CPIA_COMMAND_SetColourParams (OUTPUT | CPIA_MODULE_VP_CTRL | 3)
108 #define CPIA_COMMAND_SetExposure (OUTPUT | CPIA_MODULE_VP_CTRL | 4)
109 #define CPIA_COMMAND_SetColourBalance (OUTPUT | CPIA_MODULE_VP_CTRL | 6)
110 #define CPIA_COMMAND_SetSensorFPS (OUTPUT | CPIA_MODULE_VP_CTRL | 7)
111 #define CPIA_COMMAND_SetVPDefaults (OUTPUT | CPIA_MODULE_VP_CTRL | 8)
112 #define CPIA_COMMAND_SetApcor (OUTPUT | CPIA_MODULE_VP_CTRL | 9)
113 #define CPIA_COMMAND_SetFlickerCtrl (OUTPUT | CPIA_MODULE_VP_CTRL | 10)
114 #define CPIA_COMMAND_SetVLOffset (OUTPUT | CPIA_MODULE_VP_CTRL | 11)
115 #define CPIA_COMMAND_GetColourParams (INPUT | CPIA_MODULE_VP_CTRL | 16)
116 #define CPIA_COMMAND_GetColourBalance (INPUT | CPIA_MODULE_VP_CTRL | 17)
117 #define CPIA_COMMAND_GetExposure (INPUT | CPIA_MODULE_VP_CTRL | 18)
118 #define CPIA_COMMAND_SetSensorMatrix (OUTPUT | CPIA_MODULE_VP_CTRL | 19)
119 #define CPIA_COMMAND_ColourBars (OUTPUT | CPIA_MODULE_VP_CTRL | 25)
120 #define CPIA_COMMAND_ReadVPRegs (INPUT | CPIA_MODULE_VP_CTRL | 30)
121 #define CPIA_COMMAND_WriteVPReg (OUTPUT | CPIA_MODULE_VP_CTRL | 31)
123 #define CPIA_COMMAND_GrabFrame (OUTPUT | CPIA_MODULE_CAPTURE | 1)
124 #define CPIA_COMMAND_UploadFrame (OUTPUT | CPIA_MODULE_CAPTURE | 2)
125 #define CPIA_COMMAND_SetGrabMode (OUTPUT | CPIA_MODULE_CAPTURE | 3)
126 #define CPIA_COMMAND_InitStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 4)
127 #define CPIA_COMMAND_FiniStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 5)
128 #define CPIA_COMMAND_StartStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 6)
129 #define CPIA_COMMAND_EndStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 7)
130 #define CPIA_COMMAND_SetFormat (OUTPUT | CPIA_MODULE_CAPTURE | 8)
131 #define CPIA_COMMAND_SetROI (OUTPUT | CPIA_MODULE_CAPTURE | 9)
132 #define CPIA_COMMAND_SetCompression (OUTPUT | CPIA_MODULE_CAPTURE | 10)
133 #define CPIA_COMMAND_SetCompressionTarget (OUTPUT | CPIA_MODULE_CAPTURE | 11)
134 #define CPIA_COMMAND_SetYUVThresh (OUTPUT | CPIA_MODULE_CAPTURE | 12)
135 #define CPIA_COMMAND_SetCompressionParams (OUTPUT | CPIA_MODULE_CAPTURE | 13)
136 #define CPIA_COMMAND_DiscardFrame (OUTPUT | CPIA_MODULE_CAPTURE | 14)
137 #define CPIA_COMMAND_GrabReset (OUTPUT | CPIA_MODULE_CAPTURE | 15)
139 #define CPIA_COMMAND_OutputRS232 (OUTPUT | CPIA_MODULE_DEBUG | 1)
140 #define CPIA_COMMAND_AbortProcess (OUTPUT | CPIA_MODULE_DEBUG | 4)
141 #define CPIA_COMMAND_SetDramPage (OUTPUT | CPIA_MODULE_DEBUG | 5)
142 #define CPIA_COMMAND_StartDramUpload (OUTPUT | CPIA_MODULE_DEBUG | 6)
143 #define CPIA_COMMAND_StartDummyDtream (OUTPUT | CPIA_MODULE_DEBUG | 8)
144 #define CPIA_COMMAND_AbortStream (OUTPUT | CPIA_MODULE_DEBUG | 9)
145 #define CPIA_COMMAND_DownloadDRAM (OUTPUT | CPIA_MODULE_DEBUG | 10)
146 #define CPIA_COMMAND_Null (OUTPUT | CPIA_MODULE_DEBUG | 11)
148 enum {
149 FRAME_READY, /* Ready to grab into */
150 FRAME_GRABBING, /* In the process of being grabbed into */
151 FRAME_DONE, /* Finished grabbing, but not been synced yet */
152 FRAME_UNUSED, /* Unused (no MCAPTURE) */
155 #define COMMAND_NONE 0x0000
156 #define COMMAND_SETCOMPRESSION 0x0001
157 #define COMMAND_SETCOMPRESSIONTARGET 0x0002
158 #define COMMAND_SETCOLOURPARAMS 0x0004
159 #define COMMAND_SETFORMAT 0x0008
160 #define COMMAND_PAUSE 0x0010
161 #define COMMAND_RESUME 0x0020
162 #define COMMAND_SETYUVTHRESH 0x0040
163 #define COMMAND_SETECPTIMING 0x0080
164 #define COMMAND_SETCOMPRESSIONPARAMS 0x0100
165 #define COMMAND_SETEXPOSURE 0x0200
166 #define COMMAND_SETCOLOURBALANCE 0x0400
167 #define COMMAND_SETSENSORFPS 0x0800
168 #define COMMAND_SETAPCOR 0x1000
169 #define COMMAND_SETFLICKERCTRL 0x2000
170 #define COMMAND_SETVLOFFSET 0x4000
171 #define COMMAND_SETLIGHTS 0x8000
173 #define ROUND_UP_EXP_FOR_FLICKER 15
175 /* Constants for automatic frame rate adjustment */
176 #define MAX_EXP 302
177 #define MAX_EXP_102 255
178 #define LOW_EXP 140
179 #define VERY_LOW_EXP 70
180 #define TC 94
181 #define EXP_ACC_DARK 50
182 #define EXP_ACC_LIGHT 90
183 #define HIGH_COMP_102 160
184 #define MAX_COMP 239
185 #define DARK_TIME 3
186 #define LIGHT_TIME 3
188 /* Maximum number of 10ms loops to wait for the stream to become ready */
189 #define READY_TIMEOUT 100
191 /* Developer's Guide Table 5 p 3-34
192 * indexed by [mains][sensorFps.baserate][sensorFps.divisor]*/
193 static u8 flicker_jumps[2][2][4] =
194 { { { 76, 38, 19, 9 }, { 92, 46, 23, 11 } },
195 { { 64, 32, 16, 8 }, { 76, 38, 19, 9} }
198 /* forward declaration of local function */
199 static void reset_camera_struct(struct cam_data *cam);
200 static int find_over_exposure(int brightness);
201 static void set_flicker(struct cam_params *params, volatile u32 *command_flags,
202 int on);
205 /**********************************************************************
207 * Memory management
209 **********************************************************************/
210 static void *rvmalloc(unsigned long size)
212 void *mem;
213 unsigned long adr;
215 size = PAGE_ALIGN(size);
216 mem = vmalloc_32(size);
217 if (!mem)
218 return NULL;
220 memset(mem, 0, size); /* Clear the ram out, no junk to the user */
221 adr = (unsigned long) mem;
222 while (size > 0) {
223 SetPageReserved(vmalloc_to_page((void *)adr));
224 adr += PAGE_SIZE;
225 size -= PAGE_SIZE;
228 return mem;
231 static void rvfree(void *mem, unsigned long size)
233 unsigned long adr;
235 if (!mem)
236 return;
238 adr = (unsigned long) mem;
239 while ((long) size > 0) {
240 ClearPageReserved(vmalloc_to_page((void *)adr));
241 adr += PAGE_SIZE;
242 size -= PAGE_SIZE;
244 vfree(mem);
247 /**********************************************************************
249 * /proc interface
251 **********************************************************************/
252 #ifdef CONFIG_PROC_FS
253 static struct proc_dir_entry *cpia_proc_root=NULL;
255 static int cpia_read_proc(char *page, char **start, off_t off,
256 int count, int *eof, void *data)
258 char *out = page;
259 int len, tmp;
260 struct cam_data *cam = data;
261 char tmpstr[29];
263 /* IMPORTANT: This output MUST be kept under PAGE_SIZE
264 * or we need to get more sophisticated. */
266 out += sprintf(out, "read-only\n-----------------------\n");
267 out += sprintf(out, "V4L Driver version: %d.%d.%d\n",
268 CPIA_MAJ_VER, CPIA_MIN_VER, CPIA_PATCH_VER);
269 out += sprintf(out, "CPIA Version: %d.%02d (%d.%d)\n",
270 cam->params.version.firmwareVersion,
271 cam->params.version.firmwareRevision,
272 cam->params.version.vcVersion,
273 cam->params.version.vcRevision);
274 out += sprintf(out, "CPIA PnP-ID: %04x:%04x:%04x\n",
275 cam->params.pnpID.vendor, cam->params.pnpID.product,
276 cam->params.pnpID.deviceRevision);
277 out += sprintf(out, "VP-Version: %d.%d %04x\n",
278 cam->params.vpVersion.vpVersion,
279 cam->params.vpVersion.vpRevision,
280 cam->params.vpVersion.cameraHeadID);
282 out += sprintf(out, "system_state: %#04x\n",
283 cam->params.status.systemState);
284 out += sprintf(out, "grab_state: %#04x\n",
285 cam->params.status.grabState);
286 out += sprintf(out, "stream_state: %#04x\n",
287 cam->params.status.streamState);
288 out += sprintf(out, "fatal_error: %#04x\n",
289 cam->params.status.fatalError);
290 out += sprintf(out, "cmd_error: %#04x\n",
291 cam->params.status.cmdError);
292 out += sprintf(out, "debug_flags: %#04x\n",
293 cam->params.status.debugFlags);
294 out += sprintf(out, "vp_status: %#04x\n",
295 cam->params.status.vpStatus);
296 out += sprintf(out, "error_code: %#04x\n",
297 cam->params.status.errorCode);
298 /* QX3 specific entries */
299 if (cam->params.qx3.qx3_detected) {
300 out += sprintf(out, "button: %4d\n",
301 cam->params.qx3.button);
302 out += sprintf(out, "cradled: %4d\n",
303 cam->params.qx3.cradled);
305 out += sprintf(out, "video_size: %s\n",
306 cam->params.format.videoSize == VIDEOSIZE_CIF ?
307 "CIF " : "QCIF");
308 out += sprintf(out, "roi: (%3d, %3d) to (%3d, %3d)\n",
309 cam->params.roi.colStart*8,
310 cam->params.roi.rowStart*4,
311 cam->params.roi.colEnd*8,
312 cam->params.roi.rowEnd*4);
313 out += sprintf(out, "actual_fps: %3d\n", cam->fps);
314 out += sprintf(out, "transfer_rate: %4dkB/s\n",
315 cam->transfer_rate);
317 out += sprintf(out, "\nread-write\n");
318 out += sprintf(out, "----------------------- current min"
319 " max default comment\n");
320 out += sprintf(out, "brightness: %8d %8d %8d %8d\n",
321 cam->params.colourParams.brightness, 0, 100, 50);
322 if (cam->params.version.firmwareVersion == 1 &&
323 cam->params.version.firmwareRevision == 2)
324 /* 1-02 firmware limits contrast to 80 */
325 tmp = 80;
326 else
327 tmp = 96;
329 out += sprintf(out, "contrast: %8d %8d %8d %8d"
330 " steps of 8\n",
331 cam->params.colourParams.contrast, 0, tmp, 48);
332 out += sprintf(out, "saturation: %8d %8d %8d %8d\n",
333 cam->params.colourParams.saturation, 0, 100, 50);
334 tmp = (25000+5000*cam->params.sensorFps.baserate)/
335 (1<<cam->params.sensorFps.divisor);
336 out += sprintf(out, "sensor_fps: %4d.%03d %8d %8d %8d\n",
337 tmp/1000, tmp%1000, 3, 30, 15);
338 out += sprintf(out, "stream_start_line: %8d %8d %8d %8d\n",
339 2*cam->params.streamStartLine, 0,
340 cam->params.format.videoSize == VIDEOSIZE_CIF ? 288:144,
341 cam->params.format.videoSize == VIDEOSIZE_CIF ? 240:120);
342 out += sprintf(out, "sub_sample: %8s %8s %8s %8s\n",
343 cam->params.format.subSample == SUBSAMPLE_420 ?
344 "420" : "422", "420", "422", "422");
345 out += sprintf(out, "yuv_order: %8s %8s %8s %8s\n",
346 cam->params.format.yuvOrder == YUVORDER_YUYV ?
347 "YUYV" : "UYVY", "YUYV" , "UYVY", "YUYV");
348 out += sprintf(out, "ecp_timing: %8s %8s %8s %8s\n",
349 cam->params.ecpTiming ? "slow" : "normal", "slow",
350 "normal", "normal");
352 if (cam->params.colourBalance.balanceMode == 2) {
353 sprintf(tmpstr, "auto");
354 } else {
355 sprintf(tmpstr, "manual");
357 out += sprintf(out, "color_balance_mode: %8s %8s %8s"
358 " %8s\n", tmpstr, "manual", "auto", "auto");
359 out += sprintf(out, "red_gain: %8d %8d %8d %8d\n",
360 cam->params.colourBalance.redGain, 0, 212, 32);
361 out += sprintf(out, "green_gain: %8d %8d %8d %8d\n",
362 cam->params.colourBalance.greenGain, 0, 212, 6);
363 out += sprintf(out, "blue_gain: %8d %8d %8d %8d\n",
364 cam->params.colourBalance.blueGain, 0, 212, 92);
366 if (cam->params.version.firmwareVersion == 1 &&
367 cam->params.version.firmwareRevision == 2)
368 /* 1-02 firmware limits gain to 2 */
369 sprintf(tmpstr, "%8d %8d %8d", 1, 2, 2);
370 else
371 sprintf(tmpstr, "%8d %8d %8d", 1, 8, 2);
373 if (cam->params.exposure.gainMode == 0)
374 out += sprintf(out, "max_gain: unknown %28s"
375 " powers of 2\n", tmpstr);
376 else
377 out += sprintf(out, "max_gain: %8d %28s"
378 " 1,2,4 or 8 \n",
379 1<<(cam->params.exposure.gainMode-1), tmpstr);
381 switch(cam->params.exposure.expMode) {
382 case 1:
383 case 3:
384 sprintf(tmpstr, "manual");
385 break;
386 case 2:
387 sprintf(tmpstr, "auto");
388 break;
389 default:
390 sprintf(tmpstr, "unknown");
391 break;
393 out += sprintf(out, "exposure_mode: %8s %8s %8s"
394 " %8s\n", tmpstr, "manual", "auto", "auto");
395 out += sprintf(out, "centre_weight: %8s %8s %8s %8s\n",
396 (2-cam->params.exposure.centreWeight) ? "on" : "off",
397 "off", "on", "on");
398 out += sprintf(out, "gain: %8d %8d max_gain %8d 1,2,4,8 possible\n",
399 1<<cam->params.exposure.gain, 1, 1);
400 if (cam->params.version.firmwareVersion == 1 &&
401 cam->params.version.firmwareRevision == 2)
402 /* 1-02 firmware limits fineExp/2 to 127 */
403 tmp = 254;
404 else
405 tmp = 510;
407 out += sprintf(out, "fine_exp: %8d %8d %8d %8d\n",
408 cam->params.exposure.fineExp*2, 0, tmp, 0);
409 if (cam->params.version.firmwareVersion == 1 &&
410 cam->params.version.firmwareRevision == 2)
411 /* 1-02 firmware limits coarseExpHi to 0 */
412 tmp = MAX_EXP_102;
413 else
414 tmp = MAX_EXP;
416 out += sprintf(out, "coarse_exp: %8d %8d %8d"
417 " %8d\n", cam->params.exposure.coarseExpLo+
418 256*cam->params.exposure.coarseExpHi, 0, tmp, 185);
419 out += sprintf(out, "red_comp: %8d %8d %8d %8d\n",
420 cam->params.exposure.redComp, COMP_RED, 255, COMP_RED);
421 out += sprintf(out, "green1_comp: %8d %8d %8d %8d\n",
422 cam->params.exposure.green1Comp, COMP_GREEN1, 255,
423 COMP_GREEN1);
424 out += sprintf(out, "green2_comp: %8d %8d %8d %8d\n",
425 cam->params.exposure.green2Comp, COMP_GREEN2, 255,
426 COMP_GREEN2);
427 out += sprintf(out, "blue_comp: %8d %8d %8d %8d\n",
428 cam->params.exposure.blueComp, COMP_BLUE, 255, COMP_BLUE);
430 out += sprintf(out, "apcor_gain1: %#8x %#8x %#8x %#8x\n",
431 cam->params.apcor.gain1, 0, 0xff, 0x1c);
432 out += sprintf(out, "apcor_gain2: %#8x %#8x %#8x %#8x\n",
433 cam->params.apcor.gain2, 0, 0xff, 0x1a);
434 out += sprintf(out, "apcor_gain4: %#8x %#8x %#8x %#8x\n",
435 cam->params.apcor.gain4, 0, 0xff, 0x2d);
436 out += sprintf(out, "apcor_gain8: %#8x %#8x %#8x %#8x\n",
437 cam->params.apcor.gain8, 0, 0xff, 0x2a);
438 out += sprintf(out, "vl_offset_gain1: %8d %8d %8d %8d\n",
439 cam->params.vlOffset.gain1, 0, 255, 24);
440 out += sprintf(out, "vl_offset_gain2: %8d %8d %8d %8d\n",
441 cam->params.vlOffset.gain2, 0, 255, 28);
442 out += sprintf(out, "vl_offset_gain4: %8d %8d %8d %8d\n",
443 cam->params.vlOffset.gain4, 0, 255, 30);
444 out += sprintf(out, "vl_offset_gain8: %8d %8d %8d %8d\n",
445 cam->params.vlOffset.gain8, 0, 255, 30);
446 out += sprintf(out, "flicker_control: %8s %8s %8s %8s\n",
447 cam->params.flickerControl.flickerMode ? "on" : "off",
448 "off", "on", "off");
449 out += sprintf(out, "mains_frequency: %8d %8d %8d %8d"
450 " only 50/60\n",
451 cam->mainsFreq ? 60 : 50, 50, 60, 50);
452 if(cam->params.flickerControl.allowableOverExposure < 0)
453 out += sprintf(out, "allowable_overexposure: %4dauto auto %8d auto\n",
454 -cam->params.flickerControl.allowableOverExposure,
455 255);
456 else
457 out += sprintf(out, "allowable_overexposure: %8d auto %8d auto\n",
458 cam->params.flickerControl.allowableOverExposure,
459 255);
460 out += sprintf(out, "compression_mode: ");
461 switch(cam->params.compression.mode) {
462 case CPIA_COMPRESSION_NONE:
463 out += sprintf(out, "%8s", "none");
464 break;
465 case CPIA_COMPRESSION_AUTO:
466 out += sprintf(out, "%8s", "auto");
467 break;
468 case CPIA_COMPRESSION_MANUAL:
469 out += sprintf(out, "%8s", "manual");
470 break;
471 default:
472 out += sprintf(out, "%8s", "unknown");
473 break;
475 out += sprintf(out, " none,auto,manual auto\n");
476 out += sprintf(out, "decimation_enable: %8s %8s %8s %8s\n",
477 cam->params.compression.decimation ==
478 DECIMATION_ENAB ? "on":"off", "off", "on",
479 "off");
480 out += sprintf(out, "compression_target: %9s %9s %9s %9s\n",
481 cam->params.compressionTarget.frTargeting ==
482 CPIA_COMPRESSION_TARGET_FRAMERATE ?
483 "framerate":"quality",
484 "framerate", "quality", "quality");
485 out += sprintf(out, "target_framerate: %8d %8d %8d %8d\n",
486 cam->params.compressionTarget.targetFR, 1, 30, 15);
487 out += sprintf(out, "target_quality: %8d %8d %8d %8d\n",
488 cam->params.compressionTarget.targetQ, 1, 64, 5);
489 out += sprintf(out, "y_threshold: %8d %8d %8d %8d\n",
490 cam->params.yuvThreshold.yThreshold, 0, 31, 6);
491 out += sprintf(out, "uv_threshold: %8d %8d %8d %8d\n",
492 cam->params.yuvThreshold.uvThreshold, 0, 31, 6);
493 out += sprintf(out, "hysteresis: %8d %8d %8d %8d\n",
494 cam->params.compressionParams.hysteresis, 0, 255, 3);
495 out += sprintf(out, "threshold_max: %8d %8d %8d %8d\n",
496 cam->params.compressionParams.threshMax, 0, 255, 11);
497 out += sprintf(out, "small_step: %8d %8d %8d %8d\n",
498 cam->params.compressionParams.smallStep, 0, 255, 1);
499 out += sprintf(out, "large_step: %8d %8d %8d %8d\n",
500 cam->params.compressionParams.largeStep, 0, 255, 3);
501 out += sprintf(out, "decimation_hysteresis: %8d %8d %8d %8d\n",
502 cam->params.compressionParams.decimationHysteresis,
503 0, 255, 2);
504 out += sprintf(out, "fr_diff_step_thresh: %8d %8d %8d %8d\n",
505 cam->params.compressionParams.frDiffStepThresh,
506 0, 255, 5);
507 out += sprintf(out, "q_diff_step_thresh: %8d %8d %8d %8d\n",
508 cam->params.compressionParams.qDiffStepThresh,
509 0, 255, 3);
510 out += sprintf(out, "decimation_thresh_mod: %8d %8d %8d %8d\n",
511 cam->params.compressionParams.decimationThreshMod,
512 0, 255, 2);
513 /* QX3 specific entries */
514 if (cam->params.qx3.qx3_detected) {
515 out += sprintf(out, "toplight: %8s %8s %8s %8s\n",
516 cam->params.qx3.toplight ? "on" : "off",
517 "off", "on", "off");
518 out += sprintf(out, "bottomlight: %8s %8s %8s %8s\n",
519 cam->params.qx3.bottomlight ? "on" : "off",
520 "off", "on", "off");
523 len = out - page;
524 len -= off;
525 if (len < count) {
526 *eof = 1;
527 if (len <= 0) return 0;
528 } else
529 len = count;
531 *start = page + off;
532 return len;
536 static int match(char *checkstr, char **buffer, unsigned long *count,
537 int *find_colon, int *err)
539 int ret, colon_found = 1;
540 int len = strlen(checkstr);
541 ret = (len <= *count && strncmp(*buffer, checkstr, len) == 0);
542 if (ret) {
543 *buffer += len;
544 *count -= len;
545 if (*find_colon) {
546 colon_found = 0;
547 while (*count && (**buffer == ' ' || **buffer == '\t' ||
548 (!colon_found && **buffer == ':'))) {
549 if (**buffer == ':')
550 colon_found = 1;
551 --*count;
552 ++*buffer;
554 if (!*count || !colon_found)
555 *err = -EINVAL;
556 *find_colon = 0;
559 return ret;
562 static unsigned long int value(char **buffer, unsigned long *count, int *err)
564 char *p;
565 unsigned long int ret;
566 ret = simple_strtoul(*buffer, &p, 0);
567 if (p == *buffer)
568 *err = -EINVAL;
569 else {
570 *count -= p - *buffer;
571 *buffer = p;
573 return ret;
576 static int cpia_write_proc(struct file *file, const char __user *buf,
577 unsigned long count, void *data)
579 struct cam_data *cam = data;
580 struct cam_params new_params;
581 char *page, *buffer;
582 int retval, find_colon;
583 int size = count;
584 unsigned long val = 0;
585 u32 command_flags = 0;
586 u8 new_mains;
589 * This code to copy from buf to page is shamelessly copied
590 * from the comx driver
592 if (count > PAGE_SIZE) {
593 printk(KERN_ERR "count is %lu > %d!!!\n", count, (int)PAGE_SIZE);
594 return -ENOSPC;
597 if (!(page = (char *)__get_free_page(GFP_KERNEL))) return -ENOMEM;
599 if(copy_from_user(page, buf, count))
601 retval = -EFAULT;
602 goto out;
605 if (page[count-1] == '\n')
606 page[count-1] = '\0';
607 else if (count < PAGE_SIZE)
608 page[count] = '\0';
609 else if (page[count]) {
610 retval = -EINVAL;
611 goto out;
614 buffer = page;
616 if (mutex_lock_interruptible(&cam->param_lock))
617 return -ERESTARTSYS;
620 * Skip over leading whitespace
622 while (count && isspace(*buffer)) {
623 --count;
624 ++buffer;
627 memcpy(&new_params, &cam->params, sizeof(struct cam_params));
628 new_mains = cam->mainsFreq;
630 #define MATCH(x) (match(x, &buffer, &count, &find_colon, &retval))
631 #define VALUE (value(&buffer,&count, &retval))
632 #define FIRMWARE_VERSION(x,y) (new_params.version.firmwareVersion == (x) && \
633 new_params.version.firmwareRevision == (y))
635 retval = 0;
636 while (count && !retval) {
637 find_colon = 1;
638 if (MATCH("brightness")) {
639 if (!retval)
640 val = VALUE;
642 if (!retval) {
643 if (val <= 100)
644 new_params.colourParams.brightness = val;
645 else
646 retval = -EINVAL;
648 command_flags |= COMMAND_SETCOLOURPARAMS;
649 if(new_params.flickerControl.allowableOverExposure < 0)
650 new_params.flickerControl.allowableOverExposure =
651 -find_over_exposure(new_params.colourParams.brightness);
652 if(new_params.flickerControl.flickerMode != 0)
653 command_flags |= COMMAND_SETFLICKERCTRL;
655 } else if (MATCH("contrast")) {
656 if (!retval)
657 val = VALUE;
659 if (!retval) {
660 if (val <= 100) {
661 /* contrast is in steps of 8, so round*/
662 val = ((val + 3) / 8) * 8;
663 /* 1-02 firmware limits contrast to 80*/
664 if (FIRMWARE_VERSION(1,2) && val > 80)
665 val = 80;
667 new_params.colourParams.contrast = val;
668 } else
669 retval = -EINVAL;
671 command_flags |= COMMAND_SETCOLOURPARAMS;
672 } else if (MATCH("saturation")) {
673 if (!retval)
674 val = VALUE;
676 if (!retval) {
677 if (val <= 100)
678 new_params.colourParams.saturation = val;
679 else
680 retval = -EINVAL;
682 command_flags |= COMMAND_SETCOLOURPARAMS;
683 } else if (MATCH("sensor_fps")) {
684 if (!retval)
685 val = VALUE;
687 if (!retval) {
688 /* find values so that sensorFPS is minimized,
689 * but >= val */
690 if (val > 30)
691 retval = -EINVAL;
692 else if (val > 25) {
693 new_params.sensorFps.divisor = 0;
694 new_params.sensorFps.baserate = 1;
695 } else if (val > 15) {
696 new_params.sensorFps.divisor = 0;
697 new_params.sensorFps.baserate = 0;
698 } else if (val > 12) {
699 new_params.sensorFps.divisor = 1;
700 new_params.sensorFps.baserate = 1;
701 } else if (val > 7) {
702 new_params.sensorFps.divisor = 1;
703 new_params.sensorFps.baserate = 0;
704 } else if (val > 6) {
705 new_params.sensorFps.divisor = 2;
706 new_params.sensorFps.baserate = 1;
707 } else if (val > 3) {
708 new_params.sensorFps.divisor = 2;
709 new_params.sensorFps.baserate = 0;
710 } else {
711 new_params.sensorFps.divisor = 3;
712 /* Either base rate would work here */
713 new_params.sensorFps.baserate = 1;
715 new_params.flickerControl.coarseJump =
716 flicker_jumps[new_mains]
717 [new_params.sensorFps.baserate]
718 [new_params.sensorFps.divisor];
719 if (new_params.flickerControl.flickerMode)
720 command_flags |= COMMAND_SETFLICKERCTRL;
722 command_flags |= COMMAND_SETSENSORFPS;
723 cam->exposure_status = EXPOSURE_NORMAL;
724 } else if (MATCH("stream_start_line")) {
725 if (!retval)
726 val = VALUE;
728 if (!retval) {
729 int max_line = 288;
731 if (new_params.format.videoSize == VIDEOSIZE_QCIF)
732 max_line = 144;
733 if (val <= max_line)
734 new_params.streamStartLine = val/2;
735 else
736 retval = -EINVAL;
738 } else if (MATCH("sub_sample")) {
739 if (!retval && MATCH("420"))
740 new_params.format.subSample = SUBSAMPLE_420;
741 else if (!retval && MATCH("422"))
742 new_params.format.subSample = SUBSAMPLE_422;
743 else
744 retval = -EINVAL;
746 command_flags |= COMMAND_SETFORMAT;
747 } else if (MATCH("yuv_order")) {
748 if (!retval && MATCH("YUYV"))
749 new_params.format.yuvOrder = YUVORDER_YUYV;
750 else if (!retval && MATCH("UYVY"))
751 new_params.format.yuvOrder = YUVORDER_UYVY;
752 else
753 retval = -EINVAL;
755 command_flags |= COMMAND_SETFORMAT;
756 } else if (MATCH("ecp_timing")) {
757 if (!retval && MATCH("normal"))
758 new_params.ecpTiming = 0;
759 else if (!retval && MATCH("slow"))
760 new_params.ecpTiming = 1;
761 else
762 retval = -EINVAL;
764 command_flags |= COMMAND_SETECPTIMING;
765 } else if (MATCH("color_balance_mode")) {
766 if (!retval && MATCH("manual"))
767 new_params.colourBalance.balanceMode = 3;
768 else if (!retval && MATCH("auto"))
769 new_params.colourBalance.balanceMode = 2;
770 else
771 retval = -EINVAL;
773 command_flags |= COMMAND_SETCOLOURBALANCE;
774 } else if (MATCH("red_gain")) {
775 if (!retval)
776 val = VALUE;
778 if (!retval) {
779 if (val <= 212) {
780 new_params.colourBalance.redGain = val;
781 new_params.colourBalance.balanceMode = 1;
782 } else
783 retval = -EINVAL;
785 command_flags |= COMMAND_SETCOLOURBALANCE;
786 } else if (MATCH("green_gain")) {
787 if (!retval)
788 val = VALUE;
790 if (!retval) {
791 if (val <= 212) {
792 new_params.colourBalance.greenGain = val;
793 new_params.colourBalance.balanceMode = 1;
794 } else
795 retval = -EINVAL;
797 command_flags |= COMMAND_SETCOLOURBALANCE;
798 } else if (MATCH("blue_gain")) {
799 if (!retval)
800 val = VALUE;
802 if (!retval) {
803 if (val <= 212) {
804 new_params.colourBalance.blueGain = val;
805 new_params.colourBalance.balanceMode = 1;
806 } else
807 retval = -EINVAL;
809 command_flags |= COMMAND_SETCOLOURBALANCE;
810 } else if (MATCH("max_gain")) {
811 if (!retval)
812 val = VALUE;
814 if (!retval) {
815 /* 1-02 firmware limits gain to 2 */
816 if (FIRMWARE_VERSION(1,2) && val > 2)
817 val = 2;
818 switch(val) {
819 case 1:
820 new_params.exposure.gainMode = 1;
821 break;
822 case 2:
823 new_params.exposure.gainMode = 2;
824 break;
825 case 4:
826 new_params.exposure.gainMode = 3;
827 break;
828 case 8:
829 new_params.exposure.gainMode = 4;
830 break;
831 default:
832 retval = -EINVAL;
833 break;
836 command_flags |= COMMAND_SETEXPOSURE;
837 } else if (MATCH("exposure_mode")) {
838 if (!retval && MATCH("auto"))
839 new_params.exposure.expMode = 2;
840 else if (!retval && MATCH("manual")) {
841 if (new_params.exposure.expMode == 2)
842 new_params.exposure.expMode = 3;
843 if(new_params.flickerControl.flickerMode != 0)
844 command_flags |= COMMAND_SETFLICKERCTRL;
845 new_params.flickerControl.flickerMode = 0;
846 } else
847 retval = -EINVAL;
849 command_flags |= COMMAND_SETEXPOSURE;
850 } else if (MATCH("centre_weight")) {
851 if (!retval && MATCH("on"))
852 new_params.exposure.centreWeight = 1;
853 else if (!retval && MATCH("off"))
854 new_params.exposure.centreWeight = 2;
855 else
856 retval = -EINVAL;
858 command_flags |= COMMAND_SETEXPOSURE;
859 } else if (MATCH("gain")) {
860 if (!retval)
861 val = VALUE;
863 if (!retval) {
864 switch(val) {
865 case 1:
866 new_params.exposure.gain = 0;
867 break;
868 case 2:
869 new_params.exposure.gain = 1;
870 break;
871 case 4:
872 new_params.exposure.gain = 2;
873 break;
874 case 8:
875 new_params.exposure.gain = 3;
876 break;
877 default:
878 retval = -EINVAL;
879 break;
881 new_params.exposure.expMode = 1;
882 if(new_params.flickerControl.flickerMode != 0)
883 command_flags |= COMMAND_SETFLICKERCTRL;
884 new_params.flickerControl.flickerMode = 0;
885 command_flags |= COMMAND_SETEXPOSURE;
886 if (new_params.exposure.gain >
887 new_params.exposure.gainMode-1)
888 retval = -EINVAL;
890 } else if (MATCH("fine_exp")) {
891 if (!retval)
892 val = VALUE/2;
894 if (!retval) {
895 if (val < 256) {
896 /* 1-02 firmware limits fineExp/2 to 127*/
897 if (FIRMWARE_VERSION(1,2) && val > 127)
898 val = 127;
899 new_params.exposure.fineExp = val;
900 new_params.exposure.expMode = 1;
901 command_flags |= COMMAND_SETEXPOSURE;
902 if(new_params.flickerControl.flickerMode != 0)
903 command_flags |= COMMAND_SETFLICKERCTRL;
904 new_params.flickerControl.flickerMode = 0;
905 command_flags |= COMMAND_SETFLICKERCTRL;
906 } else
907 retval = -EINVAL;
909 } else if (MATCH("coarse_exp")) {
910 if (!retval)
911 val = VALUE;
913 if (!retval) {
914 if (val <= MAX_EXP) {
915 if (FIRMWARE_VERSION(1,2) &&
916 val > MAX_EXP_102)
917 val = MAX_EXP_102;
918 new_params.exposure.coarseExpLo =
919 val & 0xff;
920 new_params.exposure.coarseExpHi =
921 val >> 8;
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("red_comp")) {
932 if (!retval)
933 val = VALUE;
935 if (!retval) {
936 if (val >= COMP_RED && val <= 255) {
937 new_params.exposure.redComp = val;
938 new_params.exposure.compMode = 1;
939 command_flags |= COMMAND_SETEXPOSURE;
940 } else
941 retval = -EINVAL;
943 } else if (MATCH("green1_comp")) {
944 if (!retval)
945 val = VALUE;
947 if (!retval) {
948 if (val >= COMP_GREEN1 && val <= 255) {
949 new_params.exposure.green1Comp = val;
950 new_params.exposure.compMode = 1;
951 command_flags |= COMMAND_SETEXPOSURE;
952 } else
953 retval = -EINVAL;
955 } else if (MATCH("green2_comp")) {
956 if (!retval)
957 val = VALUE;
959 if (!retval) {
960 if (val >= COMP_GREEN2 && val <= 255) {
961 new_params.exposure.green2Comp = val;
962 new_params.exposure.compMode = 1;
963 command_flags |= COMMAND_SETEXPOSURE;
964 } else
965 retval = -EINVAL;
967 } else if (MATCH("blue_comp")) {
968 if (!retval)
969 val = VALUE;
971 if (!retval) {
972 if (val >= COMP_BLUE && val <= 255) {
973 new_params.exposure.blueComp = val;
974 new_params.exposure.compMode = 1;
975 command_flags |= COMMAND_SETEXPOSURE;
976 } else
977 retval = -EINVAL;
979 } else if (MATCH("apcor_gain1")) {
980 if (!retval)
981 val = VALUE;
983 if (!retval) {
984 command_flags |= COMMAND_SETAPCOR;
985 if (val <= 0xff)
986 new_params.apcor.gain1 = val;
987 else
988 retval = -EINVAL;
990 } else if (MATCH("apcor_gain2")) {
991 if (!retval)
992 val = VALUE;
994 if (!retval) {
995 command_flags |= COMMAND_SETAPCOR;
996 if (val <= 0xff)
997 new_params.apcor.gain2 = val;
998 else
999 retval = -EINVAL;
1001 } else if (MATCH("apcor_gain4")) {
1002 if (!retval)
1003 val = VALUE;
1005 if (!retval) {
1006 command_flags |= COMMAND_SETAPCOR;
1007 if (val <= 0xff)
1008 new_params.apcor.gain4 = val;
1009 else
1010 retval = -EINVAL;
1012 } else if (MATCH("apcor_gain8")) {
1013 if (!retval)
1014 val = VALUE;
1016 if (!retval) {
1017 command_flags |= COMMAND_SETAPCOR;
1018 if (val <= 0xff)
1019 new_params.apcor.gain8 = val;
1020 else
1021 retval = -EINVAL;
1023 } else if (MATCH("vl_offset_gain1")) {
1024 if (!retval)
1025 val = VALUE;
1027 if (!retval) {
1028 if (val <= 0xff)
1029 new_params.vlOffset.gain1 = val;
1030 else
1031 retval = -EINVAL;
1033 command_flags |= COMMAND_SETVLOFFSET;
1034 } else if (MATCH("vl_offset_gain2")) {
1035 if (!retval)
1036 val = VALUE;
1038 if (!retval) {
1039 if (val <= 0xff)
1040 new_params.vlOffset.gain2 = val;
1041 else
1042 retval = -EINVAL;
1044 command_flags |= COMMAND_SETVLOFFSET;
1045 } else if (MATCH("vl_offset_gain4")) {
1046 if (!retval)
1047 val = VALUE;
1049 if (!retval) {
1050 if (val <= 0xff)
1051 new_params.vlOffset.gain4 = val;
1052 else
1053 retval = -EINVAL;
1055 command_flags |= COMMAND_SETVLOFFSET;
1056 } else if (MATCH("vl_offset_gain8")) {
1057 if (!retval)
1058 val = VALUE;
1060 if (!retval) {
1061 if (val <= 0xff)
1062 new_params.vlOffset.gain8 = val;
1063 else
1064 retval = -EINVAL;
1066 command_flags |= COMMAND_SETVLOFFSET;
1067 } else if (MATCH("flicker_control")) {
1068 if (!retval && MATCH("on")) {
1069 set_flicker(&new_params, &command_flags, 1);
1070 } else if (!retval && MATCH("off")) {
1071 set_flicker(&new_params, &command_flags, 0);
1072 } else
1073 retval = -EINVAL;
1075 command_flags |= COMMAND_SETFLICKERCTRL;
1076 } else if (MATCH("mains_frequency")) {
1077 if (!retval && MATCH("50")) {
1078 new_mains = 0;
1079 new_params.flickerControl.coarseJump =
1080 flicker_jumps[new_mains]
1081 [new_params.sensorFps.baserate]
1082 [new_params.sensorFps.divisor];
1083 if (new_params.flickerControl.flickerMode)
1084 command_flags |= COMMAND_SETFLICKERCTRL;
1085 } else if (!retval && MATCH("60")) {
1086 new_mains = 1;
1087 new_params.flickerControl.coarseJump =
1088 flicker_jumps[new_mains]
1089 [new_params.sensorFps.baserate]
1090 [new_params.sensorFps.divisor];
1091 if (new_params.flickerControl.flickerMode)
1092 command_flags |= COMMAND_SETFLICKERCTRL;
1093 } else
1094 retval = -EINVAL;
1095 } else if (MATCH("allowable_overexposure")) {
1096 if (!retval && MATCH("auto")) {
1097 new_params.flickerControl.allowableOverExposure =
1098 -find_over_exposure(new_params.colourParams.brightness);
1099 if(new_params.flickerControl.flickerMode != 0)
1100 command_flags |= COMMAND_SETFLICKERCTRL;
1101 } else {
1102 if (!retval)
1103 val = VALUE;
1105 if (!retval) {
1106 if (val <= 0xff) {
1107 new_params.flickerControl.
1108 allowableOverExposure = val;
1109 if(new_params.flickerControl.flickerMode != 0)
1110 command_flags |= COMMAND_SETFLICKERCTRL;
1111 } else
1112 retval = -EINVAL;
1115 } else if (MATCH("compression_mode")) {
1116 if (!retval && MATCH("none"))
1117 new_params.compression.mode =
1118 CPIA_COMPRESSION_NONE;
1119 else if (!retval && MATCH("auto"))
1120 new_params.compression.mode =
1121 CPIA_COMPRESSION_AUTO;
1122 else if (!retval && MATCH("manual"))
1123 new_params.compression.mode =
1124 CPIA_COMPRESSION_MANUAL;
1125 else
1126 retval = -EINVAL;
1128 command_flags |= COMMAND_SETCOMPRESSION;
1129 } else if (MATCH("decimation_enable")) {
1130 if (!retval && MATCH("off"))
1131 new_params.compression.decimation = 0;
1132 else if (!retval && MATCH("on"))
1133 new_params.compression.decimation = 1;
1134 else
1135 retval = -EINVAL;
1137 command_flags |= COMMAND_SETCOMPRESSION;
1138 } else if (MATCH("compression_target")) {
1139 if (!retval && MATCH("quality"))
1140 new_params.compressionTarget.frTargeting =
1141 CPIA_COMPRESSION_TARGET_QUALITY;
1142 else if (!retval && MATCH("framerate"))
1143 new_params.compressionTarget.frTargeting =
1144 CPIA_COMPRESSION_TARGET_FRAMERATE;
1145 else
1146 retval = -EINVAL;
1148 command_flags |= COMMAND_SETCOMPRESSIONTARGET;
1149 } else if (MATCH("target_framerate")) {
1150 if (!retval)
1151 val = VALUE;
1153 if (!retval) {
1154 if(val > 0 && val <= 30)
1155 new_params.compressionTarget.targetFR = val;
1156 else
1157 retval = -EINVAL;
1159 command_flags |= COMMAND_SETCOMPRESSIONTARGET;
1160 } else if (MATCH("target_quality")) {
1161 if (!retval)
1162 val = VALUE;
1164 if (!retval) {
1165 if(val > 0 && val <= 64)
1166 new_params.compressionTarget.targetQ = val;
1167 else
1168 retval = -EINVAL;
1170 command_flags |= COMMAND_SETCOMPRESSIONTARGET;
1171 } else if (MATCH("y_threshold")) {
1172 if (!retval)
1173 val = VALUE;
1175 if (!retval) {
1176 if (val < 32)
1177 new_params.yuvThreshold.yThreshold = val;
1178 else
1179 retval = -EINVAL;
1181 command_flags |= COMMAND_SETYUVTHRESH;
1182 } else if (MATCH("uv_threshold")) {
1183 if (!retval)
1184 val = VALUE;
1186 if (!retval) {
1187 if (val < 32)
1188 new_params.yuvThreshold.uvThreshold = val;
1189 else
1190 retval = -EINVAL;
1192 command_flags |= COMMAND_SETYUVTHRESH;
1193 } else if (MATCH("hysteresis")) {
1194 if (!retval)
1195 val = VALUE;
1197 if (!retval) {
1198 if (val <= 0xff)
1199 new_params.compressionParams.hysteresis = val;
1200 else
1201 retval = -EINVAL;
1203 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1204 } else if (MATCH("threshold_max")) {
1205 if (!retval)
1206 val = VALUE;
1208 if (!retval) {
1209 if (val <= 0xff)
1210 new_params.compressionParams.threshMax = val;
1211 else
1212 retval = -EINVAL;
1214 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1215 } else if (MATCH("small_step")) {
1216 if (!retval)
1217 val = VALUE;
1219 if (!retval) {
1220 if (val <= 0xff)
1221 new_params.compressionParams.smallStep = val;
1222 else
1223 retval = -EINVAL;
1225 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1226 } else if (MATCH("large_step")) {
1227 if (!retval)
1228 val = VALUE;
1230 if (!retval) {
1231 if (val <= 0xff)
1232 new_params.compressionParams.largeStep = val;
1233 else
1234 retval = -EINVAL;
1236 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1237 } else if (MATCH("decimation_hysteresis")) {
1238 if (!retval)
1239 val = VALUE;
1241 if (!retval) {
1242 if (val <= 0xff)
1243 new_params.compressionParams.decimationHysteresis = val;
1244 else
1245 retval = -EINVAL;
1247 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1248 } else if (MATCH("fr_diff_step_thresh")) {
1249 if (!retval)
1250 val = VALUE;
1252 if (!retval) {
1253 if (val <= 0xff)
1254 new_params.compressionParams.frDiffStepThresh = val;
1255 else
1256 retval = -EINVAL;
1258 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1259 } else if (MATCH("q_diff_step_thresh")) {
1260 if (!retval)
1261 val = VALUE;
1263 if (!retval) {
1264 if (val <= 0xff)
1265 new_params.compressionParams.qDiffStepThresh = val;
1266 else
1267 retval = -EINVAL;
1269 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1270 } else if (MATCH("decimation_thresh_mod")) {
1271 if (!retval)
1272 val = VALUE;
1274 if (!retval) {
1275 if (val <= 0xff)
1276 new_params.compressionParams.decimationThreshMod = val;
1277 else
1278 retval = -EINVAL;
1280 command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1281 } else if (MATCH("toplight")) {
1282 if (!retval && MATCH("on"))
1283 new_params.qx3.toplight = 1;
1284 else if (!retval && MATCH("off"))
1285 new_params.qx3.toplight = 0;
1286 else
1287 retval = -EINVAL;
1288 command_flags |= COMMAND_SETLIGHTS;
1289 } else if (MATCH("bottomlight")) {
1290 if (!retval && MATCH("on"))
1291 new_params.qx3.bottomlight = 1;
1292 else if (!retval && MATCH("off"))
1293 new_params.qx3.bottomlight = 0;
1294 else
1295 retval = -EINVAL;
1296 command_flags |= COMMAND_SETLIGHTS;
1297 } else {
1298 DBG("No match found\n");
1299 retval = -EINVAL;
1302 if (!retval) {
1303 while (count && isspace(*buffer) && *buffer != '\n') {
1304 --count;
1305 ++buffer;
1307 if (count) {
1308 if (*buffer == '\0' && count != 1)
1309 retval = -EINVAL;
1310 else if (*buffer != '\n' && *buffer != ';' &&
1311 *buffer != '\0')
1312 retval = -EINVAL;
1313 else {
1314 --count;
1315 ++buffer;
1320 #undef MATCH
1321 #undef VALUE
1322 #undef FIRMWARE_VERSION
1323 if (!retval) {
1324 if (command_flags & COMMAND_SETCOLOURPARAMS) {
1325 /* Adjust cam->vp to reflect these changes */
1326 cam->vp.brightness =
1327 new_params.colourParams.brightness*65535/100;
1328 cam->vp.contrast =
1329 new_params.colourParams.contrast*65535/100;
1330 cam->vp.colour =
1331 new_params.colourParams.saturation*65535/100;
1333 if((command_flags & COMMAND_SETEXPOSURE) &&
1334 new_params.exposure.expMode == 2)
1335 cam->exposure_status = EXPOSURE_NORMAL;
1337 memcpy(&cam->params, &new_params, sizeof(struct cam_params));
1338 cam->mainsFreq = new_mains;
1339 cam->cmd_queue |= command_flags;
1340 retval = size;
1341 } else
1342 DBG("error: %d\n", retval);
1344 mutex_unlock(&cam->param_lock);
1346 out:
1347 free_page((unsigned long)page);
1348 return retval;
1351 static void create_proc_cpia_cam(struct cam_data *cam)
1353 char name[5 + 1 + 10 + 1];
1354 struct proc_dir_entry *ent;
1356 if (!cpia_proc_root || !cam)
1357 return;
1359 snprintf(name, sizeof(name), "video%d", cam->vdev.minor);
1361 ent = create_proc_entry(name, S_IFREG|S_IRUGO|S_IWUSR, cpia_proc_root);
1362 if (!ent)
1363 return;
1365 ent->data = cam;
1366 ent->read_proc = cpia_read_proc;
1367 ent->write_proc = cpia_write_proc;
1369 size of the proc entry is 3736 bytes for the standard webcam;
1370 the extra features of the QX3 microscope add 189 bytes.
1371 (we have not yet probed the camera to see which type it is).
1373 ent->size = 3736 + 189;
1374 cam->proc_entry = ent;
1377 static void destroy_proc_cpia_cam(struct cam_data *cam)
1379 char name[5 + 1 + 10 + 1];
1381 if (!cam || !cam->proc_entry)
1382 return;
1384 snprintf(name, sizeof(name), "video%d", cam->vdev.minor);
1385 remove_proc_entry(name, cpia_proc_root);
1386 cam->proc_entry = NULL;
1389 static void proc_cpia_create(void)
1391 cpia_proc_root = proc_mkdir("cpia", NULL);
1393 if (cpia_proc_root)
1394 cpia_proc_root->owner = THIS_MODULE;
1395 else
1396 LOG("Unable to initialise /proc/cpia\n");
1399 static void __exit proc_cpia_destroy(void)
1401 remove_proc_entry("cpia", NULL);
1403 #endif /* CONFIG_PROC_FS */
1405 /* ----------------------- debug functions ---------------------- */
1407 #define printstatus(cam) \
1408 DBG("%02x %02x %02x %02x %02x %02x %02x %02x\n",\
1409 cam->params.status.systemState, cam->params.status.grabState, \
1410 cam->params.status.streamState, cam->params.status.fatalError, \
1411 cam->params.status.cmdError, cam->params.status.debugFlags, \
1412 cam->params.status.vpStatus, cam->params.status.errorCode);
1414 /* ----------------------- v4l helpers -------------------------- */
1416 /* supported frame palettes and depths */
1417 static inline int valid_mode(u16 palette, u16 depth)
1419 if ((palette == VIDEO_PALETTE_YUV422 && depth == 16) ||
1420 (palette == VIDEO_PALETTE_YUYV && depth == 16))
1421 return 1;
1423 if (colorspace_conv)
1424 return (palette == VIDEO_PALETTE_GREY && depth == 8) ||
1425 (palette == VIDEO_PALETTE_RGB555 && depth == 16) ||
1426 (palette == VIDEO_PALETTE_RGB565 && depth == 16) ||
1427 (palette == VIDEO_PALETTE_RGB24 && depth == 24) ||
1428 (palette == VIDEO_PALETTE_RGB32 && depth == 32) ||
1429 (palette == VIDEO_PALETTE_UYVY && depth == 16);
1431 return 0;
1434 static int match_videosize( int width, int height )
1436 /* return the best match, where 'best' is as always
1437 * the largest that is not bigger than what is requested. */
1438 if (width>=352 && height>=288)
1439 return VIDEOSIZE_352_288; /* CIF */
1441 if (width>=320 && height>=240)
1442 return VIDEOSIZE_320_240; /* SIF */
1444 if (width>=288 && height>=216)
1445 return VIDEOSIZE_288_216;
1447 if (width>=256 && height>=192)
1448 return VIDEOSIZE_256_192;
1450 if (width>=224 && height>=168)
1451 return VIDEOSIZE_224_168;
1453 if (width>=192 && height>=144)
1454 return VIDEOSIZE_192_144;
1456 if (width>=176 && height>=144)
1457 return VIDEOSIZE_176_144; /* QCIF */
1459 if (width>=160 && height>=120)
1460 return VIDEOSIZE_160_120; /* QSIF */
1462 if (width>=128 && height>=96)
1463 return VIDEOSIZE_128_96;
1465 if (width>=88 && height>=72)
1466 return VIDEOSIZE_88_72;
1468 if (width>=64 && height>=48)
1469 return VIDEOSIZE_64_48;
1471 if (width>=48 && height>=48)
1472 return VIDEOSIZE_48_48;
1474 return -1;
1477 /* these are the capture sizes we support */
1478 static void set_vw_size(struct cam_data *cam)
1480 /* the col/row/start/end values are the result of simple math */
1481 /* study the SetROI-command in cpia developers guide p 2-22 */
1482 /* streamStartLine is set to the recommended value in the cpia */
1483 /* developers guide p 3-37 */
1484 switch(cam->video_size) {
1485 case VIDEOSIZE_CIF:
1486 cam->vw.width = 352;
1487 cam->vw.height = 288;
1488 cam->params.format.videoSize=VIDEOSIZE_CIF;
1489 cam->params.roi.colStart=0;
1490 cam->params.roi.rowStart=0;
1491 cam->params.streamStartLine = 120;
1492 break;
1493 case VIDEOSIZE_SIF:
1494 cam->vw.width = 320;
1495 cam->vw.height = 240;
1496 cam->params.format.videoSize=VIDEOSIZE_CIF;
1497 cam->params.roi.colStart=2;
1498 cam->params.roi.rowStart=6;
1499 cam->params.streamStartLine = 120;
1500 break;
1501 case VIDEOSIZE_288_216:
1502 cam->vw.width = 288;
1503 cam->vw.height = 216;
1504 cam->params.format.videoSize=VIDEOSIZE_CIF;
1505 cam->params.roi.colStart=4;
1506 cam->params.roi.rowStart=9;
1507 cam->params.streamStartLine = 120;
1508 break;
1509 case VIDEOSIZE_256_192:
1510 cam->vw.width = 256;
1511 cam->vw.height = 192;
1512 cam->params.format.videoSize=VIDEOSIZE_CIF;
1513 cam->params.roi.colStart=6;
1514 cam->params.roi.rowStart=12;
1515 cam->params.streamStartLine = 120;
1516 break;
1517 case VIDEOSIZE_224_168:
1518 cam->vw.width = 224;
1519 cam->vw.height = 168;
1520 cam->params.format.videoSize=VIDEOSIZE_CIF;
1521 cam->params.roi.colStart=8;
1522 cam->params.roi.rowStart=15;
1523 cam->params.streamStartLine = 120;
1524 break;
1525 case VIDEOSIZE_192_144:
1526 cam->vw.width = 192;
1527 cam->vw.height = 144;
1528 cam->params.format.videoSize=VIDEOSIZE_CIF;
1529 cam->params.roi.colStart=10;
1530 cam->params.roi.rowStart=18;
1531 cam->params.streamStartLine = 120;
1532 break;
1533 case VIDEOSIZE_QCIF:
1534 cam->vw.width = 176;
1535 cam->vw.height = 144;
1536 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1537 cam->params.roi.colStart=0;
1538 cam->params.roi.rowStart=0;
1539 cam->params.streamStartLine = 60;
1540 break;
1541 case VIDEOSIZE_QSIF:
1542 cam->vw.width = 160;
1543 cam->vw.height = 120;
1544 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1545 cam->params.roi.colStart=1;
1546 cam->params.roi.rowStart=3;
1547 cam->params.streamStartLine = 60;
1548 break;
1549 case VIDEOSIZE_128_96:
1550 cam->vw.width = 128;
1551 cam->vw.height = 96;
1552 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1553 cam->params.roi.colStart=3;
1554 cam->params.roi.rowStart=6;
1555 cam->params.streamStartLine = 60;
1556 break;
1557 case VIDEOSIZE_88_72:
1558 cam->vw.width = 88;
1559 cam->vw.height = 72;
1560 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1561 cam->params.roi.colStart=5;
1562 cam->params.roi.rowStart=9;
1563 cam->params.streamStartLine = 60;
1564 break;
1565 case VIDEOSIZE_64_48:
1566 cam->vw.width = 64;
1567 cam->vw.height = 48;
1568 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1569 cam->params.roi.colStart=7;
1570 cam->params.roi.rowStart=12;
1571 cam->params.streamStartLine = 60;
1572 break;
1573 case VIDEOSIZE_48_48:
1574 cam->vw.width = 48;
1575 cam->vw.height = 48;
1576 cam->params.format.videoSize=VIDEOSIZE_QCIF;
1577 cam->params.roi.colStart=8;
1578 cam->params.roi.rowStart=6;
1579 cam->params.streamStartLine = 60;
1580 break;
1581 default:
1582 LOG("bad videosize value: %d\n", cam->video_size);
1583 return;
1586 if(cam->vc.width == 0)
1587 cam->vc.width = cam->vw.width;
1588 if(cam->vc.height == 0)
1589 cam->vc.height = cam->vw.height;
1591 cam->params.roi.colStart += cam->vc.x >> 3;
1592 cam->params.roi.colEnd = cam->params.roi.colStart +
1593 (cam->vc.width >> 3);
1594 cam->params.roi.rowStart += cam->vc.y >> 2;
1595 cam->params.roi.rowEnd = cam->params.roi.rowStart +
1596 (cam->vc.height >> 2);
1598 return;
1601 static int allocate_frame_buf(struct cam_data *cam)
1603 int i;
1605 cam->frame_buf = rvmalloc(FRAME_NUM * CPIA_MAX_FRAME_SIZE);
1606 if (!cam->frame_buf)
1607 return -ENOBUFS;
1609 for (i = 0; i < FRAME_NUM; i++)
1610 cam->frame[i].data = cam->frame_buf + i * CPIA_MAX_FRAME_SIZE;
1612 return 0;
1615 static int free_frame_buf(struct cam_data *cam)
1617 int i;
1619 rvfree(cam->frame_buf, FRAME_NUM*CPIA_MAX_FRAME_SIZE);
1620 cam->frame_buf = NULL;
1621 for (i=0; i < FRAME_NUM; i++)
1622 cam->frame[i].data = NULL;
1624 return 0;
1628 static inline void free_frames(struct cpia_frame frame[FRAME_NUM])
1630 int i;
1632 for (i=0; i < FRAME_NUM; i++)
1633 frame[i].state = FRAME_UNUSED;
1634 return;
1637 /**********************************************************************
1639 * General functions
1641 **********************************************************************/
1642 /* send an arbitrary command to the camera */
1643 static int do_command(struct cam_data *cam, u16 command, u8 a, u8 b, u8 c, u8 d)
1645 int retval, datasize;
1646 u8 cmd[8], data[8];
1648 switch(command) {
1649 case CPIA_COMMAND_GetCPIAVersion:
1650 case CPIA_COMMAND_GetPnPID:
1651 case CPIA_COMMAND_GetCameraStatus:
1652 case CPIA_COMMAND_GetVPVersion:
1653 datasize=8;
1654 break;
1655 case CPIA_COMMAND_GetColourParams:
1656 case CPIA_COMMAND_GetColourBalance:
1657 case CPIA_COMMAND_GetExposure:
1658 mutex_lock(&cam->param_lock);
1659 datasize=8;
1660 break;
1661 case CPIA_COMMAND_ReadMCPorts:
1662 case CPIA_COMMAND_ReadVCRegs:
1663 datasize = 4;
1664 break;
1665 default:
1666 datasize=0;
1667 break;
1670 cmd[0] = command>>8;
1671 cmd[1] = command&0xff;
1672 cmd[2] = a;
1673 cmd[3] = b;
1674 cmd[4] = c;
1675 cmd[5] = d;
1676 cmd[6] = datasize;
1677 cmd[7] = 0;
1679 retval = cam->ops->transferCmd(cam->lowlevel_data, cmd, data);
1680 if (retval) {
1681 DBG("%x - failed, retval=%d\n", command, retval);
1682 if (command == CPIA_COMMAND_GetColourParams ||
1683 command == CPIA_COMMAND_GetColourBalance ||
1684 command == CPIA_COMMAND_GetExposure)
1685 mutex_unlock(&cam->param_lock);
1686 } else {
1687 switch(command) {
1688 case CPIA_COMMAND_GetCPIAVersion:
1689 cam->params.version.firmwareVersion = data[0];
1690 cam->params.version.firmwareRevision = data[1];
1691 cam->params.version.vcVersion = data[2];
1692 cam->params.version.vcRevision = data[3];
1693 break;
1694 case CPIA_COMMAND_GetPnPID:
1695 cam->params.pnpID.vendor = data[0]+(((u16)data[1])<<8);
1696 cam->params.pnpID.product = data[2]+(((u16)data[3])<<8);
1697 cam->params.pnpID.deviceRevision =
1698 data[4]+(((u16)data[5])<<8);
1699 break;
1700 case CPIA_COMMAND_GetCameraStatus:
1701 cam->params.status.systemState = data[0];
1702 cam->params.status.grabState = data[1];
1703 cam->params.status.streamState = data[2];
1704 cam->params.status.fatalError = data[3];
1705 cam->params.status.cmdError = data[4];
1706 cam->params.status.debugFlags = data[5];
1707 cam->params.status.vpStatus = data[6];
1708 cam->params.status.errorCode = data[7];
1709 break;
1710 case CPIA_COMMAND_GetVPVersion:
1711 cam->params.vpVersion.vpVersion = data[0];
1712 cam->params.vpVersion.vpRevision = data[1];
1713 cam->params.vpVersion.cameraHeadID =
1714 data[2]+(((u16)data[3])<<8);
1715 break;
1716 case CPIA_COMMAND_GetColourParams:
1717 cam->params.colourParams.brightness = data[0];
1718 cam->params.colourParams.contrast = data[1];
1719 cam->params.colourParams.saturation = data[2];
1720 mutex_unlock(&cam->param_lock);
1721 break;
1722 case CPIA_COMMAND_GetColourBalance:
1723 cam->params.colourBalance.redGain = data[0];
1724 cam->params.colourBalance.greenGain = data[1];
1725 cam->params.colourBalance.blueGain = data[2];
1726 mutex_unlock(&cam->param_lock);
1727 break;
1728 case CPIA_COMMAND_GetExposure:
1729 cam->params.exposure.gain = data[0];
1730 cam->params.exposure.fineExp = data[1];
1731 cam->params.exposure.coarseExpLo = data[2];
1732 cam->params.exposure.coarseExpHi = data[3];
1733 cam->params.exposure.redComp = data[4];
1734 cam->params.exposure.green1Comp = data[5];
1735 cam->params.exposure.green2Comp = data[6];
1736 cam->params.exposure.blueComp = data[7];
1737 mutex_unlock(&cam->param_lock);
1738 break;
1740 case CPIA_COMMAND_ReadMCPorts:
1741 if (!cam->params.qx3.qx3_detected)
1742 break;
1743 /* test button press */
1744 cam->params.qx3.button = ((data[1] & 0x02) == 0);
1745 if (cam->params.qx3.button) {
1746 /* button pressed - unlock the latch */
1747 do_command(cam,CPIA_COMMAND_WriteMCPort,3,0xDF,0xDF,0);
1748 do_command(cam,CPIA_COMMAND_WriteMCPort,3,0xFF,0xFF,0);
1751 /* test whether microscope is cradled */
1752 cam->params.qx3.cradled = ((data[2] & 0x40) == 0);
1753 break;
1755 default:
1756 break;
1759 return retval;
1762 /* send a command to the camera with an additional data transaction */
1763 static int do_command_extended(struct cam_data *cam, u16 command,
1764 u8 a, u8 b, u8 c, u8 d,
1765 u8 e, u8 f, u8 g, u8 h,
1766 u8 i, u8 j, u8 k, u8 l)
1768 int retval;
1769 u8 cmd[8], data[8];
1771 cmd[0] = command>>8;
1772 cmd[1] = command&0xff;
1773 cmd[2] = a;
1774 cmd[3] = b;
1775 cmd[4] = c;
1776 cmd[5] = d;
1777 cmd[6] = 8;
1778 cmd[7] = 0;
1779 data[0] = e;
1780 data[1] = f;
1781 data[2] = g;
1782 data[3] = h;
1783 data[4] = i;
1784 data[5] = j;
1785 data[6] = k;
1786 data[7] = l;
1788 retval = cam->ops->transferCmd(cam->lowlevel_data, cmd, data);
1789 if (retval)
1790 DBG("%x - failed\n", command);
1792 return retval;
1795 /**********************************************************************
1797 * Colorspace conversion
1799 **********************************************************************/
1800 #define LIMIT(x) ((((x)>0xffffff)?0xff0000:(((x)<=0xffff)?0:(x)&0xff0000))>>16)
1802 static int convert420(unsigned char *yuv, unsigned char *rgb, int out_fmt,
1803 int linesize, int mmap_kludge)
1805 int y, u, v, r, g, b, y1;
1807 /* Odd lines use the same u and v as the previous line.
1808 * Because of compression, it is necessary to get this
1809 * information from the decoded image. */
1810 switch(out_fmt) {
1811 case VIDEO_PALETTE_RGB555:
1812 y = (*yuv++ - 16) * 76310;
1813 y1 = (*yuv - 16) * 76310;
1814 r = ((*(rgb+1-linesize)) & 0x7c) << 1;
1815 g = ((*(rgb-linesize)) & 0xe0) >> 4 |
1816 ((*(rgb+1-linesize)) & 0x03) << 6;
1817 b = ((*(rgb-linesize)) & 0x1f) << 3;
1818 u = (-53294 * r - 104635 * g + 157929 * b) / 5756495;
1819 v = (157968 * r - 132278 * g - 25690 * b) / 5366159;
1820 r = 104635 * v;
1821 g = -25690 * u - 53294 * v;
1822 b = 132278 * u;
1823 *rgb++ = ((LIMIT(g+y) & 0xf8) << 2) | (LIMIT(b+y) >> 3);
1824 *rgb++ = ((LIMIT(r+y) & 0xf8) >> 1) | (LIMIT(g+y) >> 6);
1825 *rgb++ = ((LIMIT(g+y1) & 0xf8) << 2) | (LIMIT(b+y1) >> 3);
1826 *rgb = ((LIMIT(r+y1) & 0xf8) >> 1) | (LIMIT(g+y1) >> 6);
1827 return 4;
1828 case VIDEO_PALETTE_RGB565:
1829 y = (*yuv++ - 16) * 76310;
1830 y1 = (*yuv - 16) * 76310;
1831 r = (*(rgb+1-linesize)) & 0xf8;
1832 g = ((*(rgb-linesize)) & 0xe0) >> 3 |
1833 ((*(rgb+1-linesize)) & 0x07) << 5;
1834 b = ((*(rgb-linesize)) & 0x1f) << 3;
1835 u = (-53294 * r - 104635 * g + 157929 * b) / 5756495;
1836 v = (157968 * r - 132278 * g - 25690 * b) / 5366159;
1837 r = 104635 * v;
1838 g = -25690 * u - 53294 * v;
1839 b = 132278 * u;
1840 *rgb++ = ((LIMIT(g+y) & 0xfc) << 3) | (LIMIT(b+y) >> 3);
1841 *rgb++ = (LIMIT(r+y) & 0xf8) | (LIMIT(g+y) >> 5);
1842 *rgb++ = ((LIMIT(g+y1) & 0xfc) << 3) | (LIMIT(b+y1) >> 3);
1843 *rgb = (LIMIT(r+y1) & 0xf8) | (LIMIT(g+y1) >> 5);
1844 return 4;
1845 break;
1846 case VIDEO_PALETTE_RGB24:
1847 case VIDEO_PALETTE_RGB32:
1848 y = (*yuv++ - 16) * 76310;
1849 y1 = (*yuv - 16) * 76310;
1850 if (mmap_kludge) {
1851 r = *(rgb+2-linesize);
1852 g = *(rgb+1-linesize);
1853 b = *(rgb-linesize);
1854 } else {
1855 r = *(rgb-linesize);
1856 g = *(rgb+1-linesize);
1857 b = *(rgb+2-linesize);
1859 u = (-53294 * r - 104635 * g + 157929 * b) / 5756495;
1860 v = (157968 * r - 132278 * g - 25690 * b) / 5366159;
1861 r = 104635 * v;
1862 g = -25690 * u + -53294 * v;
1863 b = 132278 * u;
1864 if (mmap_kludge) {
1865 *rgb++ = LIMIT(b+y);
1866 *rgb++ = LIMIT(g+y);
1867 *rgb++ = LIMIT(r+y);
1868 if(out_fmt == VIDEO_PALETTE_RGB32)
1869 rgb++;
1870 *rgb++ = LIMIT(b+y1);
1871 *rgb++ = LIMIT(g+y1);
1872 *rgb = LIMIT(r+y1);
1873 } else {
1874 *rgb++ = LIMIT(r+y);
1875 *rgb++ = LIMIT(g+y);
1876 *rgb++ = LIMIT(b+y);
1877 if(out_fmt == VIDEO_PALETTE_RGB32)
1878 rgb++;
1879 *rgb++ = LIMIT(r+y1);
1880 *rgb++ = LIMIT(g+y1);
1881 *rgb = LIMIT(b+y1);
1883 if(out_fmt == VIDEO_PALETTE_RGB32)
1884 return 8;
1885 return 6;
1886 case VIDEO_PALETTE_YUV422:
1887 case VIDEO_PALETTE_YUYV:
1888 y = *yuv++;
1889 u = *(rgb+1-linesize);
1890 y1 = *yuv;
1891 v = *(rgb+3-linesize);
1892 *rgb++ = y;
1893 *rgb++ = u;
1894 *rgb++ = y1;
1895 *rgb = v;
1896 return 4;
1897 case VIDEO_PALETTE_UYVY:
1898 u = *(rgb-linesize);
1899 y = *yuv++;
1900 v = *(rgb+2-linesize);
1901 y1 = *yuv;
1902 *rgb++ = u;
1903 *rgb++ = y;
1904 *rgb++ = v;
1905 *rgb = y1;
1906 return 4;
1907 case VIDEO_PALETTE_GREY:
1908 *rgb++ = *yuv++;
1909 *rgb = *yuv;
1910 return 2;
1911 default:
1912 DBG("Empty: %d\n", out_fmt);
1913 return 0;
1918 static int yuvconvert(unsigned char *yuv, unsigned char *rgb, int out_fmt,
1919 int in_uyvy, int mmap_kludge)
1921 int y, u, v, r, g, b, y1;
1923 switch(out_fmt) {
1924 case VIDEO_PALETTE_RGB555:
1925 case VIDEO_PALETTE_RGB565:
1926 case VIDEO_PALETTE_RGB24:
1927 case VIDEO_PALETTE_RGB32:
1928 if (in_uyvy) {
1929 u = *yuv++ - 128;
1930 y = (*yuv++ - 16) * 76310;
1931 v = *yuv++ - 128;
1932 y1 = (*yuv - 16) * 76310;
1933 } else {
1934 y = (*yuv++ - 16) * 76310;
1935 u = *yuv++ - 128;
1936 y1 = (*yuv++ - 16) * 76310;
1937 v = *yuv - 128;
1939 r = 104635 * v;
1940 g = -25690 * u + -53294 * v;
1941 b = 132278 * u;
1942 break;
1943 default:
1944 y = *yuv++;
1945 u = *yuv++;
1946 y1 = *yuv++;
1947 v = *yuv;
1948 /* Just to avoid compiler warnings */
1949 r = 0;
1950 g = 0;
1951 b = 0;
1952 break;
1954 switch(out_fmt) {
1955 case VIDEO_PALETTE_RGB555:
1956 *rgb++ = ((LIMIT(g+y) & 0xf8) << 2) | (LIMIT(b+y) >> 3);
1957 *rgb++ = ((LIMIT(r+y) & 0xf8) >> 1) | (LIMIT(g+y) >> 6);
1958 *rgb++ = ((LIMIT(g+y1) & 0xf8) << 2) | (LIMIT(b+y1) >> 3);
1959 *rgb = ((LIMIT(r+y1) & 0xf8) >> 1) | (LIMIT(g+y1) >> 6);
1960 return 4;
1961 case VIDEO_PALETTE_RGB565:
1962 *rgb++ = ((LIMIT(g+y) & 0xfc) << 3) | (LIMIT(b+y) >> 3);
1963 *rgb++ = (LIMIT(r+y) & 0xf8) | (LIMIT(g+y) >> 5);
1964 *rgb++ = ((LIMIT(g+y1) & 0xfc) << 3) | (LIMIT(b+y1) >> 3);
1965 *rgb = (LIMIT(r+y1) & 0xf8) | (LIMIT(g+y1) >> 5);
1966 return 4;
1967 case VIDEO_PALETTE_RGB24:
1968 if (mmap_kludge) {
1969 *rgb++ = LIMIT(b+y);
1970 *rgb++ = LIMIT(g+y);
1971 *rgb++ = LIMIT(r+y);
1972 *rgb++ = LIMIT(b+y1);
1973 *rgb++ = LIMIT(g+y1);
1974 *rgb = LIMIT(r+y1);
1975 } else {
1976 *rgb++ = LIMIT(r+y);
1977 *rgb++ = LIMIT(g+y);
1978 *rgb++ = LIMIT(b+y);
1979 *rgb++ = LIMIT(r+y1);
1980 *rgb++ = LIMIT(g+y1);
1981 *rgb = LIMIT(b+y1);
1983 return 6;
1984 case VIDEO_PALETTE_RGB32:
1985 if (mmap_kludge) {
1986 *rgb++ = LIMIT(b+y);
1987 *rgb++ = LIMIT(g+y);
1988 *rgb++ = LIMIT(r+y);
1989 rgb++;
1990 *rgb++ = LIMIT(b+y1);
1991 *rgb++ = LIMIT(g+y1);
1992 *rgb = LIMIT(r+y1);
1993 } else {
1994 *rgb++ = LIMIT(r+y);
1995 *rgb++ = LIMIT(g+y);
1996 *rgb++ = LIMIT(b+y);
1997 rgb++;
1998 *rgb++ = LIMIT(r+y1);
1999 *rgb++ = LIMIT(g+y1);
2000 *rgb = LIMIT(b+y1);
2002 return 8;
2003 case VIDEO_PALETTE_GREY:
2004 *rgb++ = y;
2005 *rgb = y1;
2006 return 2;
2007 case VIDEO_PALETTE_YUV422:
2008 case VIDEO_PALETTE_YUYV:
2009 *rgb++ = y;
2010 *rgb++ = u;
2011 *rgb++ = y1;
2012 *rgb = v;
2013 return 4;
2014 case VIDEO_PALETTE_UYVY:
2015 *rgb++ = u;
2016 *rgb++ = y;
2017 *rgb++ = v;
2018 *rgb = y1;
2019 return 4;
2020 default:
2021 DBG("Empty: %d\n", out_fmt);
2022 return 0;
2026 static int skipcount(int count, int fmt)
2028 switch(fmt) {
2029 case VIDEO_PALETTE_GREY:
2030 return count;
2031 case VIDEO_PALETTE_RGB555:
2032 case VIDEO_PALETTE_RGB565:
2033 case VIDEO_PALETTE_YUV422:
2034 case VIDEO_PALETTE_YUYV:
2035 case VIDEO_PALETTE_UYVY:
2036 return 2*count;
2037 case VIDEO_PALETTE_RGB24:
2038 return 3*count;
2039 case VIDEO_PALETTE_RGB32:
2040 return 4*count;
2041 default:
2042 return 0;
2046 static int parse_picture(struct cam_data *cam, int size)
2048 u8 *obuf, *ibuf, *end_obuf;
2049 int ll, in_uyvy, compressed, decimation, even_line, origsize, out_fmt;
2050 int rows, cols, linesize, subsample_422;
2052 /* make sure params don't change while we are decoding */
2053 mutex_lock(&cam->param_lock);
2055 obuf = cam->decompressed_frame.data;
2056 end_obuf = obuf+CPIA_MAX_FRAME_SIZE;
2057 ibuf = cam->raw_image;
2058 origsize = size;
2059 out_fmt = cam->vp.palette;
2061 if ((ibuf[0] != MAGIC_0) || (ibuf[1] != MAGIC_1)) {
2062 LOG("header not found\n");
2063 mutex_unlock(&cam->param_lock);
2064 return -1;
2067 if ((ibuf[16] != VIDEOSIZE_QCIF) && (ibuf[16] != VIDEOSIZE_CIF)) {
2068 LOG("wrong video size\n");
2069 mutex_unlock(&cam->param_lock);
2070 return -1;
2073 if (ibuf[17] != SUBSAMPLE_420 && ibuf[17] != SUBSAMPLE_422) {
2074 LOG("illegal subtype %d\n",ibuf[17]);
2075 mutex_unlock(&cam->param_lock);
2076 return -1;
2078 subsample_422 = ibuf[17] == SUBSAMPLE_422;
2080 if (ibuf[18] != YUVORDER_YUYV && ibuf[18] != YUVORDER_UYVY) {
2081 LOG("illegal yuvorder %d\n",ibuf[18]);
2082 mutex_unlock(&cam->param_lock);
2083 return -1;
2085 in_uyvy = ibuf[18] == YUVORDER_UYVY;
2087 if ((ibuf[24] != cam->params.roi.colStart) ||
2088 (ibuf[25] != cam->params.roi.colEnd) ||
2089 (ibuf[26] != cam->params.roi.rowStart) ||
2090 (ibuf[27] != cam->params.roi.rowEnd)) {
2091 LOG("ROI mismatch\n");
2092 mutex_unlock(&cam->param_lock);
2093 return -1;
2095 cols = 8*(ibuf[25] - ibuf[24]);
2096 rows = 4*(ibuf[27] - ibuf[26]);
2099 if ((ibuf[28] != NOT_COMPRESSED) && (ibuf[28] != COMPRESSED)) {
2100 LOG("illegal compression %d\n",ibuf[28]);
2101 mutex_unlock(&cam->param_lock);
2102 return -1;
2104 compressed = (ibuf[28] == COMPRESSED);
2106 if (ibuf[29] != NO_DECIMATION && ibuf[29] != DECIMATION_ENAB) {
2107 LOG("illegal decimation %d\n",ibuf[29]);
2108 mutex_unlock(&cam->param_lock);
2109 return -1;
2111 decimation = (ibuf[29] == DECIMATION_ENAB);
2113 cam->params.yuvThreshold.yThreshold = ibuf[30];
2114 cam->params.yuvThreshold.uvThreshold = ibuf[31];
2115 cam->params.status.systemState = ibuf[32];
2116 cam->params.status.grabState = ibuf[33];
2117 cam->params.status.streamState = ibuf[34];
2118 cam->params.status.fatalError = ibuf[35];
2119 cam->params.status.cmdError = ibuf[36];
2120 cam->params.status.debugFlags = ibuf[37];
2121 cam->params.status.vpStatus = ibuf[38];
2122 cam->params.status.errorCode = ibuf[39];
2123 cam->fps = ibuf[41];
2124 mutex_unlock(&cam->param_lock);
2126 linesize = skipcount(cols, out_fmt);
2127 ibuf += FRAME_HEADER_SIZE;
2128 size -= FRAME_HEADER_SIZE;
2129 ll = ibuf[0] | (ibuf[1] << 8);
2130 ibuf += 2;
2131 even_line = 1;
2133 while (size > 0) {
2134 size -= (ll+2);
2135 if (size < 0) {
2136 LOG("Insufficient data in buffer\n");
2137 return -1;
2140 while (ll > 1) {
2141 if (!compressed || (compressed && !(*ibuf & 1))) {
2142 if(subsample_422 || even_line) {
2143 obuf += yuvconvert(ibuf, obuf, out_fmt,
2144 in_uyvy, cam->mmap_kludge);
2145 ibuf += 4;
2146 ll -= 4;
2147 } else {
2148 /* SUBSAMPLE_420 on an odd line */
2149 obuf += convert420(ibuf, obuf,
2150 out_fmt, linesize,
2151 cam->mmap_kludge);
2152 ibuf += 2;
2153 ll -= 2;
2155 } else {
2156 /*skip compressed interval from previous frame*/
2157 obuf += skipcount(*ibuf >> 1, out_fmt);
2158 if (obuf > end_obuf) {
2159 LOG("Insufficient buffer size\n");
2160 return -1;
2162 ++ibuf;
2163 ll--;
2166 if (ll == 1) {
2167 if (*ibuf != EOL) {
2168 DBG("EOL not found giving up after %d/%d"
2169 " bytes\n", origsize-size, origsize);
2170 return -1;
2173 ++ibuf; /* skip over EOL */
2175 if ((size > 3) && (ibuf[0] == EOI) && (ibuf[1] == EOI) &&
2176 (ibuf[2] == EOI) && (ibuf[3] == EOI)) {
2177 size -= 4;
2178 break;
2181 if(decimation) {
2182 /* skip the odd lines for now */
2183 obuf += linesize;
2186 if (size > 1) {
2187 ll = ibuf[0] | (ibuf[1] << 8);
2188 ibuf += 2; /* skip over line length */
2190 if(!decimation)
2191 even_line = !even_line;
2192 } else {
2193 LOG("line length was not 1 but %d after %d/%d bytes\n",
2194 ll, origsize-size, origsize);
2195 return -1;
2199 if(decimation) {
2200 /* interpolate odd rows */
2201 int i, j;
2202 u8 *prev, *next;
2203 prev = cam->decompressed_frame.data;
2204 obuf = prev+linesize;
2205 next = obuf+linesize;
2206 for(i=1; i<rows-1; i+=2) {
2207 for(j=0; j<linesize; ++j) {
2208 *obuf++ = ((int)*prev++ + *next++) / 2;
2210 prev += linesize;
2211 obuf += linesize;
2212 next += linesize;
2214 /* last row is odd, just copy previous row */
2215 memcpy(obuf, prev, linesize);
2218 cam->decompressed_frame.count = obuf-cam->decompressed_frame.data;
2220 return cam->decompressed_frame.count;
2223 /* InitStreamCap wrapper to select correct start line */
2224 static inline int init_stream_cap(struct cam_data *cam)
2226 return do_command(cam, CPIA_COMMAND_InitStreamCap,
2227 0, cam->params.streamStartLine, 0, 0);
2231 /* find_over_exposure
2232 * Finds a suitable value of OverExposure for use with SetFlickerCtrl
2233 * Some calculation is required because this value changes with the brightness
2234 * set with SetColourParameters
2236 * Parameters: Brightness - last brightness value set with SetColourParameters
2238 * Returns: OverExposure value to use with SetFlickerCtrl
2240 #define FLICKER_MAX_EXPOSURE 250
2241 #define FLICKER_ALLOWABLE_OVER_EXPOSURE 146
2242 #define FLICKER_BRIGHTNESS_CONSTANT 59
2243 static int find_over_exposure(int brightness)
2245 int MaxAllowableOverExposure, OverExposure;
2247 MaxAllowableOverExposure = FLICKER_MAX_EXPOSURE - brightness -
2248 FLICKER_BRIGHTNESS_CONSTANT;
2250 if (MaxAllowableOverExposure < FLICKER_ALLOWABLE_OVER_EXPOSURE) {
2251 OverExposure = MaxAllowableOverExposure;
2252 } else {
2253 OverExposure = FLICKER_ALLOWABLE_OVER_EXPOSURE;
2256 return OverExposure;
2258 #undef FLICKER_MAX_EXPOSURE
2259 #undef FLICKER_ALLOWABLE_OVER_EXPOSURE
2260 #undef FLICKER_BRIGHTNESS_CONSTANT
2262 /* update various camera modes and settings */
2263 static void dispatch_commands(struct cam_data *cam)
2265 mutex_lock(&cam->param_lock);
2266 if (cam->cmd_queue==COMMAND_NONE) {
2267 mutex_unlock(&cam->param_lock);
2268 return;
2270 DEB_BYTE(cam->cmd_queue);
2271 DEB_BYTE(cam->cmd_queue>>8);
2272 if (cam->cmd_queue & COMMAND_SETFORMAT) {
2273 do_command(cam, CPIA_COMMAND_SetFormat,
2274 cam->params.format.videoSize,
2275 cam->params.format.subSample,
2276 cam->params.format.yuvOrder, 0);
2277 do_command(cam, CPIA_COMMAND_SetROI,
2278 cam->params.roi.colStart, cam->params.roi.colEnd,
2279 cam->params.roi.rowStart, cam->params.roi.rowEnd);
2280 cam->first_frame = 1;
2283 if (cam->cmd_queue & COMMAND_SETCOLOURPARAMS)
2284 do_command(cam, CPIA_COMMAND_SetColourParams,
2285 cam->params.colourParams.brightness,
2286 cam->params.colourParams.contrast,
2287 cam->params.colourParams.saturation, 0);
2289 if (cam->cmd_queue & COMMAND_SETAPCOR)
2290 do_command(cam, CPIA_COMMAND_SetApcor,
2291 cam->params.apcor.gain1,
2292 cam->params.apcor.gain2,
2293 cam->params.apcor.gain4,
2294 cam->params.apcor.gain8);
2296 if (cam->cmd_queue & COMMAND_SETVLOFFSET)
2297 do_command(cam, CPIA_COMMAND_SetVLOffset,
2298 cam->params.vlOffset.gain1,
2299 cam->params.vlOffset.gain2,
2300 cam->params.vlOffset.gain4,
2301 cam->params.vlOffset.gain8);
2303 if (cam->cmd_queue & COMMAND_SETEXPOSURE) {
2304 do_command_extended(cam, CPIA_COMMAND_SetExposure,
2305 cam->params.exposure.gainMode,
2307 cam->params.exposure.compMode,
2308 cam->params.exposure.centreWeight,
2309 cam->params.exposure.gain,
2310 cam->params.exposure.fineExp,
2311 cam->params.exposure.coarseExpLo,
2312 cam->params.exposure.coarseExpHi,
2313 cam->params.exposure.redComp,
2314 cam->params.exposure.green1Comp,
2315 cam->params.exposure.green2Comp,
2316 cam->params.exposure.blueComp);
2317 if(cam->params.exposure.expMode != 1) {
2318 do_command_extended(cam, CPIA_COMMAND_SetExposure,
2320 cam->params.exposure.expMode,
2321 0, 0,
2322 cam->params.exposure.gain,
2323 cam->params.exposure.fineExp,
2324 cam->params.exposure.coarseExpLo,
2325 cam->params.exposure.coarseExpHi,
2326 0, 0, 0, 0);
2330 if (cam->cmd_queue & COMMAND_SETCOLOURBALANCE) {
2331 if (cam->params.colourBalance.balanceMode == 1) {
2332 do_command(cam, CPIA_COMMAND_SetColourBalance,
2334 cam->params.colourBalance.redGain,
2335 cam->params.colourBalance.greenGain,
2336 cam->params.colourBalance.blueGain);
2337 do_command(cam, CPIA_COMMAND_SetColourBalance,
2338 3, 0, 0, 0);
2340 if (cam->params.colourBalance.balanceMode == 2) {
2341 do_command(cam, CPIA_COMMAND_SetColourBalance,
2342 2, 0, 0, 0);
2344 if (cam->params.colourBalance.balanceMode == 3) {
2345 do_command(cam, CPIA_COMMAND_SetColourBalance,
2346 3, 0, 0, 0);
2350 if (cam->cmd_queue & COMMAND_SETCOMPRESSIONTARGET)
2351 do_command(cam, CPIA_COMMAND_SetCompressionTarget,
2352 cam->params.compressionTarget.frTargeting,
2353 cam->params.compressionTarget.targetFR,
2354 cam->params.compressionTarget.targetQ, 0);
2356 if (cam->cmd_queue & COMMAND_SETYUVTHRESH)
2357 do_command(cam, CPIA_COMMAND_SetYUVThresh,
2358 cam->params.yuvThreshold.yThreshold,
2359 cam->params.yuvThreshold.uvThreshold, 0, 0);
2361 if (cam->cmd_queue & COMMAND_SETCOMPRESSIONPARAMS)
2362 do_command_extended(cam, CPIA_COMMAND_SetCompressionParams,
2363 0, 0, 0, 0,
2364 cam->params.compressionParams.hysteresis,
2365 cam->params.compressionParams.threshMax,
2366 cam->params.compressionParams.smallStep,
2367 cam->params.compressionParams.largeStep,
2368 cam->params.compressionParams.decimationHysteresis,
2369 cam->params.compressionParams.frDiffStepThresh,
2370 cam->params.compressionParams.qDiffStepThresh,
2371 cam->params.compressionParams.decimationThreshMod);
2373 if (cam->cmd_queue & COMMAND_SETCOMPRESSION)
2374 do_command(cam, CPIA_COMMAND_SetCompression,
2375 cam->params.compression.mode,
2376 cam->params.compression.decimation, 0, 0);
2378 if (cam->cmd_queue & COMMAND_SETSENSORFPS)
2379 do_command(cam, CPIA_COMMAND_SetSensorFPS,
2380 cam->params.sensorFps.divisor,
2381 cam->params.sensorFps.baserate, 0, 0);
2383 if (cam->cmd_queue & COMMAND_SETFLICKERCTRL)
2384 do_command(cam, CPIA_COMMAND_SetFlickerCtrl,
2385 cam->params.flickerControl.flickerMode,
2386 cam->params.flickerControl.coarseJump,
2387 abs(cam->params.flickerControl.allowableOverExposure),
2390 if (cam->cmd_queue & COMMAND_SETECPTIMING)
2391 do_command(cam, CPIA_COMMAND_SetECPTiming,
2392 cam->params.ecpTiming, 0, 0, 0);
2394 if (cam->cmd_queue & COMMAND_PAUSE)
2395 do_command(cam, CPIA_COMMAND_EndStreamCap, 0, 0, 0, 0);
2397 if (cam->cmd_queue & COMMAND_RESUME)
2398 init_stream_cap(cam);
2400 if (cam->cmd_queue & COMMAND_SETLIGHTS && cam->params.qx3.qx3_detected)
2402 int p1 = (cam->params.qx3.bottomlight == 0) << 1;
2403 int p2 = (cam->params.qx3.toplight == 0) << 3;
2404 do_command(cam, CPIA_COMMAND_WriteVCReg, 0x90, 0x8F, 0x50, 0);
2405 do_command(cam, CPIA_COMMAND_WriteMCPort, 2, 0, (p1|p2|0xE0), 0);
2408 cam->cmd_queue = COMMAND_NONE;
2409 mutex_unlock(&cam->param_lock);
2410 return;
2415 static void set_flicker(struct cam_params *params, volatile u32 *command_flags,
2416 int on)
2418 /* Everything in here is from the Windows driver */
2419 #define FIRMWARE_VERSION(x,y) (params->version.firmwareVersion == (x) && \
2420 params->version.firmwareRevision == (y))
2421 /* define for compgain calculation */
2422 #if 0
2423 #define COMPGAIN(base, curexp, newexp) \
2424 (u8) ((((float) base - 128.0) * ((float) curexp / (float) newexp)) + 128.5)
2425 #define EXP_FROM_COMP(basecomp, curcomp, curexp) \
2426 (u16)((float)curexp * (float)(u8)(curcomp + 128) / (float)(u8)(basecomp - 128))
2427 #else
2428 /* equivalent functions without floating point math */
2429 #define COMPGAIN(base, curexp, newexp) \
2430 (u8)(128 + (((u32)(2*(base-128)*curexp + newexp)) / (2* newexp)) )
2431 #define EXP_FROM_COMP(basecomp, curcomp, curexp) \
2432 (u16)(((u32)(curexp * (u8)(curcomp + 128)) / (u8)(basecomp - 128)))
2433 #endif
2436 int currentexp = params->exposure.coarseExpLo +
2437 params->exposure.coarseExpHi*256;
2438 int startexp;
2439 if (on) {
2440 int cj = params->flickerControl.coarseJump;
2441 params->flickerControl.flickerMode = 1;
2442 params->flickerControl.disabled = 0;
2443 if(params->exposure.expMode != 2)
2444 *command_flags |= COMMAND_SETEXPOSURE;
2445 params->exposure.expMode = 2;
2446 currentexp = currentexp << params->exposure.gain;
2447 params->exposure.gain = 0;
2448 /* round down current exposure to nearest value */
2449 startexp = (currentexp + ROUND_UP_EXP_FOR_FLICKER) / cj;
2450 if(startexp < 1)
2451 startexp = 1;
2452 startexp = (startexp * cj) - 1;
2453 if(FIRMWARE_VERSION(1,2))
2454 while(startexp > MAX_EXP_102)
2455 startexp -= cj;
2456 else
2457 while(startexp > MAX_EXP)
2458 startexp -= cj;
2459 params->exposure.coarseExpLo = startexp & 0xff;
2460 params->exposure.coarseExpHi = startexp >> 8;
2461 if (currentexp > startexp) {
2462 if (currentexp > (2 * startexp))
2463 currentexp = 2 * startexp;
2464 params->exposure.redComp = COMPGAIN (COMP_RED, currentexp, startexp);
2465 params->exposure.green1Comp = COMPGAIN (COMP_GREEN1, currentexp, startexp);
2466 params->exposure.green2Comp = COMPGAIN (COMP_GREEN2, currentexp, startexp);
2467 params->exposure.blueComp = COMPGAIN (COMP_BLUE, currentexp, startexp);
2468 } else {
2469 params->exposure.redComp = COMP_RED;
2470 params->exposure.green1Comp = COMP_GREEN1;
2471 params->exposure.green2Comp = COMP_GREEN2;
2472 params->exposure.blueComp = COMP_BLUE;
2474 if(FIRMWARE_VERSION(1,2))
2475 params->exposure.compMode = 0;
2476 else
2477 params->exposure.compMode = 1;
2479 params->apcor.gain1 = 0x18;
2480 params->apcor.gain2 = 0x18;
2481 params->apcor.gain4 = 0x16;
2482 params->apcor.gain8 = 0x14;
2483 *command_flags |= COMMAND_SETAPCOR;
2484 } else {
2485 params->flickerControl.flickerMode = 0;
2486 params->flickerControl.disabled = 1;
2487 /* Coarse = average of equivalent coarse for each comp channel */
2488 startexp = EXP_FROM_COMP(COMP_RED, params->exposure.redComp, currentexp);
2489 startexp += EXP_FROM_COMP(COMP_GREEN1, params->exposure.green1Comp, currentexp);
2490 startexp += EXP_FROM_COMP(COMP_GREEN2, params->exposure.green2Comp, currentexp);
2491 startexp += EXP_FROM_COMP(COMP_BLUE, params->exposure.blueComp, currentexp);
2492 startexp = startexp >> 2;
2493 while(startexp > MAX_EXP &&
2494 params->exposure.gain < params->exposure.gainMode-1) {
2495 startexp = startexp >> 1;
2496 ++params->exposure.gain;
2498 if(FIRMWARE_VERSION(1,2) && startexp > MAX_EXP_102)
2499 startexp = MAX_EXP_102;
2500 if(startexp > MAX_EXP)
2501 startexp = MAX_EXP;
2502 params->exposure.coarseExpLo = startexp&0xff;
2503 params->exposure.coarseExpHi = startexp >> 8;
2504 params->exposure.redComp = COMP_RED;
2505 params->exposure.green1Comp = COMP_GREEN1;
2506 params->exposure.green2Comp = COMP_GREEN2;
2507 params->exposure.blueComp = COMP_BLUE;
2508 params->exposure.compMode = 1;
2509 *command_flags |= COMMAND_SETEXPOSURE;
2510 params->apcor.gain1 = 0x18;
2511 params->apcor.gain2 = 0x16;
2512 params->apcor.gain4 = 0x24;
2513 params->apcor.gain8 = 0x34;
2514 *command_flags |= COMMAND_SETAPCOR;
2516 params->vlOffset.gain1 = 20;
2517 params->vlOffset.gain2 = 24;
2518 params->vlOffset.gain4 = 26;
2519 params->vlOffset.gain8 = 26;
2520 *command_flags |= COMMAND_SETVLOFFSET;
2521 #undef FIRMWARE_VERSION
2522 #undef EXP_FROM_COMP
2523 #undef COMPGAIN
2526 #define FIRMWARE_VERSION(x,y) (cam->params.version.firmwareVersion == (x) && \
2527 cam->params.version.firmwareRevision == (y))
2528 /* monitor the exposure and adjust the sensor frame rate if needed */
2529 static void monitor_exposure(struct cam_data *cam)
2531 u8 exp_acc, bcomp, gain, coarseL, cmd[8], data[8];
2532 int retval, light_exp, dark_exp, very_dark_exp;
2533 int old_exposure, new_exposure, framerate;
2535 /* get necessary stats and register settings from camera */
2536 /* do_command can't handle this, so do it ourselves */
2537 cmd[0] = CPIA_COMMAND_ReadVPRegs>>8;
2538 cmd[1] = CPIA_COMMAND_ReadVPRegs&0xff;
2539 cmd[2] = 30;
2540 cmd[3] = 4;
2541 cmd[4] = 9;
2542 cmd[5] = 8;
2543 cmd[6] = 8;
2544 cmd[7] = 0;
2545 retval = cam->ops->transferCmd(cam->lowlevel_data, cmd, data);
2546 if (retval) {
2547 LOG("ReadVPRegs(30,4,9,8) - failed, retval=%d\n",
2548 retval);
2549 return;
2551 exp_acc = data[0];
2552 bcomp = data[1];
2553 gain = data[2];
2554 coarseL = data[3];
2556 mutex_lock(&cam->param_lock);
2557 light_exp = cam->params.colourParams.brightness +
2558 TC - 50 + EXP_ACC_LIGHT;
2559 if(light_exp > 255)
2560 light_exp = 255;
2561 dark_exp = cam->params.colourParams.brightness +
2562 TC - 50 - EXP_ACC_DARK;
2563 if(dark_exp < 0)
2564 dark_exp = 0;
2565 very_dark_exp = dark_exp/2;
2567 old_exposure = cam->params.exposure.coarseExpHi * 256 +
2568 cam->params.exposure.coarseExpLo;
2570 if(!cam->params.flickerControl.disabled) {
2571 /* Flicker control on */
2572 int max_comp = FIRMWARE_VERSION(1,2) ? MAX_COMP : HIGH_COMP_102;
2573 bcomp += 128; /* decode */
2574 if(bcomp >= max_comp && exp_acc < dark_exp) {
2575 /* dark */
2576 if(exp_acc < very_dark_exp) {
2577 /* very dark */
2578 if(cam->exposure_status == EXPOSURE_VERY_DARK)
2579 ++cam->exposure_count;
2580 else {
2581 cam->exposure_status = EXPOSURE_VERY_DARK;
2582 cam->exposure_count = 1;
2584 } else {
2585 /* just dark */
2586 if(cam->exposure_status == EXPOSURE_DARK)
2587 ++cam->exposure_count;
2588 else {
2589 cam->exposure_status = EXPOSURE_DARK;
2590 cam->exposure_count = 1;
2593 } else if(old_exposure <= LOW_EXP || exp_acc > light_exp) {
2594 /* light */
2595 if(old_exposure <= VERY_LOW_EXP) {
2596 /* very light */
2597 if(cam->exposure_status == EXPOSURE_VERY_LIGHT)
2598 ++cam->exposure_count;
2599 else {
2600 cam->exposure_status = EXPOSURE_VERY_LIGHT;
2601 cam->exposure_count = 1;
2603 } else {
2604 /* just light */
2605 if(cam->exposure_status == EXPOSURE_LIGHT)
2606 ++cam->exposure_count;
2607 else {
2608 cam->exposure_status = EXPOSURE_LIGHT;
2609 cam->exposure_count = 1;
2612 } else {
2613 /* not dark or light */
2614 cam->exposure_status = EXPOSURE_NORMAL;
2616 } else {
2617 /* Flicker control off */
2618 if(old_exposure >= MAX_EXP && exp_acc < dark_exp) {
2619 /* dark */
2620 if(exp_acc < very_dark_exp) {
2621 /* very dark */
2622 if(cam->exposure_status == EXPOSURE_VERY_DARK)
2623 ++cam->exposure_count;
2624 else {
2625 cam->exposure_status = EXPOSURE_VERY_DARK;
2626 cam->exposure_count = 1;
2628 } else {
2629 /* just dark */
2630 if(cam->exposure_status == EXPOSURE_DARK)
2631 ++cam->exposure_count;
2632 else {
2633 cam->exposure_status = EXPOSURE_DARK;
2634 cam->exposure_count = 1;
2637 } else if(old_exposure <= LOW_EXP || exp_acc > light_exp) {
2638 /* light */
2639 if(old_exposure <= VERY_LOW_EXP) {
2640 /* very light */
2641 if(cam->exposure_status == EXPOSURE_VERY_LIGHT)
2642 ++cam->exposure_count;
2643 else {
2644 cam->exposure_status = EXPOSURE_VERY_LIGHT;
2645 cam->exposure_count = 1;
2647 } else {
2648 /* just light */
2649 if(cam->exposure_status == EXPOSURE_LIGHT)
2650 ++cam->exposure_count;
2651 else {
2652 cam->exposure_status = EXPOSURE_LIGHT;
2653 cam->exposure_count = 1;
2656 } else {
2657 /* not dark or light */
2658 cam->exposure_status = EXPOSURE_NORMAL;
2662 framerate = cam->fps;
2663 if(framerate > 30 || framerate < 1)
2664 framerate = 1;
2666 if(!cam->params.flickerControl.disabled) {
2667 /* Flicker control on */
2668 if((cam->exposure_status == EXPOSURE_VERY_DARK ||
2669 cam->exposure_status == EXPOSURE_DARK) &&
2670 cam->exposure_count >= DARK_TIME*framerate &&
2671 cam->params.sensorFps.divisor < 3) {
2673 /* dark for too long */
2674 ++cam->params.sensorFps.divisor;
2675 cam->cmd_queue |= COMMAND_SETSENSORFPS;
2677 cam->params.flickerControl.coarseJump =
2678 flicker_jumps[cam->mainsFreq]
2679 [cam->params.sensorFps.baserate]
2680 [cam->params.sensorFps.divisor];
2681 cam->cmd_queue |= COMMAND_SETFLICKERCTRL;
2683 new_exposure = cam->params.flickerControl.coarseJump-1;
2684 while(new_exposure < old_exposure/2)
2685 new_exposure += cam->params.flickerControl.coarseJump;
2686 cam->params.exposure.coarseExpLo = new_exposure & 0xff;
2687 cam->params.exposure.coarseExpHi = new_exposure >> 8;
2688 cam->cmd_queue |= COMMAND_SETEXPOSURE;
2689 cam->exposure_status = EXPOSURE_NORMAL;
2690 LOG("Automatically decreasing sensor_fps\n");
2692 } else if((cam->exposure_status == EXPOSURE_VERY_LIGHT ||
2693 cam->exposure_status == EXPOSURE_LIGHT) &&
2694 cam->exposure_count >= LIGHT_TIME*framerate &&
2695 cam->params.sensorFps.divisor > 0) {
2697 /* light for too long */
2698 int max_exp = FIRMWARE_VERSION(1,2) ? MAX_EXP_102 : MAX_EXP ;
2700 --cam->params.sensorFps.divisor;
2701 cam->cmd_queue |= COMMAND_SETSENSORFPS;
2703 cam->params.flickerControl.coarseJump =
2704 flicker_jumps[cam->mainsFreq]
2705 [cam->params.sensorFps.baserate]
2706 [cam->params.sensorFps.divisor];
2707 cam->cmd_queue |= COMMAND_SETFLICKERCTRL;
2709 new_exposure = cam->params.flickerControl.coarseJump-1;
2710 while(new_exposure < 2*old_exposure &&
2711 new_exposure+
2712 cam->params.flickerControl.coarseJump < max_exp)
2713 new_exposure += cam->params.flickerControl.coarseJump;
2714 cam->params.exposure.coarseExpLo = new_exposure & 0xff;
2715 cam->params.exposure.coarseExpHi = new_exposure >> 8;
2716 cam->cmd_queue |= COMMAND_SETEXPOSURE;
2717 cam->exposure_status = EXPOSURE_NORMAL;
2718 LOG("Automatically increasing sensor_fps\n");
2720 } else {
2721 /* Flicker control off */
2722 if((cam->exposure_status == EXPOSURE_VERY_DARK ||
2723 cam->exposure_status == EXPOSURE_DARK) &&
2724 cam->exposure_count >= DARK_TIME*framerate &&
2725 cam->params.sensorFps.divisor < 3) {
2727 /* dark for too long */
2728 ++cam->params.sensorFps.divisor;
2729 cam->cmd_queue |= COMMAND_SETSENSORFPS;
2731 if(cam->params.exposure.gain > 0) {
2732 --cam->params.exposure.gain;
2733 cam->cmd_queue |= COMMAND_SETEXPOSURE;
2735 cam->exposure_status = EXPOSURE_NORMAL;
2736 LOG("Automatically decreasing sensor_fps\n");
2738 } else if((cam->exposure_status == EXPOSURE_VERY_LIGHT ||
2739 cam->exposure_status == EXPOSURE_LIGHT) &&
2740 cam->exposure_count >= LIGHT_TIME*framerate &&
2741 cam->params.sensorFps.divisor > 0) {
2743 /* light for too long */
2744 --cam->params.sensorFps.divisor;
2745 cam->cmd_queue |= COMMAND_SETSENSORFPS;
2747 if(cam->params.exposure.gain <
2748 cam->params.exposure.gainMode-1) {
2749 ++cam->params.exposure.gain;
2750 cam->cmd_queue |= COMMAND_SETEXPOSURE;
2752 cam->exposure_status = EXPOSURE_NORMAL;
2753 LOG("Automatically increasing sensor_fps\n");
2756 mutex_unlock(&cam->param_lock);
2759 /*-----------------------------------------------------------------*/
2760 /* if flicker is switched off, this function switches it back on.It checks,
2761 however, that conditions are suitable before restarting it.
2762 This should only be called for firmware version 1.2.
2764 It also adjust the colour balance when an exposure step is detected - as
2765 long as flicker is running
2767 static void restart_flicker(struct cam_data *cam)
2769 int cam_exposure, old_exp;
2770 if(!FIRMWARE_VERSION(1,2))
2771 return;
2772 mutex_lock(&cam->param_lock);
2773 if(cam->params.flickerControl.flickerMode == 0 ||
2774 cam->raw_image[39] == 0) {
2775 mutex_unlock(&cam->param_lock);
2776 return;
2778 cam_exposure = cam->raw_image[39]*2;
2779 old_exp = cam->params.exposure.coarseExpLo +
2780 cam->params.exposure.coarseExpHi*256;
2782 see how far away camera exposure is from a valid
2783 flicker exposure value
2785 cam_exposure %= cam->params.flickerControl.coarseJump;
2786 if(!cam->params.flickerControl.disabled &&
2787 cam_exposure <= cam->params.flickerControl.coarseJump - 3) {
2788 /* Flicker control auto-disabled */
2789 cam->params.flickerControl.disabled = 1;
2792 if(cam->params.flickerControl.disabled &&
2793 cam->params.flickerControl.flickerMode &&
2794 old_exp > cam->params.flickerControl.coarseJump +
2795 ROUND_UP_EXP_FOR_FLICKER) {
2796 /* exposure is now high enough to switch
2797 flicker control back on */
2798 set_flicker(&cam->params, &cam->cmd_queue, 1);
2799 if((cam->cmd_queue & COMMAND_SETEXPOSURE) &&
2800 cam->params.exposure.expMode == 2)
2801 cam->exposure_status = EXPOSURE_NORMAL;
2804 mutex_unlock(&cam->param_lock);
2806 #undef FIRMWARE_VERSION
2808 static int clear_stall(struct cam_data *cam)
2810 /* FIXME: Does this actually work? */
2811 LOG("Clearing stall\n");
2813 cam->ops->streamRead(cam->lowlevel_data, cam->raw_image, 0);
2814 do_command(cam, CPIA_COMMAND_GetCameraStatus,0,0,0,0);
2815 return cam->params.status.streamState != STREAM_PAUSED;
2818 /* kernel thread function to read image from camera */
2819 static int fetch_frame(void *data)
2821 int image_size, retry;
2822 struct cam_data *cam = (struct cam_data *)data;
2823 unsigned long oldjif, rate, diff;
2825 /* Allow up to two bad images in a row to be read and
2826 * ignored before an error is reported */
2827 for (retry = 0; retry < 3; ++retry) {
2828 if (retry)
2829 DBG("retry=%d\n", retry);
2831 if (!cam->ops)
2832 continue;
2834 /* load first frame always uncompressed */
2835 if (cam->first_frame &&
2836 cam->params.compression.mode != CPIA_COMPRESSION_NONE) {
2837 do_command(cam, CPIA_COMMAND_SetCompression,
2838 CPIA_COMPRESSION_NONE,
2839 NO_DECIMATION, 0, 0);
2840 /* Trial & error - Discarding a frame prevents the
2841 first frame from having an error in the data. */
2842 do_command(cam, CPIA_COMMAND_DiscardFrame, 0, 0, 0, 0);
2845 /* init camera upload */
2846 if (do_command(cam, CPIA_COMMAND_GrabFrame, 0,
2847 cam->params.streamStartLine, 0, 0))
2848 continue;
2850 if (cam->ops->wait_for_stream_ready) {
2851 /* loop until image ready */
2852 int count = 0;
2853 do_command(cam, CPIA_COMMAND_GetCameraStatus,0,0,0,0);
2854 while (cam->params.status.streamState != STREAM_READY) {
2855 if(++count > READY_TIMEOUT)
2856 break;
2857 if(cam->params.status.streamState ==
2858 STREAM_PAUSED) {
2859 /* Bad news */
2860 if(!clear_stall(cam))
2861 return -EIO;
2864 cond_resched();
2866 /* sleep for 10 ms, hopefully ;) */
2867 msleep_interruptible(10);
2868 if (signal_pending(current))
2869 return -EINTR;
2871 do_command(cam, CPIA_COMMAND_GetCameraStatus,
2872 0, 0, 0, 0);
2874 if(cam->params.status.streamState != STREAM_READY) {
2875 continue;
2879 cond_resched();
2881 /* grab image from camera */
2882 oldjif = jiffies;
2883 image_size = cam->ops->streamRead(cam->lowlevel_data,
2884 cam->raw_image, 0);
2885 if (image_size <= 0) {
2886 DBG("streamRead failed: %d\n", image_size);
2887 continue;
2890 rate = image_size * HZ / 1024;
2891 diff = jiffies-oldjif;
2892 cam->transfer_rate = diff==0 ? rate : rate/diff;
2893 /* diff==0 ? unlikely but possible */
2895 /* Switch flicker control back on if it got turned off */
2896 restart_flicker(cam);
2898 /* If AEC is enabled, monitor the exposure and
2899 adjust the sensor frame rate if needed */
2900 if(cam->params.exposure.expMode == 2)
2901 monitor_exposure(cam);
2903 /* camera idle now so dispatch queued commands */
2904 dispatch_commands(cam);
2906 /* Update our knowledge of the camera state */
2907 do_command(cam, CPIA_COMMAND_GetColourBalance, 0, 0, 0, 0);
2908 do_command(cam, CPIA_COMMAND_GetExposure, 0, 0, 0, 0);
2909 do_command(cam, CPIA_COMMAND_ReadMCPorts, 0, 0, 0, 0);
2911 /* decompress and convert image to by copying it from
2912 * raw_image to decompressed_frame
2915 cond_resched();
2917 cam->image_size = parse_picture(cam, image_size);
2918 if (cam->image_size <= 0) {
2919 DBG("parse_picture failed %d\n", cam->image_size);
2920 if(cam->params.compression.mode !=
2921 CPIA_COMPRESSION_NONE) {
2922 /* Compression may not work right if we
2923 had a bad frame, get the next one
2924 uncompressed. */
2925 cam->first_frame = 1;
2926 do_command(cam, CPIA_COMMAND_SetGrabMode,
2927 CPIA_GRAB_SINGLE, 0, 0, 0);
2928 /* FIXME: Trial & error - need up to 70ms for
2929 the grab mode change to complete ? */
2930 msleep_interruptible(70);
2931 if (signal_pending(current))
2932 return -EINTR;
2934 } else
2935 break;
2938 if (retry < 3) {
2939 /* FIXME: this only works for double buffering */
2940 if (cam->frame[cam->curframe].state == FRAME_READY) {
2941 memcpy(cam->frame[cam->curframe].data,
2942 cam->decompressed_frame.data,
2943 cam->decompressed_frame.count);
2944 cam->frame[cam->curframe].state = FRAME_DONE;
2945 } else
2946 cam->decompressed_frame.state = FRAME_DONE;
2948 if (cam->first_frame) {
2949 cam->first_frame = 0;
2950 do_command(cam, CPIA_COMMAND_SetCompression,
2951 cam->params.compression.mode,
2952 cam->params.compression.decimation, 0, 0);
2954 /* Switch from single-grab to continuous grab */
2955 do_command(cam, CPIA_COMMAND_SetGrabMode,
2956 CPIA_GRAB_CONTINUOUS, 0, 0, 0);
2958 return 0;
2960 return -EIO;
2963 static int capture_frame(struct cam_data *cam, struct video_mmap *vm)
2965 if (!cam->frame_buf) {
2966 /* we do lazy allocation */
2967 int err;
2968 if ((err = allocate_frame_buf(cam)))
2969 return err;
2972 cam->curframe = vm->frame;
2973 cam->frame[cam->curframe].state = FRAME_READY;
2974 return fetch_frame(cam);
2977 static int goto_high_power(struct cam_data *cam)
2979 if (do_command(cam, CPIA_COMMAND_GotoHiPower, 0, 0, 0, 0))
2980 return -EIO;
2981 msleep_interruptible(40); /* windows driver does it too */
2982 if(signal_pending(current))
2983 return -EINTR;
2984 if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0))
2985 return -EIO;
2986 if (cam->params.status.systemState == HI_POWER_STATE) {
2987 DBG("camera now in HIGH power state\n");
2988 return 0;
2990 printstatus(cam);
2991 return -EIO;
2994 static int goto_low_power(struct cam_data *cam)
2996 if (do_command(cam, CPIA_COMMAND_GotoLoPower, 0, 0, 0, 0))
2997 return -1;
2998 if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0))
2999 return -1;
3000 if (cam->params.status.systemState == LO_POWER_STATE) {
3001 DBG("camera now in LOW power state\n");
3002 return 0;
3004 printstatus(cam);
3005 return -1;
3008 static void save_camera_state(struct cam_data *cam)
3010 if(!(cam->cmd_queue & COMMAND_SETCOLOURBALANCE))
3011 do_command(cam, CPIA_COMMAND_GetColourBalance, 0, 0, 0, 0);
3012 if(!(cam->cmd_queue & COMMAND_SETEXPOSURE))
3013 do_command(cam, CPIA_COMMAND_GetExposure, 0, 0, 0, 0);
3015 DBG("%d/%d/%d/%d/%d/%d/%d/%d\n",
3016 cam->params.exposure.gain,
3017 cam->params.exposure.fineExp,
3018 cam->params.exposure.coarseExpLo,
3019 cam->params.exposure.coarseExpHi,
3020 cam->params.exposure.redComp,
3021 cam->params.exposure.green1Comp,
3022 cam->params.exposure.green2Comp,
3023 cam->params.exposure.blueComp);
3024 DBG("%d/%d/%d\n",
3025 cam->params.colourBalance.redGain,
3026 cam->params.colourBalance.greenGain,
3027 cam->params.colourBalance.blueGain);
3030 static int set_camera_state(struct cam_data *cam)
3032 cam->cmd_queue = COMMAND_SETCOMPRESSION |
3033 COMMAND_SETCOMPRESSIONTARGET |
3034 COMMAND_SETCOLOURPARAMS |
3035 COMMAND_SETFORMAT |
3036 COMMAND_SETYUVTHRESH |
3037 COMMAND_SETECPTIMING |
3038 COMMAND_SETCOMPRESSIONPARAMS |
3039 COMMAND_SETEXPOSURE |
3040 COMMAND_SETCOLOURBALANCE |
3041 COMMAND_SETSENSORFPS |
3042 COMMAND_SETAPCOR |
3043 COMMAND_SETFLICKERCTRL |
3044 COMMAND_SETVLOFFSET;
3046 do_command(cam, CPIA_COMMAND_SetGrabMode, CPIA_GRAB_SINGLE,0,0,0);
3047 dispatch_commands(cam);
3049 /* Wait 6 frames for the sensor to get all settings and
3050 AEC/ACB to settle */
3051 msleep_interruptible(6*(cam->params.sensorFps.baserate ? 33 : 40) *
3052 (1 << cam->params.sensorFps.divisor) + 10);
3054 if(signal_pending(current))
3055 return -EINTR;
3057 save_camera_state(cam);
3059 return 0;
3062 static void get_version_information(struct cam_data *cam)
3064 /* GetCPIAVersion */
3065 do_command(cam, CPIA_COMMAND_GetCPIAVersion, 0, 0, 0, 0);
3067 /* GetPnPID */
3068 do_command(cam, CPIA_COMMAND_GetPnPID, 0, 0, 0, 0);
3071 /* initialize camera */
3072 static int reset_camera(struct cam_data *cam)
3074 int err;
3075 /* Start the camera in low power mode */
3076 if (goto_low_power(cam)) {
3077 if (cam->params.status.systemState != WARM_BOOT_STATE)
3078 return -ENODEV;
3080 /* FIXME: this is just dirty trial and error */
3081 err = goto_high_power(cam);
3082 if(err)
3083 return err;
3084 do_command(cam, CPIA_COMMAND_DiscardFrame, 0, 0, 0, 0);
3085 if (goto_low_power(cam))
3086 return -ENODEV;
3089 /* procedure described in developer's guide p3-28 */
3091 /* Check the firmware version. */
3092 cam->params.version.firmwareVersion = 0;
3093 get_version_information(cam);
3094 if (cam->params.version.firmwareVersion != 1)
3095 return -ENODEV;
3097 /* A bug in firmware 1-02 limits gainMode to 2 */
3098 if(cam->params.version.firmwareRevision <= 2 &&
3099 cam->params.exposure.gainMode > 2) {
3100 cam->params.exposure.gainMode = 2;
3103 /* set QX3 detected flag */
3104 cam->params.qx3.qx3_detected = (cam->params.pnpID.vendor == 0x0813 &&
3105 cam->params.pnpID.product == 0x0001);
3107 /* The fatal error checking should be done after
3108 * the camera powers up (developer's guide p 3-38) */
3110 /* Set streamState before transition to high power to avoid bug
3111 * in firmware 1-02 */
3112 do_command(cam, CPIA_COMMAND_ModifyCameraStatus, STREAMSTATE, 0,
3113 STREAM_NOT_READY, 0);
3115 /* GotoHiPower */
3116 err = goto_high_power(cam);
3117 if (err)
3118 return err;
3120 /* Check the camera status */
3121 if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0))
3122 return -EIO;
3124 if (cam->params.status.fatalError) {
3125 DBG("fatal_error: %#04x\n",
3126 cam->params.status.fatalError);
3127 DBG("vp_status: %#04x\n",
3128 cam->params.status.vpStatus);
3129 if (cam->params.status.fatalError & ~(COM_FLAG|CPIA_FLAG)) {
3130 /* Fatal error in camera */
3131 return -EIO;
3132 } else if (cam->params.status.fatalError & (COM_FLAG|CPIA_FLAG)) {
3133 /* Firmware 1-02 may do this for parallel port cameras,
3134 * just clear the flags (developer's guide p 3-38) */
3135 do_command(cam, CPIA_COMMAND_ModifyCameraStatus,
3136 FATALERROR, ~(COM_FLAG|CPIA_FLAG), 0, 0);
3140 /* Check the camera status again */
3141 if (cam->params.status.fatalError) {
3142 if (cam->params.status.fatalError)
3143 return -EIO;
3146 /* VPVersion can't be retrieved before the camera is in HiPower,
3147 * so get it here instead of in get_version_information. */
3148 do_command(cam, CPIA_COMMAND_GetVPVersion, 0, 0, 0, 0);
3150 /* set camera to a known state */
3151 return set_camera_state(cam);
3154 static void put_cam(struct cpia_camera_ops* ops)
3156 module_put(ops->owner);
3159 /* ------------------------- V4L interface --------------------- */
3160 static int cpia_open(struct inode *inode, struct file *file)
3162 struct video_device *dev = video_devdata(file);
3163 struct cam_data *cam = dev->priv;
3164 int err;
3166 if (!cam) {
3167 DBG("Internal error, cam_data not found!\n");
3168 return -ENODEV;
3171 if (cam->open_count > 0) {
3172 DBG("Camera already open\n");
3173 return -EBUSY;
3176 if (!try_module_get(cam->ops->owner))
3177 return -ENODEV;
3179 mutex_lock(&cam->busy_lock);
3180 err = -ENOMEM;
3181 if (!cam->raw_image) {
3182 cam->raw_image = rvmalloc(CPIA_MAX_IMAGE_SIZE);
3183 if (!cam->raw_image)
3184 goto oops;
3187 if (!cam->decompressed_frame.data) {
3188 cam->decompressed_frame.data = rvmalloc(CPIA_MAX_FRAME_SIZE);
3189 if (!cam->decompressed_frame.data)
3190 goto oops;
3193 /* open cpia */
3194 err = -ENODEV;
3195 if (cam->ops->open(cam->lowlevel_data))
3196 goto oops;
3198 /* reset the camera */
3199 if ((err = reset_camera(cam)) != 0) {
3200 cam->ops->close(cam->lowlevel_data);
3201 goto oops;
3204 err = -EINTR;
3205 if(signal_pending(current))
3206 goto oops;
3208 /* Set ownership of /proc/cpia/videoX to current user */
3209 if(cam->proc_entry)
3210 cam->proc_entry->uid = current->uid;
3212 /* set mark for loading first frame uncompressed */
3213 cam->first_frame = 1;
3215 /* init it to something */
3216 cam->mmap_kludge = 0;
3218 ++cam->open_count;
3219 file->private_data = dev;
3220 mutex_unlock(&cam->busy_lock);
3221 return 0;
3223 oops:
3224 if (cam->decompressed_frame.data) {
3225 rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE);
3226 cam->decompressed_frame.data = NULL;
3228 if (cam->raw_image) {
3229 rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
3230 cam->raw_image = NULL;
3232 mutex_unlock(&cam->busy_lock);
3233 put_cam(cam->ops);
3234 return err;
3237 static int cpia_close(struct inode *inode, struct file *file)
3239 struct video_device *dev = file->private_data;
3240 struct cam_data *cam = dev->priv;
3242 if (cam->ops) {
3243 /* Return ownership of /proc/cpia/videoX to root */
3244 if(cam->proc_entry)
3245 cam->proc_entry->uid = 0;
3247 /* save camera state for later open (developers guide ch 3.5.3) */
3248 save_camera_state(cam);
3250 /* GotoLoPower */
3251 goto_low_power(cam);
3253 /* Update the camera status */
3254 do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0);
3256 /* cleanup internal state stuff */
3257 free_frames(cam->frame);
3259 /* close cpia */
3260 cam->ops->close(cam->lowlevel_data);
3262 put_cam(cam->ops);
3265 if (--cam->open_count == 0) {
3266 /* clean up capture-buffers */
3267 if (cam->raw_image) {
3268 rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
3269 cam->raw_image = NULL;
3272 if (cam->decompressed_frame.data) {
3273 rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE);
3274 cam->decompressed_frame.data = NULL;
3277 if (cam->frame_buf)
3278 free_frame_buf(cam);
3280 if (!cam->ops)
3281 kfree(cam);
3283 file->private_data = NULL;
3285 return 0;
3288 static ssize_t cpia_read(struct file *file, char __user *buf,
3289 size_t count, loff_t *ppos)
3291 struct video_device *dev = file->private_data;
3292 struct cam_data *cam = dev->priv;
3293 int err;
3295 /* make this _really_ smp and multithread-safe */
3296 if (mutex_lock_interruptible(&cam->busy_lock))
3297 return -EINTR;
3299 if (!buf) {
3300 DBG("buf NULL\n");
3301 mutex_unlock(&cam->busy_lock);
3302 return -EINVAL;
3305 if (!count) {
3306 DBG("count 0\n");
3307 mutex_unlock(&cam->busy_lock);
3308 return 0;
3311 if (!cam->ops) {
3312 DBG("ops NULL\n");
3313 mutex_unlock(&cam->busy_lock);
3314 return -ENODEV;
3317 /* upload frame */
3318 cam->decompressed_frame.state = FRAME_READY;
3319 cam->mmap_kludge=0;
3320 if((err = fetch_frame(cam)) != 0) {
3321 DBG("ERROR from fetch_frame: %d\n", err);
3322 mutex_unlock(&cam->busy_lock);
3323 return err;
3325 cam->decompressed_frame.state = FRAME_UNUSED;
3327 /* copy data to user space */
3328 if (cam->decompressed_frame.count > count) {
3329 DBG("count wrong: %d, %lu\n", cam->decompressed_frame.count,
3330 (unsigned long) count);
3331 mutex_unlock(&cam->busy_lock);
3332 return -EFAULT;
3334 if (copy_to_user(buf, cam->decompressed_frame.data,
3335 cam->decompressed_frame.count)) {
3336 DBG("copy_to_user failed\n");
3337 mutex_unlock(&cam->busy_lock);
3338 return -EFAULT;
3341 mutex_unlock(&cam->busy_lock);
3342 return cam->decompressed_frame.count;
3345 static int cpia_do_ioctl(struct inode *inode, struct file *file,
3346 unsigned int ioctlnr, void *arg)
3348 struct video_device *dev = file->private_data;
3349 struct cam_data *cam = dev->priv;
3350 int retval = 0;
3352 if (!cam || !cam->ops)
3353 return -ENODEV;
3355 /* make this _really_ smp-safe */
3356 if (mutex_lock_interruptible(&cam->busy_lock))
3357 return -EINTR;
3359 //DBG("cpia_ioctl: %u\n", ioctlnr);
3361 switch (ioctlnr) {
3362 /* query capabilities */
3363 case VIDIOCGCAP:
3365 struct video_capability *b = arg;
3367 DBG("VIDIOCGCAP\n");
3368 strcpy(b->name, "CPiA Camera");
3369 b->type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE;
3370 b->channels = 1;
3371 b->audios = 0;
3372 b->maxwidth = 352; /* VIDEOSIZE_CIF */
3373 b->maxheight = 288;
3374 b->minwidth = 48; /* VIDEOSIZE_48_48 */
3375 b->minheight = 48;
3376 break;
3379 /* get/set video source - we are a camera and nothing else */
3380 case VIDIOCGCHAN:
3382 struct video_channel *v = arg;
3384 DBG("VIDIOCGCHAN\n");
3385 if (v->channel != 0) {
3386 retval = -EINVAL;
3387 break;
3390 v->channel = 0;
3391 strcpy(v->name, "Camera");
3392 v->tuners = 0;
3393 v->flags = 0;
3394 v->type = VIDEO_TYPE_CAMERA;
3395 v->norm = 0;
3396 break;
3399 case VIDIOCSCHAN:
3401 struct video_channel *v = arg;
3403 DBG("VIDIOCSCHAN\n");
3404 if (v->channel != 0)
3405 retval = -EINVAL;
3406 break;
3409 /* image properties */
3410 case VIDIOCGPICT:
3412 struct video_picture *pic = arg;
3413 DBG("VIDIOCGPICT\n");
3414 *pic = cam->vp;
3415 break;
3418 case VIDIOCSPICT:
3420 struct video_picture *vp = arg;
3422 DBG("VIDIOCSPICT\n");
3424 /* check validity */
3425 DBG("palette: %d\n", vp->palette);
3426 DBG("depth: %d\n", vp->depth);
3427 if (!valid_mode(vp->palette, vp->depth)) {
3428 retval = -EINVAL;
3429 break;
3432 mutex_lock(&cam->param_lock);
3433 /* brightness, colour, contrast need no check 0-65535 */
3434 cam->vp = *vp;
3435 /* update cam->params.colourParams */
3436 cam->params.colourParams.brightness = vp->brightness*100/65535;
3437 cam->params.colourParams.contrast = vp->contrast*100/65535;
3438 cam->params.colourParams.saturation = vp->colour*100/65535;
3439 /* contrast is in steps of 8, so round */
3440 cam->params.colourParams.contrast =
3441 ((cam->params.colourParams.contrast + 3) / 8) * 8;
3442 if (cam->params.version.firmwareVersion == 1 &&
3443 cam->params.version.firmwareRevision == 2 &&
3444 cam->params.colourParams.contrast > 80) {
3445 /* 1-02 firmware limits contrast to 80 */
3446 cam->params.colourParams.contrast = 80;
3449 /* Adjust flicker control if necessary */
3450 if(cam->params.flickerControl.allowableOverExposure < 0)
3451 cam->params.flickerControl.allowableOverExposure =
3452 -find_over_exposure(cam->params.colourParams.brightness);
3453 if(cam->params.flickerControl.flickerMode != 0)
3454 cam->cmd_queue |= COMMAND_SETFLICKERCTRL;
3457 /* queue command to update camera */
3458 cam->cmd_queue |= COMMAND_SETCOLOURPARAMS;
3459 mutex_unlock(&cam->param_lock);
3460 DBG("VIDIOCSPICT: %d / %d // %d / %d / %d / %d\n",
3461 vp->depth, vp->palette, vp->brightness, vp->hue, vp->colour,
3462 vp->contrast);
3463 break;
3466 /* get/set capture window */
3467 case VIDIOCGWIN:
3469 struct video_window *vw = arg;
3470 DBG("VIDIOCGWIN\n");
3472 *vw = cam->vw;
3473 break;
3476 case VIDIOCSWIN:
3478 /* copy_from_user, check validity, copy to internal structure */
3479 struct video_window *vw = arg;
3480 DBG("VIDIOCSWIN\n");
3482 if (vw->clipcount != 0) { /* clipping not supported */
3483 retval = -EINVAL;
3484 break;
3486 if (vw->clips != NULL) { /* clipping not supported */
3487 retval = -EINVAL;
3488 break;
3491 /* we set the video window to something smaller or equal to what
3492 * is requested by the user???
3494 mutex_lock(&cam->param_lock);
3495 if (vw->width != cam->vw.width || vw->height != cam->vw.height) {
3496 int video_size = match_videosize(vw->width, vw->height);
3498 if (video_size < 0) {
3499 retval = -EINVAL;
3500 mutex_unlock(&cam->param_lock);
3501 break;
3503 cam->video_size = video_size;
3505 /* video size is changing, reset the subcapture area */
3506 memset(&cam->vc, 0, sizeof(cam->vc));
3508 set_vw_size(cam);
3509 DBG("%d / %d\n", cam->vw.width, cam->vw.height);
3510 cam->cmd_queue |= COMMAND_SETFORMAT;
3513 mutex_unlock(&cam->param_lock);
3515 /* setformat ignored by camera during streaming,
3516 * so stop/dispatch/start */
3517 if (cam->cmd_queue & COMMAND_SETFORMAT) {
3518 DBG("\n");
3519 dispatch_commands(cam);
3521 DBG("%d/%d:%d\n", cam->video_size,
3522 cam->vw.width, cam->vw.height);
3523 break;
3526 /* mmap interface */
3527 case VIDIOCGMBUF:
3529 struct video_mbuf *vm = arg;
3530 int i;
3532 DBG("VIDIOCGMBUF\n");
3533 memset(vm, 0, sizeof(*vm));
3534 vm->size = CPIA_MAX_FRAME_SIZE*FRAME_NUM;
3535 vm->frames = FRAME_NUM;
3536 for (i = 0; i < FRAME_NUM; i++)
3537 vm->offsets[i] = CPIA_MAX_FRAME_SIZE * i;
3538 break;
3541 case VIDIOCMCAPTURE:
3543 struct video_mmap *vm = arg;
3544 int video_size;
3546 DBG("VIDIOCMCAPTURE: %d / %d / %dx%d\n", vm->format, vm->frame,
3547 vm->width, vm->height);
3548 if (vm->frame<0||vm->frame>=FRAME_NUM) {
3549 retval = -EINVAL;
3550 break;
3553 /* set video format */
3554 cam->vp.palette = vm->format;
3555 switch(vm->format) {
3556 case VIDEO_PALETTE_GREY:
3557 cam->vp.depth=8;
3558 break;
3559 case VIDEO_PALETTE_RGB555:
3560 case VIDEO_PALETTE_RGB565:
3561 case VIDEO_PALETTE_YUV422:
3562 case VIDEO_PALETTE_YUYV:
3563 case VIDEO_PALETTE_UYVY:
3564 cam->vp.depth = 16;
3565 break;
3566 case VIDEO_PALETTE_RGB24:
3567 cam->vp.depth = 24;
3568 break;
3569 case VIDEO_PALETTE_RGB32:
3570 cam->vp.depth = 32;
3571 break;
3572 default:
3573 retval = -EINVAL;
3574 break;
3576 if (retval)
3577 break;
3579 /* set video size */
3580 video_size = match_videosize(vm->width, vm->height);
3581 if (video_size < 0) {
3582 retval = -EINVAL;
3583 break;
3585 if (video_size != cam->video_size) {
3586 cam->video_size = video_size;
3588 /* video size is changing, reset the subcapture area */
3589 memset(&cam->vc, 0, sizeof(cam->vc));
3591 set_vw_size(cam);
3592 cam->cmd_queue |= COMMAND_SETFORMAT;
3593 dispatch_commands(cam);
3595 /* according to v4l-spec we must start streaming here */
3596 cam->mmap_kludge = 1;
3597 retval = capture_frame(cam, vm);
3599 break;
3602 case VIDIOCSYNC:
3604 int *frame = arg;
3606 //DBG("VIDIOCSYNC: %d\n", *frame);
3608 if (*frame<0 || *frame >= FRAME_NUM) {
3609 retval = -EINVAL;
3610 break;
3613 switch (cam->frame[*frame].state) {
3614 case FRAME_UNUSED:
3615 case FRAME_READY:
3616 case FRAME_GRABBING:
3617 DBG("sync to unused frame %d\n", *frame);
3618 retval = -EINVAL;
3619 break;
3621 case FRAME_DONE:
3622 cam->frame[*frame].state = FRAME_UNUSED;
3623 //DBG("VIDIOCSYNC: %d synced\n", *frame);
3624 break;
3626 if (retval == -EINTR) {
3627 /* FIXME - xawtv does not handle this nice */
3628 retval = 0;
3630 break;
3633 case VIDIOCGCAPTURE:
3635 struct video_capture *vc = arg;
3637 DBG("VIDIOCGCAPTURE\n");
3639 *vc = cam->vc;
3641 break;
3644 case VIDIOCSCAPTURE:
3646 struct video_capture *vc = arg;
3648 DBG("VIDIOCSCAPTURE\n");
3650 if (vc->decimation != 0) { /* How should this be used? */
3651 retval = -EINVAL;
3652 break;
3654 if (vc->flags != 0) { /* Even/odd grab not supported */
3655 retval = -EINVAL;
3656 break;
3659 /* Clip to the resolution we can set for the ROI
3660 (every 8 columns and 4 rows) */
3661 vc->x = vc->x & ~(__u32)7;
3662 vc->y = vc->y & ~(__u32)3;
3663 vc->width = vc->width & ~(__u32)7;
3664 vc->height = vc->height & ~(__u32)3;
3666 if(vc->width == 0 || vc->height == 0 ||
3667 vc->x + vc->width > cam->vw.width ||
3668 vc->y + vc->height > cam->vw.height) {
3669 retval = -EINVAL;
3670 break;
3673 DBG("%d,%d/%dx%d\n", vc->x,vc->y,vc->width, vc->height);
3675 mutex_lock(&cam->param_lock);
3677 cam->vc.x = vc->x;
3678 cam->vc.y = vc->y;
3679 cam->vc.width = vc->width;
3680 cam->vc.height = vc->height;
3682 set_vw_size(cam);
3683 cam->cmd_queue |= COMMAND_SETFORMAT;
3685 mutex_unlock(&cam->param_lock);
3687 /* setformat ignored by camera during streaming,
3688 * so stop/dispatch/start */
3689 dispatch_commands(cam);
3690 break;
3693 case VIDIOCGUNIT:
3695 struct video_unit *vu = arg;
3697 DBG("VIDIOCGUNIT\n");
3699 vu->video = cam->vdev.minor;
3700 vu->vbi = VIDEO_NO_UNIT;
3701 vu->radio = VIDEO_NO_UNIT;
3702 vu->audio = VIDEO_NO_UNIT;
3703 vu->teletext = VIDEO_NO_UNIT;
3705 break;
3709 /* pointless to implement overlay with this camera */
3710 case VIDIOCCAPTURE:
3711 case VIDIOCGFBUF:
3712 case VIDIOCSFBUF:
3713 case VIDIOCKEY:
3714 /* tuner interface - we have none */
3715 case VIDIOCGTUNER:
3716 case VIDIOCSTUNER:
3717 case VIDIOCGFREQ:
3718 case VIDIOCSFREQ:
3719 /* audio interface - we have none */
3720 case VIDIOCGAUDIO:
3721 case VIDIOCSAUDIO:
3722 retval = -EINVAL;
3723 break;
3724 default:
3725 retval = -ENOIOCTLCMD;
3726 break;
3729 mutex_unlock(&cam->busy_lock);
3730 return retval;
3733 static int cpia_ioctl(struct inode *inode, struct file *file,
3734 unsigned int cmd, unsigned long arg)
3736 return video_usercopy(inode, file, cmd, arg, cpia_do_ioctl);
3740 /* FIXME */
3741 static int cpia_mmap(struct file *file, struct vm_area_struct *vma)
3743 struct video_device *dev = file->private_data;
3744 unsigned long start = vma->vm_start;
3745 unsigned long size = vma->vm_end - vma->vm_start;
3746 unsigned long page, pos;
3747 struct cam_data *cam = dev->priv;
3748 int retval;
3750 if (!cam || !cam->ops)
3751 return -ENODEV;
3753 DBG("cpia_mmap: %ld\n", size);
3755 if (size > FRAME_NUM*CPIA_MAX_FRAME_SIZE)
3756 return -EINVAL;
3758 if (!cam || !cam->ops)
3759 return -ENODEV;
3761 /* make this _really_ smp-safe */
3762 if (mutex_lock_interruptible(&cam->busy_lock))
3763 return -EINTR;
3765 if (!cam->frame_buf) { /* we do lazy allocation */
3766 if ((retval = allocate_frame_buf(cam))) {
3767 mutex_unlock(&cam->busy_lock);
3768 return retval;
3772 pos = (unsigned long)(cam->frame_buf);
3773 while (size > 0) {
3774 page = vmalloc_to_pfn((void *)pos);
3775 if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
3776 mutex_unlock(&cam->busy_lock);
3777 return -EAGAIN;
3779 start += PAGE_SIZE;
3780 pos += PAGE_SIZE;
3781 if (size > PAGE_SIZE)
3782 size -= PAGE_SIZE;
3783 else
3784 size = 0;
3787 DBG("cpia_mmap: %ld\n", size);
3788 mutex_unlock(&cam->busy_lock);
3790 return 0;
3793 static const struct file_operations cpia_fops = {
3794 .owner = THIS_MODULE,
3795 .open = cpia_open,
3796 .release = cpia_close,
3797 .read = cpia_read,
3798 .mmap = cpia_mmap,
3799 .ioctl = cpia_ioctl,
3800 .compat_ioctl = v4l_compat_ioctl32,
3801 .llseek = no_llseek,
3804 static struct video_device cpia_template = {
3805 .owner = THIS_MODULE,
3806 .name = "CPiA Camera",
3807 .type = VID_TYPE_CAPTURE,
3808 .hardware = VID_HARDWARE_CPIA,
3809 .fops = &cpia_fops,
3812 /* initialise cam_data structure */
3813 static void reset_camera_struct(struct cam_data *cam)
3815 /* The following parameter values are the defaults from
3816 * "Software Developer's Guide for CPiA Cameras". Any changes
3817 * to the defaults are noted in comments. */
3818 cam->params.colourParams.brightness = 50;
3819 cam->params.colourParams.contrast = 48;
3820 cam->params.colourParams.saturation = 50;
3821 cam->params.exposure.gainMode = 4;
3822 cam->params.exposure.expMode = 2; /* AEC */
3823 cam->params.exposure.compMode = 1;
3824 cam->params.exposure.centreWeight = 1;
3825 cam->params.exposure.gain = 0;
3826 cam->params.exposure.fineExp = 0;
3827 cam->params.exposure.coarseExpLo = 185;
3828 cam->params.exposure.coarseExpHi = 0;
3829 cam->params.exposure.redComp = COMP_RED;
3830 cam->params.exposure.green1Comp = COMP_GREEN1;
3831 cam->params.exposure.green2Comp = COMP_GREEN2;
3832 cam->params.exposure.blueComp = COMP_BLUE;
3833 cam->params.colourBalance.balanceMode = 2; /* ACB */
3834 cam->params.colourBalance.redGain = 32;
3835 cam->params.colourBalance.greenGain = 6;
3836 cam->params.colourBalance.blueGain = 92;
3837 cam->params.apcor.gain1 = 0x18;
3838 cam->params.apcor.gain2 = 0x16;
3839 cam->params.apcor.gain4 = 0x24;
3840 cam->params.apcor.gain8 = 0x34;
3841 cam->params.flickerControl.flickerMode = 0;
3842 cam->params.flickerControl.disabled = 1;
3844 cam->params.flickerControl.coarseJump =
3845 flicker_jumps[cam->mainsFreq]
3846 [cam->params.sensorFps.baserate]
3847 [cam->params.sensorFps.divisor];
3848 cam->params.flickerControl.allowableOverExposure =
3849 -find_over_exposure(cam->params.colourParams.brightness);
3850 cam->params.vlOffset.gain1 = 20;
3851 cam->params.vlOffset.gain2 = 24;
3852 cam->params.vlOffset.gain4 = 26;
3853 cam->params.vlOffset.gain8 = 26;
3854 cam->params.compressionParams.hysteresis = 3;
3855 cam->params.compressionParams.threshMax = 11;
3856 cam->params.compressionParams.smallStep = 1;
3857 cam->params.compressionParams.largeStep = 3;
3858 cam->params.compressionParams.decimationHysteresis = 2;
3859 cam->params.compressionParams.frDiffStepThresh = 5;
3860 cam->params.compressionParams.qDiffStepThresh = 3;
3861 cam->params.compressionParams.decimationThreshMod = 2;
3862 /* End of default values from Software Developer's Guide */
3864 cam->transfer_rate = 0;
3865 cam->exposure_status = EXPOSURE_NORMAL;
3867 /* Set Sensor FPS to 15fps. This seems better than 30fps
3868 * for indoor lighting. */
3869 cam->params.sensorFps.divisor = 1;
3870 cam->params.sensorFps.baserate = 1;
3872 cam->params.yuvThreshold.yThreshold = 6; /* From windows driver */
3873 cam->params.yuvThreshold.uvThreshold = 6; /* From windows driver */
3875 cam->params.format.subSample = SUBSAMPLE_422;
3876 cam->params.format.yuvOrder = YUVORDER_YUYV;
3878 cam->params.compression.mode = CPIA_COMPRESSION_AUTO;
3879 cam->params.compressionTarget.frTargeting =
3880 CPIA_COMPRESSION_TARGET_QUALITY;
3881 cam->params.compressionTarget.targetFR = 15; /* From windows driver */
3882 cam->params.compressionTarget.targetQ = 5; /* From windows driver */
3884 cam->params.qx3.qx3_detected = 0;
3885 cam->params.qx3.toplight = 0;
3886 cam->params.qx3.bottomlight = 0;
3887 cam->params.qx3.button = 0;
3888 cam->params.qx3.cradled = 0;
3890 cam->video_size = VIDEOSIZE_CIF;
3892 cam->vp.colour = 32768; /* 50% */
3893 cam->vp.hue = 32768; /* 50% */
3894 cam->vp.brightness = 32768; /* 50% */
3895 cam->vp.contrast = 32768; /* 50% */
3896 cam->vp.whiteness = 0; /* not used -> grayscale only */
3897 cam->vp.depth = 24; /* to be set by user */
3898 cam->vp.palette = VIDEO_PALETTE_RGB24; /* to be set by user */
3900 cam->vc.x = 0;
3901 cam->vc.y = 0;
3902 cam->vc.width = 0;
3903 cam->vc.height = 0;
3905 cam->vw.x = 0;
3906 cam->vw.y = 0;
3907 set_vw_size(cam);
3908 cam->vw.chromakey = 0;
3909 cam->vw.flags = 0;
3910 cam->vw.clipcount = 0;
3911 cam->vw.clips = NULL;
3913 cam->cmd_queue = COMMAND_NONE;
3914 cam->first_frame = 1;
3916 return;
3919 /* initialize cam_data structure */
3920 static void init_camera_struct(struct cam_data *cam,
3921 struct cpia_camera_ops *ops )
3923 int i;
3925 /* Default everything to 0 */
3926 memset(cam, 0, sizeof(struct cam_data));
3928 cam->ops = ops;
3929 mutex_init(&cam->param_lock);
3930 mutex_init(&cam->busy_lock);
3932 reset_camera_struct(cam);
3934 cam->proc_entry = NULL;
3936 memcpy(&cam->vdev, &cpia_template, sizeof(cpia_template));
3937 cam->vdev.priv = cam;
3939 cam->curframe = 0;
3940 for (i = 0; i < FRAME_NUM; i++) {
3941 cam->frame[i].width = 0;
3942 cam->frame[i].height = 0;
3943 cam->frame[i].state = FRAME_UNUSED;
3944 cam->frame[i].data = NULL;
3946 cam->decompressed_frame.width = 0;
3947 cam->decompressed_frame.height = 0;
3948 cam->decompressed_frame.state = FRAME_UNUSED;
3949 cam->decompressed_frame.data = NULL;
3952 struct cam_data *cpia_register_camera(struct cpia_camera_ops *ops, void *lowlevel)
3954 struct cam_data *camera;
3956 if ((camera = kmalloc(sizeof(struct cam_data), GFP_KERNEL)) == NULL)
3957 return NULL;
3960 init_camera_struct( camera, ops );
3961 camera->lowlevel_data = lowlevel;
3963 /* register v4l device */
3964 if (video_register_device(&camera->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
3965 kfree(camera);
3966 printk(KERN_DEBUG "video_register_device failed\n");
3967 return NULL;
3970 /* get version information from camera: open/reset/close */
3972 /* open cpia */
3973 if (camera->ops->open(camera->lowlevel_data))
3974 return camera;
3976 /* reset the camera */
3977 if (reset_camera(camera) != 0) {
3978 camera->ops->close(camera->lowlevel_data);
3979 return camera;
3982 /* close cpia */
3983 camera->ops->close(camera->lowlevel_data);
3985 #ifdef CONFIG_PROC_FS
3986 create_proc_cpia_cam(camera);
3987 #endif
3989 printk(KERN_INFO " CPiA Version: %d.%02d (%d.%d)\n",
3990 camera->params.version.firmwareVersion,
3991 camera->params.version.firmwareRevision,
3992 camera->params.version.vcVersion,
3993 camera->params.version.vcRevision);
3994 printk(KERN_INFO " CPiA PnP-ID: %04x:%04x:%04x\n",
3995 camera->params.pnpID.vendor,
3996 camera->params.pnpID.product,
3997 camera->params.pnpID.deviceRevision);
3998 printk(KERN_INFO " VP-Version: %d.%d %04x\n",
3999 camera->params.vpVersion.vpVersion,
4000 camera->params.vpVersion.vpRevision,
4001 camera->params.vpVersion.cameraHeadID);
4003 return camera;
4006 void cpia_unregister_camera(struct cam_data *cam)
4008 DBG("unregistering video\n");
4009 video_unregister_device(&cam->vdev);
4010 if (cam->open_count) {
4011 put_cam(cam->ops);
4012 DBG("camera open -- setting ops to NULL\n");
4013 cam->ops = NULL;
4016 #ifdef CONFIG_PROC_FS
4017 DBG("destroying /proc/cpia/video%d\n", cam->vdev.minor);
4018 destroy_proc_cpia_cam(cam);
4019 #endif
4020 if (!cam->open_count) {
4021 DBG("freeing camera\n");
4022 kfree(cam);
4026 static int __init cpia_init(void)
4028 printk(KERN_INFO "%s v%d.%d.%d\n", ABOUT,
4029 CPIA_MAJ_VER, CPIA_MIN_VER, CPIA_PATCH_VER);
4031 printk(KERN_WARNING "Since in-kernel colorspace conversion is not "
4032 "allowed, it is disabled by default now. Users should fix the "
4033 "applications in case they don't work without conversion "
4034 "reenabled by setting the 'colorspace_conv' module "
4035 "parameter to 1\n");
4037 #ifdef CONFIG_PROC_FS
4038 proc_cpia_create();
4039 #endif
4041 return 0;
4044 static void __exit cpia_exit(void)
4046 #ifdef CONFIG_PROC_FS
4047 proc_cpia_destroy();
4048 #endif
4051 module_init(cpia_init);
4052 module_exit(cpia_exit);
4054 /* Exported symbols for modules. */
4056 EXPORT_SYMBOL(cpia_register_camera);
4057 EXPORT_SYMBOL(cpia_unregister_camera);