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