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