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