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