4 * Supports CPiA based Video Camera's.
6 * (C) Copyright 1999-2000 Peter Pregler
7 * (C) Copyright 1999-2000 Scott J. Bertin
8 * (C) Copyright 1999-2000 Johannes Erdfelt <johannes@erdfelt.com>
9 * (C) Copyright 2000 STMicroelectronics
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26 /* define _CPIA_DEBUG_ for verbose debug output (see cpia.h) */
27 /* #define _CPIA_DEBUG_ 1 */
30 #include <linux/module.h>
31 #include <linux/init.h>
33 #include <linux/vmalloc.h>
34 #include <linux/sched.h>
35 #include <linux/seq_file.h>
36 #include <linux/slab.h>
37 #include <linux/proc_fs.h>
38 #include <linux/ctype.h>
39 #include <linux/pagemap.h>
40 #include <linux/delay.h>
42 #include <linux/mutex.h>
46 static int video_nr
= -1;
49 module_param(video_nr
, int, 0);
50 MODULE_AUTHOR("Scott J. Bertin <sbertin@securenym.net> & Peter Pregler <Peter_Pregler@email.com> & Johannes Erdfelt <johannes@erdfelt.com>");
51 MODULE_DESCRIPTION("V4L-driver for Vision CPiA based cameras");
52 MODULE_LICENSE("GPL");
53 MODULE_SUPPORTED_DEVICE("video");
56 static unsigned short colorspace_conv
;
57 module_param(colorspace_conv
, ushort
, 0444);
58 MODULE_PARM_DESC(colorspace_conv
,
59 " Colorspace conversion:"
60 "\n 0 = disable, 1 = enable"
61 "\n Default value is 0"
64 #define ABOUT "V4L-Driver for Vision CPiA based cameras"
66 #define CPIA_MODULE_CPIA (0<<5)
67 #define CPIA_MODULE_SYSTEM (1<<5)
68 #define CPIA_MODULE_VP_CTRL (5<<5)
69 #define CPIA_MODULE_CAPTURE (6<<5)
70 #define CPIA_MODULE_DEBUG (7<<5)
72 #define INPUT (DATA_IN << 8)
73 #define OUTPUT (DATA_OUT << 8)
75 #define CPIA_COMMAND_GetCPIAVersion (INPUT | CPIA_MODULE_CPIA | 1)
76 #define CPIA_COMMAND_GetPnPID (INPUT | CPIA_MODULE_CPIA | 2)
77 #define CPIA_COMMAND_GetCameraStatus (INPUT | CPIA_MODULE_CPIA | 3)
78 #define CPIA_COMMAND_GotoHiPower (OUTPUT | CPIA_MODULE_CPIA | 4)
79 #define CPIA_COMMAND_GotoLoPower (OUTPUT | CPIA_MODULE_CPIA | 5)
80 #define CPIA_COMMAND_GotoSuspend (OUTPUT | CPIA_MODULE_CPIA | 7)
81 #define CPIA_COMMAND_GotoPassThrough (OUTPUT | CPIA_MODULE_CPIA | 8)
82 #define CPIA_COMMAND_ModifyCameraStatus (OUTPUT | CPIA_MODULE_CPIA | 10)
84 #define CPIA_COMMAND_ReadVCRegs (INPUT | CPIA_MODULE_SYSTEM | 1)
85 #define CPIA_COMMAND_WriteVCReg (OUTPUT | CPIA_MODULE_SYSTEM | 2)
86 #define CPIA_COMMAND_ReadMCPorts (INPUT | CPIA_MODULE_SYSTEM | 3)
87 #define CPIA_COMMAND_WriteMCPort (OUTPUT | CPIA_MODULE_SYSTEM | 4)
88 #define CPIA_COMMAND_SetBaudRate (OUTPUT | CPIA_MODULE_SYSTEM | 5)
89 #define CPIA_COMMAND_SetECPTiming (OUTPUT | CPIA_MODULE_SYSTEM | 6)
90 #define CPIA_COMMAND_ReadIDATA (INPUT | CPIA_MODULE_SYSTEM | 7)
91 #define CPIA_COMMAND_WriteIDATA (OUTPUT | CPIA_MODULE_SYSTEM | 8)
92 #define CPIA_COMMAND_GenericCall (OUTPUT | CPIA_MODULE_SYSTEM | 9)
93 #define CPIA_COMMAND_I2CStart (OUTPUT | CPIA_MODULE_SYSTEM | 10)
94 #define CPIA_COMMAND_I2CStop (OUTPUT | CPIA_MODULE_SYSTEM | 11)
95 #define CPIA_COMMAND_I2CWrite (OUTPUT | CPIA_MODULE_SYSTEM | 12)
96 #define CPIA_COMMAND_I2CRead (INPUT | CPIA_MODULE_SYSTEM | 13)
98 #define CPIA_COMMAND_GetVPVersion (INPUT | CPIA_MODULE_VP_CTRL | 1)
99 #define CPIA_COMMAND_ResetFrameCounter (INPUT | CPIA_MODULE_VP_CTRL | 2)
100 #define CPIA_COMMAND_SetColourParams (OUTPUT | CPIA_MODULE_VP_CTRL | 3)
101 #define CPIA_COMMAND_SetExposure (OUTPUT | CPIA_MODULE_VP_CTRL | 4)
102 #define CPIA_COMMAND_SetColourBalance (OUTPUT | CPIA_MODULE_VP_CTRL | 6)
103 #define CPIA_COMMAND_SetSensorFPS (OUTPUT | CPIA_MODULE_VP_CTRL | 7)
104 #define CPIA_COMMAND_SetVPDefaults (OUTPUT | CPIA_MODULE_VP_CTRL | 8)
105 #define CPIA_COMMAND_SetApcor (OUTPUT | CPIA_MODULE_VP_CTRL | 9)
106 #define CPIA_COMMAND_SetFlickerCtrl (OUTPUT | CPIA_MODULE_VP_CTRL | 10)
107 #define CPIA_COMMAND_SetVLOffset (OUTPUT | CPIA_MODULE_VP_CTRL | 11)
108 #define CPIA_COMMAND_GetColourParams (INPUT | CPIA_MODULE_VP_CTRL | 16)
109 #define CPIA_COMMAND_GetColourBalance (INPUT | CPIA_MODULE_VP_CTRL | 17)
110 #define CPIA_COMMAND_GetExposure (INPUT | CPIA_MODULE_VP_CTRL | 18)
111 #define CPIA_COMMAND_SetSensorMatrix (OUTPUT | CPIA_MODULE_VP_CTRL | 19)
112 #define CPIA_COMMAND_ColourBars (OUTPUT | CPIA_MODULE_VP_CTRL | 25)
113 #define CPIA_COMMAND_ReadVPRegs (INPUT | CPIA_MODULE_VP_CTRL | 30)
114 #define CPIA_COMMAND_WriteVPReg (OUTPUT | CPIA_MODULE_VP_CTRL | 31)
116 #define CPIA_COMMAND_GrabFrame (OUTPUT | CPIA_MODULE_CAPTURE | 1)
117 #define CPIA_COMMAND_UploadFrame (OUTPUT | CPIA_MODULE_CAPTURE | 2)
118 #define CPIA_COMMAND_SetGrabMode (OUTPUT | CPIA_MODULE_CAPTURE | 3)
119 #define CPIA_COMMAND_InitStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 4)
120 #define CPIA_COMMAND_FiniStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 5)
121 #define CPIA_COMMAND_StartStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 6)
122 #define CPIA_COMMAND_EndStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 7)
123 #define CPIA_COMMAND_SetFormat (OUTPUT | CPIA_MODULE_CAPTURE | 8)
124 #define CPIA_COMMAND_SetROI (OUTPUT | CPIA_MODULE_CAPTURE | 9)
125 #define CPIA_COMMAND_SetCompression (OUTPUT | CPIA_MODULE_CAPTURE | 10)
126 #define CPIA_COMMAND_SetCompressionTarget (OUTPUT | CPIA_MODULE_CAPTURE | 11)
127 #define CPIA_COMMAND_SetYUVThresh (OUTPUT | CPIA_MODULE_CAPTURE | 12)
128 #define CPIA_COMMAND_SetCompressionParams (OUTPUT | CPIA_MODULE_CAPTURE | 13)
129 #define CPIA_COMMAND_DiscardFrame (OUTPUT | CPIA_MODULE_CAPTURE | 14)
130 #define CPIA_COMMAND_GrabReset (OUTPUT | CPIA_MODULE_CAPTURE | 15)
132 #define CPIA_COMMAND_OutputRS232 (OUTPUT | CPIA_MODULE_DEBUG | 1)
133 #define CPIA_COMMAND_AbortProcess (OUTPUT | CPIA_MODULE_DEBUG | 4)
134 #define CPIA_COMMAND_SetDramPage (OUTPUT | CPIA_MODULE_DEBUG | 5)
135 #define CPIA_COMMAND_StartDramUpload (OUTPUT | CPIA_MODULE_DEBUG | 6)
136 #define CPIA_COMMAND_StartDummyDtream (OUTPUT | CPIA_MODULE_DEBUG | 8)
137 #define CPIA_COMMAND_AbortStream (OUTPUT | CPIA_MODULE_DEBUG | 9)
138 #define CPIA_COMMAND_DownloadDRAM (OUTPUT | CPIA_MODULE_DEBUG | 10)
139 #define CPIA_COMMAND_Null (OUTPUT | CPIA_MODULE_DEBUG | 11)
142 FRAME_READY
, /* Ready to grab into */
143 FRAME_GRABBING
, /* In the process of being grabbed into */
144 FRAME_DONE
, /* Finished grabbing, but not been synced yet */
145 FRAME_UNUSED
, /* Unused (no MCAPTURE) */
148 #define COMMAND_NONE 0x0000
149 #define COMMAND_SETCOMPRESSION 0x0001
150 #define COMMAND_SETCOMPRESSIONTARGET 0x0002
151 #define COMMAND_SETCOLOURPARAMS 0x0004
152 #define COMMAND_SETFORMAT 0x0008
153 #define COMMAND_PAUSE 0x0010
154 #define COMMAND_RESUME 0x0020
155 #define COMMAND_SETYUVTHRESH 0x0040
156 #define COMMAND_SETECPTIMING 0x0080
157 #define COMMAND_SETCOMPRESSIONPARAMS 0x0100
158 #define COMMAND_SETEXPOSURE 0x0200
159 #define COMMAND_SETCOLOURBALANCE 0x0400
160 #define COMMAND_SETSENSORFPS 0x0800
161 #define COMMAND_SETAPCOR 0x1000
162 #define COMMAND_SETFLICKERCTRL 0x2000
163 #define COMMAND_SETVLOFFSET 0x4000
164 #define COMMAND_SETLIGHTS 0x8000
166 #define ROUND_UP_EXP_FOR_FLICKER 15
168 /* Constants for automatic frame rate adjustment */
170 #define MAX_EXP_102 255
172 #define VERY_LOW_EXP 70
174 #define EXP_ACC_DARK 50
175 #define EXP_ACC_LIGHT 90
176 #define HIGH_COMP_102 160
181 /* Maximum number of 10ms loops to wait for the stream to become ready */
182 #define READY_TIMEOUT 100
184 /* Developer's Guide Table 5 p 3-34
185 * indexed by [mains][sensorFps.baserate][sensorFps.divisor]*/
186 static u8 flicker_jumps
[2][2][4] =
187 { { { 76, 38, 19, 9 }, { 92, 46, 23, 11 } },
188 { { 64, 32, 16, 8 }, { 76, 38, 19, 9} }
191 /* forward declaration of local function */
192 static void reset_camera_struct(struct cam_data
*cam
);
193 static int find_over_exposure(int brightness
);
194 static void set_flicker(struct cam_params
*params
, volatile u32
*command_flags
,
198 /**********************************************************************
202 **********************************************************************/
203 static void *rvmalloc(unsigned long size
)
208 size
= PAGE_ALIGN(size
);
209 mem
= vmalloc_32(size
);
213 memset(mem
, 0, size
); /* Clear the ram out, no junk to the user */
214 adr
= (unsigned long) mem
;
216 SetPageReserved(vmalloc_to_page((void *)adr
));
224 static void rvfree(void *mem
, unsigned long size
)
231 adr
= (unsigned long) mem
;
232 while ((long) size
> 0) {
233 ClearPageReserved(vmalloc_to_page((void *)adr
));
240 /**********************************************************************
244 **********************************************************************/
245 #ifdef CONFIG_PROC_FS
246 static struct proc_dir_entry
*cpia_proc_root
=NULL
;
248 static int cpia_proc_show(struct seq_file
*m
, void *v
)
250 struct cam_data
*cam
= m
->private;
254 seq_printf(m
, "read-only\n-----------------------\n");
255 seq_printf(m
, "V4L Driver version: %d.%d.%d\n",
256 CPIA_MAJ_VER
, CPIA_MIN_VER
, CPIA_PATCH_VER
);
257 seq_printf(m
, "CPIA Version: %d.%02d (%d.%d)\n",
258 cam
->params
.version
.firmwareVersion
,
259 cam
->params
.version
.firmwareRevision
,
260 cam
->params
.version
.vcVersion
,
261 cam
->params
.version
.vcRevision
);
262 seq_printf(m
, "CPIA PnP-ID: %04x:%04x:%04x\n",
263 cam
->params
.pnpID
.vendor
, cam
->params
.pnpID
.product
,
264 cam
->params
.pnpID
.deviceRevision
);
265 seq_printf(m
, "VP-Version: %d.%d %04x\n",
266 cam
->params
.vpVersion
.vpVersion
,
267 cam
->params
.vpVersion
.vpRevision
,
268 cam
->params
.vpVersion
.cameraHeadID
);
270 seq_printf(m
, "system_state: %#04x\n",
271 cam
->params
.status
.systemState
);
272 seq_printf(m
, "grab_state: %#04x\n",
273 cam
->params
.status
.grabState
);
274 seq_printf(m
, "stream_state: %#04x\n",
275 cam
->params
.status
.streamState
);
276 seq_printf(m
, "fatal_error: %#04x\n",
277 cam
->params
.status
.fatalError
);
278 seq_printf(m
, "cmd_error: %#04x\n",
279 cam
->params
.status
.cmdError
);
280 seq_printf(m
, "debug_flags: %#04x\n",
281 cam
->params
.status
.debugFlags
);
282 seq_printf(m
, "vp_status: %#04x\n",
283 cam
->params
.status
.vpStatus
);
284 seq_printf(m
, "error_code: %#04x\n",
285 cam
->params
.status
.errorCode
);
286 /* QX3 specific entries */
287 if (cam
->params
.qx3
.qx3_detected
) {
288 seq_printf(m
, "button: %4d\n",
289 cam
->params
.qx3
.button
);
290 seq_printf(m
, "cradled: %4d\n",
291 cam
->params
.qx3
.cradled
);
293 seq_printf(m
, "video_size: %s\n",
294 cam
->params
.format
.videoSize
== VIDEOSIZE_CIF
?
296 seq_printf(m
, "roi: (%3d, %3d) to (%3d, %3d)\n",
297 cam
->params
.roi
.colStart
*8,
298 cam
->params
.roi
.rowStart
*4,
299 cam
->params
.roi
.colEnd
*8,
300 cam
->params
.roi
.rowEnd
*4);
301 seq_printf(m
, "actual_fps: %3d\n", cam
->fps
);
302 seq_printf(m
, "transfer_rate: %4dkB/s\n",
305 seq_printf(m
, "\nread-write\n");
306 seq_printf(m
, "----------------------- current min"
307 " max default comment\n");
308 seq_printf(m
, "brightness: %8d %8d %8d %8d\n",
309 cam
->params
.colourParams
.brightness
, 0, 100, 50);
310 if (cam
->params
.version
.firmwareVersion
== 1 &&
311 cam
->params
.version
.firmwareRevision
== 2)
312 /* 1-02 firmware limits contrast to 80 */
317 seq_printf(m
, "contrast: %8d %8d %8d %8d"
319 cam
->params
.colourParams
.contrast
, 0, tmp
, 48);
320 seq_printf(m
, "saturation: %8d %8d %8d %8d\n",
321 cam
->params
.colourParams
.saturation
, 0, 100, 50);
322 tmp
= (25000+5000*cam
->params
.sensorFps
.baserate
)/
323 (1<<cam
->params
.sensorFps
.divisor
);
324 seq_printf(m
, "sensor_fps: %4d.%03d %8d %8d %8d\n",
325 tmp
/1000, tmp
%1000, 3, 30, 15);
326 seq_printf(m
, "stream_start_line: %8d %8d %8d %8d\n",
327 2*cam
->params
.streamStartLine
, 0,
328 cam
->params
.format
.videoSize
== VIDEOSIZE_CIF
? 288:144,
329 cam
->params
.format
.videoSize
== VIDEOSIZE_CIF
? 240:120);
330 seq_printf(m
, "sub_sample: %8s %8s %8s %8s\n",
331 cam
->params
.format
.subSample
== SUBSAMPLE_420
?
332 "420" : "422", "420", "422", "422");
333 seq_printf(m
, "yuv_order: %8s %8s %8s %8s\n",
334 cam
->params
.format
.yuvOrder
== YUVORDER_YUYV
?
335 "YUYV" : "UYVY", "YUYV" , "UYVY", "YUYV");
336 seq_printf(m
, "ecp_timing: %8s %8s %8s %8s\n",
337 cam
->params
.ecpTiming
? "slow" : "normal", "slow",
340 if (cam
->params
.colourBalance
.balanceMode
== 2) {
341 sprintf(tmpstr
, "auto");
343 sprintf(tmpstr
, "manual");
345 seq_printf(m
, "color_balance_mode: %8s %8s %8s"
346 " %8s\n", tmpstr
, "manual", "auto", "auto");
347 seq_printf(m
, "red_gain: %8d %8d %8d %8d\n",
348 cam
->params
.colourBalance
.redGain
, 0, 212, 32);
349 seq_printf(m
, "green_gain: %8d %8d %8d %8d\n",
350 cam
->params
.colourBalance
.greenGain
, 0, 212, 6);
351 seq_printf(m
, "blue_gain: %8d %8d %8d %8d\n",
352 cam
->params
.colourBalance
.blueGain
, 0, 212, 92);
354 if (cam
->params
.version
.firmwareVersion
== 1 &&
355 cam
->params
.version
.firmwareRevision
== 2)
356 /* 1-02 firmware limits gain to 2 */
357 sprintf(tmpstr
, "%8d %8d %8d", 1, 2, 2);
359 sprintf(tmpstr
, "%8d %8d %8d", 1, 8, 2);
361 if (cam
->params
.exposure
.gainMode
== 0)
362 seq_printf(m
, "max_gain: unknown %28s"
363 " powers of 2\n", tmpstr
);
365 seq_printf(m
, "max_gain: %8d %28s"
367 1<<(cam
->params
.exposure
.gainMode
-1), tmpstr
);
369 switch(cam
->params
.exposure
.expMode
) {
372 sprintf(tmpstr
, "manual");
375 sprintf(tmpstr
, "auto");
378 sprintf(tmpstr
, "unknown");
381 seq_printf(m
, "exposure_mode: %8s %8s %8s"
382 " %8s\n", tmpstr
, "manual", "auto", "auto");
383 seq_printf(m
, "centre_weight: %8s %8s %8s %8s\n",
384 (2-cam
->params
.exposure
.centreWeight
) ? "on" : "off",
386 seq_printf(m
, "gain: %8d %8d max_gain %8d 1,2,4,8 possible\n",
387 1<<cam
->params
.exposure
.gain
, 1, 1);
388 if (cam
->params
.version
.firmwareVersion
== 1 &&
389 cam
->params
.version
.firmwareRevision
== 2)
390 /* 1-02 firmware limits fineExp/2 to 127 */
395 seq_printf(m
, "fine_exp: %8d %8d %8d %8d\n",
396 cam
->params
.exposure
.fineExp
*2, 0, tmp
, 0);
397 if (cam
->params
.version
.firmwareVersion
== 1 &&
398 cam
->params
.version
.firmwareRevision
== 2)
399 /* 1-02 firmware limits coarseExpHi to 0 */
404 seq_printf(m
, "coarse_exp: %8d %8d %8d"
405 " %8d\n", cam
->params
.exposure
.coarseExpLo
+
406 256*cam
->params
.exposure
.coarseExpHi
, 0, tmp
, 185);
407 seq_printf(m
, "red_comp: %8d %8d %8d %8d\n",
408 cam
->params
.exposure
.redComp
, COMP_RED
, 255, COMP_RED
);
409 seq_printf(m
, "green1_comp: %8d %8d %8d %8d\n",
410 cam
->params
.exposure
.green1Comp
, COMP_GREEN1
, 255,
412 seq_printf(m
, "green2_comp: %8d %8d %8d %8d\n",
413 cam
->params
.exposure
.green2Comp
, COMP_GREEN2
, 255,
415 seq_printf(m
, "blue_comp: %8d %8d %8d %8d\n",
416 cam
->params
.exposure
.blueComp
, COMP_BLUE
, 255, COMP_BLUE
);
418 seq_printf(m
, "apcor_gain1: %#8x %#8x %#8x %#8x\n",
419 cam
->params
.apcor
.gain1
, 0, 0xff, 0x1c);
420 seq_printf(m
, "apcor_gain2: %#8x %#8x %#8x %#8x\n",
421 cam
->params
.apcor
.gain2
, 0, 0xff, 0x1a);
422 seq_printf(m
, "apcor_gain4: %#8x %#8x %#8x %#8x\n",
423 cam
->params
.apcor
.gain4
, 0, 0xff, 0x2d);
424 seq_printf(m
, "apcor_gain8: %#8x %#8x %#8x %#8x\n",
425 cam
->params
.apcor
.gain8
, 0, 0xff, 0x2a);
426 seq_printf(m
, "vl_offset_gain1: %8d %8d %8d %8d\n",
427 cam
->params
.vlOffset
.gain1
, 0, 255, 24);
428 seq_printf(m
, "vl_offset_gain2: %8d %8d %8d %8d\n",
429 cam
->params
.vlOffset
.gain2
, 0, 255, 28);
430 seq_printf(m
, "vl_offset_gain4: %8d %8d %8d %8d\n",
431 cam
->params
.vlOffset
.gain4
, 0, 255, 30);
432 seq_printf(m
, "vl_offset_gain8: %8d %8d %8d %8d\n",
433 cam
->params
.vlOffset
.gain8
, 0, 255, 30);
434 seq_printf(m
, "flicker_control: %8s %8s %8s %8s\n",
435 cam
->params
.flickerControl
.flickerMode
? "on" : "off",
437 seq_printf(m
, "mains_frequency: %8d %8d %8d %8d"
439 cam
->mainsFreq
? 60 : 50, 50, 60, 50);
440 if(cam
->params
.flickerControl
.allowableOverExposure
< 0)
441 seq_printf(m
, "allowable_overexposure: %4dauto auto %8d auto\n",
442 -cam
->params
.flickerControl
.allowableOverExposure
,
445 seq_printf(m
, "allowable_overexposure: %8d auto %8d auto\n",
446 cam
->params
.flickerControl
.allowableOverExposure
,
448 seq_printf(m
, "compression_mode: ");
449 switch(cam
->params
.compression
.mode
) {
450 case CPIA_COMPRESSION_NONE
:
451 seq_printf(m
, "%8s", "none");
453 case CPIA_COMPRESSION_AUTO
:
454 seq_printf(m
, "%8s", "auto");
456 case CPIA_COMPRESSION_MANUAL
:
457 seq_printf(m
, "%8s", "manual");
460 seq_printf(m
, "%8s", "unknown");
463 seq_printf(m
, " none,auto,manual auto\n");
464 seq_printf(m
, "decimation_enable: %8s %8s %8s %8s\n",
465 cam
->params
.compression
.decimation
==
466 DECIMATION_ENAB
? "on":"off", "off", "on",
468 seq_printf(m
, "compression_target: %9s %9s %9s %9s\n",
469 cam
->params
.compressionTarget
.frTargeting
==
470 CPIA_COMPRESSION_TARGET_FRAMERATE
?
471 "framerate":"quality",
472 "framerate", "quality", "quality");
473 seq_printf(m
, "target_framerate: %8d %8d %8d %8d\n",
474 cam
->params
.compressionTarget
.targetFR
, 1, 30, 15);
475 seq_printf(m
, "target_quality: %8d %8d %8d %8d\n",
476 cam
->params
.compressionTarget
.targetQ
, 1, 64, 5);
477 seq_printf(m
, "y_threshold: %8d %8d %8d %8d\n",
478 cam
->params
.yuvThreshold
.yThreshold
, 0, 31, 6);
479 seq_printf(m
, "uv_threshold: %8d %8d %8d %8d\n",
480 cam
->params
.yuvThreshold
.uvThreshold
, 0, 31, 6);
481 seq_printf(m
, "hysteresis: %8d %8d %8d %8d\n",
482 cam
->params
.compressionParams
.hysteresis
, 0, 255, 3);
483 seq_printf(m
, "threshold_max: %8d %8d %8d %8d\n",
484 cam
->params
.compressionParams
.threshMax
, 0, 255, 11);
485 seq_printf(m
, "small_step: %8d %8d %8d %8d\n",
486 cam
->params
.compressionParams
.smallStep
, 0, 255, 1);
487 seq_printf(m
, "large_step: %8d %8d %8d %8d\n",
488 cam
->params
.compressionParams
.largeStep
, 0, 255, 3);
489 seq_printf(m
, "decimation_hysteresis: %8d %8d %8d %8d\n",
490 cam
->params
.compressionParams
.decimationHysteresis
,
492 seq_printf(m
, "fr_diff_step_thresh: %8d %8d %8d %8d\n",
493 cam
->params
.compressionParams
.frDiffStepThresh
,
495 seq_printf(m
, "q_diff_step_thresh: %8d %8d %8d %8d\n",
496 cam
->params
.compressionParams
.qDiffStepThresh
,
498 seq_printf(m
, "decimation_thresh_mod: %8d %8d %8d %8d\n",
499 cam
->params
.compressionParams
.decimationThreshMod
,
501 /* QX3 specific entries */
502 if (cam
->params
.qx3
.qx3_detected
) {
503 seq_printf(m
, "toplight: %8s %8s %8s %8s\n",
504 cam
->params
.qx3
.toplight
? "on" : "off",
506 seq_printf(m
, "bottomlight: %8s %8s %8s %8s\n",
507 cam
->params
.qx3
.bottomlight
? "on" : "off",
514 static int cpia_proc_open(struct inode
*inode
, struct file
*file
)
516 return single_open(file
, cpia_proc_show
, PDE(inode
)->data
);
519 static int match(char *checkstr
, char **buffer
, size_t *count
,
520 int *find_colon
, int *err
)
522 int ret
, colon_found
= 1;
523 int len
= strlen(checkstr
);
524 ret
= (len
<= *count
&& strncmp(*buffer
, checkstr
, len
) == 0);
530 while (*count
&& (**buffer
== ' ' || **buffer
== '\t' ||
531 (!colon_found
&& **buffer
== ':'))) {
537 if (!*count
|| !colon_found
)
545 static unsigned long int value(char **buffer
, size_t *count
, int *err
)
548 unsigned long int ret
;
549 ret
= simple_strtoul(*buffer
, &p
, 0);
553 *count
-= p
- *buffer
;
559 static ssize_t
cpia_proc_write(struct file
*file
, const char __user
*buf
,
560 size_t count
, loff_t
*pos
)
562 struct cam_data
*cam
= PDE(file
->f_path
.dentry
->d_inode
)->data
;
563 struct cam_params new_params
;
565 int retval
, find_colon
;
567 unsigned long val
= 0;
568 u32 command_flags
= 0;
572 * This code to copy from buf to page is shamelessly copied
573 * from the comx driver
575 if (count
> PAGE_SIZE
) {
576 printk(KERN_ERR
"count is %zu > %d!!!\n", count
, (int)PAGE_SIZE
);
580 if (!(page
= (char *)__get_free_page(GFP_KERNEL
))) return -ENOMEM
;
582 if(copy_from_user(page
, buf
, count
))
588 if (page
[count
-1] == '\n')
589 page
[count
-1] = '\0';
590 else if (count
< PAGE_SIZE
)
592 else if (page
[count
]) {
599 if (mutex_lock_interruptible(&cam
->param_lock
))
603 * Skip over leading whitespace
605 while (count
&& isspace(*buffer
)) {
610 memcpy(&new_params
, &cam
->params
, sizeof(struct cam_params
));
611 new_mains
= cam
->mainsFreq
;
613 #define MATCH(x) (match(x, &buffer, &count, &find_colon, &retval))
614 #define VALUE (value(&buffer,&count, &retval))
615 #define FIRMWARE_VERSION(x,y) (new_params.version.firmwareVersion == (x) && \
616 new_params.version.firmwareRevision == (y))
619 while (count
&& !retval
) {
621 if (MATCH("brightness")) {
627 new_params
.colourParams
.brightness
= val
;
631 command_flags
|= COMMAND_SETCOLOURPARAMS
;
632 if(new_params
.flickerControl
.allowableOverExposure
< 0)
633 new_params
.flickerControl
.allowableOverExposure
=
634 -find_over_exposure(new_params
.colourParams
.brightness
);
635 if(new_params
.flickerControl
.flickerMode
!= 0)
636 command_flags
|= COMMAND_SETFLICKERCTRL
;
638 } else if (MATCH("contrast")) {
644 /* contrast is in steps of 8, so round*/
645 val
= ((val
+ 3) / 8) * 8;
646 /* 1-02 firmware limits contrast to 80*/
647 if (FIRMWARE_VERSION(1,2) && val
> 80)
650 new_params
.colourParams
.contrast
= val
;
654 command_flags
|= COMMAND_SETCOLOURPARAMS
;
655 } else if (MATCH("saturation")) {
661 new_params
.colourParams
.saturation
= val
;
665 command_flags
|= COMMAND_SETCOLOURPARAMS
;
666 } else if (MATCH("sensor_fps")) {
671 /* find values so that sensorFPS is minimized,
676 new_params
.sensorFps
.divisor
= 0;
677 new_params
.sensorFps
.baserate
= 1;
678 } else if (val
> 15) {
679 new_params
.sensorFps
.divisor
= 0;
680 new_params
.sensorFps
.baserate
= 0;
681 } else if (val
> 12) {
682 new_params
.sensorFps
.divisor
= 1;
683 new_params
.sensorFps
.baserate
= 1;
684 } else if (val
> 7) {
685 new_params
.sensorFps
.divisor
= 1;
686 new_params
.sensorFps
.baserate
= 0;
687 } else if (val
> 6) {
688 new_params
.sensorFps
.divisor
= 2;
689 new_params
.sensorFps
.baserate
= 1;
690 } else if (val
> 3) {
691 new_params
.sensorFps
.divisor
= 2;
692 new_params
.sensorFps
.baserate
= 0;
694 new_params
.sensorFps
.divisor
= 3;
695 /* Either base rate would work here */
696 new_params
.sensorFps
.baserate
= 1;
698 new_params
.flickerControl
.coarseJump
=
699 flicker_jumps
[new_mains
]
700 [new_params
.sensorFps
.baserate
]
701 [new_params
.sensorFps
.divisor
];
702 if (new_params
.flickerControl
.flickerMode
)
703 command_flags
|= COMMAND_SETFLICKERCTRL
;
705 command_flags
|= COMMAND_SETSENSORFPS
;
706 cam
->exposure_status
= EXPOSURE_NORMAL
;
707 } else if (MATCH("stream_start_line")) {
714 if (new_params
.format
.videoSize
== VIDEOSIZE_QCIF
)
717 new_params
.streamStartLine
= val
/2;
721 } else if (MATCH("sub_sample")) {
722 if (!retval
&& MATCH("420"))
723 new_params
.format
.subSample
= SUBSAMPLE_420
;
724 else if (!retval
&& MATCH("422"))
725 new_params
.format
.subSample
= SUBSAMPLE_422
;
729 command_flags
|= COMMAND_SETFORMAT
;
730 } else if (MATCH("yuv_order")) {
731 if (!retval
&& MATCH("YUYV"))
732 new_params
.format
.yuvOrder
= YUVORDER_YUYV
;
733 else if (!retval
&& MATCH("UYVY"))
734 new_params
.format
.yuvOrder
= YUVORDER_UYVY
;
738 command_flags
|= COMMAND_SETFORMAT
;
739 } else if (MATCH("ecp_timing")) {
740 if (!retval
&& MATCH("normal"))
741 new_params
.ecpTiming
= 0;
742 else if (!retval
&& MATCH("slow"))
743 new_params
.ecpTiming
= 1;
747 command_flags
|= COMMAND_SETECPTIMING
;
748 } else if (MATCH("color_balance_mode")) {
749 if (!retval
&& MATCH("manual"))
750 new_params
.colourBalance
.balanceMode
= 3;
751 else if (!retval
&& MATCH("auto"))
752 new_params
.colourBalance
.balanceMode
= 2;
756 command_flags
|= COMMAND_SETCOLOURBALANCE
;
757 } else if (MATCH("red_gain")) {
763 new_params
.colourBalance
.redGain
= val
;
764 new_params
.colourBalance
.balanceMode
= 1;
768 command_flags
|= COMMAND_SETCOLOURBALANCE
;
769 } else if (MATCH("green_gain")) {
775 new_params
.colourBalance
.greenGain
= val
;
776 new_params
.colourBalance
.balanceMode
= 1;
780 command_flags
|= COMMAND_SETCOLOURBALANCE
;
781 } else if (MATCH("blue_gain")) {
787 new_params
.colourBalance
.blueGain
= val
;
788 new_params
.colourBalance
.balanceMode
= 1;
792 command_flags
|= COMMAND_SETCOLOURBALANCE
;
793 } else if (MATCH("max_gain")) {
798 /* 1-02 firmware limits gain to 2 */
799 if (FIRMWARE_VERSION(1,2) && val
> 2)
803 new_params
.exposure
.gainMode
= 1;
806 new_params
.exposure
.gainMode
= 2;
809 new_params
.exposure
.gainMode
= 3;
812 new_params
.exposure
.gainMode
= 4;
819 command_flags
|= COMMAND_SETEXPOSURE
;
820 } else if (MATCH("exposure_mode")) {
821 if (!retval
&& MATCH("auto"))
822 new_params
.exposure
.expMode
= 2;
823 else if (!retval
&& MATCH("manual")) {
824 if (new_params
.exposure
.expMode
== 2)
825 new_params
.exposure
.expMode
= 3;
826 if(new_params
.flickerControl
.flickerMode
!= 0)
827 command_flags
|= COMMAND_SETFLICKERCTRL
;
828 new_params
.flickerControl
.flickerMode
= 0;
832 command_flags
|= COMMAND_SETEXPOSURE
;
833 } else if (MATCH("centre_weight")) {
834 if (!retval
&& MATCH("on"))
835 new_params
.exposure
.centreWeight
= 1;
836 else if (!retval
&& MATCH("off"))
837 new_params
.exposure
.centreWeight
= 2;
841 command_flags
|= COMMAND_SETEXPOSURE
;
842 } else if (MATCH("gain")) {
849 new_params
.exposure
.gain
= 0;
852 new_params
.exposure
.gain
= 1;
855 new_params
.exposure
.gain
= 2;
858 new_params
.exposure
.gain
= 3;
864 new_params
.exposure
.expMode
= 1;
865 if(new_params
.flickerControl
.flickerMode
!= 0)
866 command_flags
|= COMMAND_SETFLICKERCTRL
;
867 new_params
.flickerControl
.flickerMode
= 0;
868 command_flags
|= COMMAND_SETEXPOSURE
;
869 if (new_params
.exposure
.gain
>
870 new_params
.exposure
.gainMode
-1)
873 } else if (MATCH("fine_exp")) {
879 /* 1-02 firmware limits fineExp/2 to 127*/
880 if (FIRMWARE_VERSION(1,2) && val
> 127)
882 new_params
.exposure
.fineExp
= val
;
883 new_params
.exposure
.expMode
= 1;
884 command_flags
|= COMMAND_SETEXPOSURE
;
885 if(new_params
.flickerControl
.flickerMode
!= 0)
886 command_flags
|= COMMAND_SETFLICKERCTRL
;
887 new_params
.flickerControl
.flickerMode
= 0;
888 command_flags
|= COMMAND_SETFLICKERCTRL
;
892 } else if (MATCH("coarse_exp")) {
897 if (val
<= MAX_EXP
) {
898 if (FIRMWARE_VERSION(1,2) &&
901 new_params
.exposure
.coarseExpLo
=
903 new_params
.exposure
.coarseExpHi
=
905 new_params
.exposure
.expMode
= 1;
906 command_flags
|= COMMAND_SETEXPOSURE
;
907 if(new_params
.flickerControl
.flickerMode
!= 0)
908 command_flags
|= COMMAND_SETFLICKERCTRL
;
909 new_params
.flickerControl
.flickerMode
= 0;
910 command_flags
|= COMMAND_SETFLICKERCTRL
;
914 } else if (MATCH("red_comp")) {
919 if (val
>= COMP_RED
&& val
<= 255) {
920 new_params
.exposure
.redComp
= val
;
921 new_params
.exposure
.compMode
= 1;
922 command_flags
|= COMMAND_SETEXPOSURE
;
926 } else if (MATCH("green1_comp")) {
931 if (val
>= COMP_GREEN1
&& val
<= 255) {
932 new_params
.exposure
.green1Comp
= val
;
933 new_params
.exposure
.compMode
= 1;
934 command_flags
|= COMMAND_SETEXPOSURE
;
938 } else if (MATCH("green2_comp")) {
943 if (val
>= COMP_GREEN2
&& val
<= 255) {
944 new_params
.exposure
.green2Comp
= val
;
945 new_params
.exposure
.compMode
= 1;
946 command_flags
|= COMMAND_SETEXPOSURE
;
950 } else if (MATCH("blue_comp")) {
955 if (val
>= COMP_BLUE
&& val
<= 255) {
956 new_params
.exposure
.blueComp
= val
;
957 new_params
.exposure
.compMode
= 1;
958 command_flags
|= COMMAND_SETEXPOSURE
;
962 } else if (MATCH("apcor_gain1")) {
967 command_flags
|= COMMAND_SETAPCOR
;
969 new_params
.apcor
.gain1
= val
;
973 } else if (MATCH("apcor_gain2")) {
978 command_flags
|= COMMAND_SETAPCOR
;
980 new_params
.apcor
.gain2
= val
;
984 } else if (MATCH("apcor_gain4")) {
989 command_flags
|= COMMAND_SETAPCOR
;
991 new_params
.apcor
.gain4
= val
;
995 } else if (MATCH("apcor_gain8")) {
1000 command_flags
|= COMMAND_SETAPCOR
;
1002 new_params
.apcor
.gain8
= val
;
1006 } else if (MATCH("vl_offset_gain1")) {
1012 new_params
.vlOffset
.gain1
= val
;
1016 command_flags
|= COMMAND_SETVLOFFSET
;
1017 } else if (MATCH("vl_offset_gain2")) {
1023 new_params
.vlOffset
.gain2
= val
;
1027 command_flags
|= COMMAND_SETVLOFFSET
;
1028 } else if (MATCH("vl_offset_gain4")) {
1034 new_params
.vlOffset
.gain4
= val
;
1038 command_flags
|= COMMAND_SETVLOFFSET
;
1039 } else if (MATCH("vl_offset_gain8")) {
1045 new_params
.vlOffset
.gain8
= val
;
1049 command_flags
|= COMMAND_SETVLOFFSET
;
1050 } else if (MATCH("flicker_control")) {
1051 if (!retval
&& MATCH("on")) {
1052 set_flicker(&new_params
, &command_flags
, 1);
1053 } else if (!retval
&& MATCH("off")) {
1054 set_flicker(&new_params
, &command_flags
, 0);
1058 command_flags
|= COMMAND_SETFLICKERCTRL
;
1059 } else if (MATCH("mains_frequency")) {
1060 if (!retval
&& MATCH("50")) {
1062 new_params
.flickerControl
.coarseJump
=
1063 flicker_jumps
[new_mains
]
1064 [new_params
.sensorFps
.baserate
]
1065 [new_params
.sensorFps
.divisor
];
1066 if (new_params
.flickerControl
.flickerMode
)
1067 command_flags
|= COMMAND_SETFLICKERCTRL
;
1068 } else if (!retval
&& MATCH("60")) {
1070 new_params
.flickerControl
.coarseJump
=
1071 flicker_jumps
[new_mains
]
1072 [new_params
.sensorFps
.baserate
]
1073 [new_params
.sensorFps
.divisor
];
1074 if (new_params
.flickerControl
.flickerMode
)
1075 command_flags
|= COMMAND_SETFLICKERCTRL
;
1078 } else if (MATCH("allowable_overexposure")) {
1079 if (!retval
&& MATCH("auto")) {
1080 new_params
.flickerControl
.allowableOverExposure
=
1081 -find_over_exposure(new_params
.colourParams
.brightness
);
1082 if(new_params
.flickerControl
.flickerMode
!= 0)
1083 command_flags
|= COMMAND_SETFLICKERCTRL
;
1090 new_params
.flickerControl
.
1091 allowableOverExposure
= val
;
1092 if(new_params
.flickerControl
.flickerMode
!= 0)
1093 command_flags
|= COMMAND_SETFLICKERCTRL
;
1098 } else if (MATCH("compression_mode")) {
1099 if (!retval
&& MATCH("none"))
1100 new_params
.compression
.mode
=
1101 CPIA_COMPRESSION_NONE
;
1102 else if (!retval
&& MATCH("auto"))
1103 new_params
.compression
.mode
=
1104 CPIA_COMPRESSION_AUTO
;
1105 else if (!retval
&& MATCH("manual"))
1106 new_params
.compression
.mode
=
1107 CPIA_COMPRESSION_MANUAL
;
1111 command_flags
|= COMMAND_SETCOMPRESSION
;
1112 } else if (MATCH("decimation_enable")) {
1113 if (!retval
&& MATCH("off"))
1114 new_params
.compression
.decimation
= 0;
1115 else if (!retval
&& MATCH("on"))
1116 new_params
.compression
.decimation
= 1;
1120 command_flags
|= COMMAND_SETCOMPRESSION
;
1121 } else if (MATCH("compression_target")) {
1122 if (!retval
&& MATCH("quality"))
1123 new_params
.compressionTarget
.frTargeting
=
1124 CPIA_COMPRESSION_TARGET_QUALITY
;
1125 else if (!retval
&& MATCH("framerate"))
1126 new_params
.compressionTarget
.frTargeting
=
1127 CPIA_COMPRESSION_TARGET_FRAMERATE
;
1131 command_flags
|= COMMAND_SETCOMPRESSIONTARGET
;
1132 } else if (MATCH("target_framerate")) {
1137 if(val
> 0 && val
<= 30)
1138 new_params
.compressionTarget
.targetFR
= val
;
1142 command_flags
|= COMMAND_SETCOMPRESSIONTARGET
;
1143 } else if (MATCH("target_quality")) {
1148 if(val
> 0 && val
<= 64)
1149 new_params
.compressionTarget
.targetQ
= val
;
1153 command_flags
|= COMMAND_SETCOMPRESSIONTARGET
;
1154 } else if (MATCH("y_threshold")) {
1160 new_params
.yuvThreshold
.yThreshold
= val
;
1164 command_flags
|= COMMAND_SETYUVTHRESH
;
1165 } else if (MATCH("uv_threshold")) {
1171 new_params
.yuvThreshold
.uvThreshold
= val
;
1175 command_flags
|= COMMAND_SETYUVTHRESH
;
1176 } else if (MATCH("hysteresis")) {
1182 new_params
.compressionParams
.hysteresis
= val
;
1186 command_flags
|= COMMAND_SETCOMPRESSIONPARAMS
;
1187 } else if (MATCH("threshold_max")) {
1193 new_params
.compressionParams
.threshMax
= val
;
1197 command_flags
|= COMMAND_SETCOMPRESSIONPARAMS
;
1198 } else if (MATCH("small_step")) {
1204 new_params
.compressionParams
.smallStep
= val
;
1208 command_flags
|= COMMAND_SETCOMPRESSIONPARAMS
;
1209 } else if (MATCH("large_step")) {
1215 new_params
.compressionParams
.largeStep
= val
;
1219 command_flags
|= COMMAND_SETCOMPRESSIONPARAMS
;
1220 } else if (MATCH("decimation_hysteresis")) {
1226 new_params
.compressionParams
.decimationHysteresis
= val
;
1230 command_flags
|= COMMAND_SETCOMPRESSIONPARAMS
;
1231 } else if (MATCH("fr_diff_step_thresh")) {
1237 new_params
.compressionParams
.frDiffStepThresh
= val
;
1241 command_flags
|= COMMAND_SETCOMPRESSIONPARAMS
;
1242 } else if (MATCH("q_diff_step_thresh")) {
1248 new_params
.compressionParams
.qDiffStepThresh
= val
;
1252 command_flags
|= COMMAND_SETCOMPRESSIONPARAMS
;
1253 } else if (MATCH("decimation_thresh_mod")) {
1259 new_params
.compressionParams
.decimationThreshMod
= val
;
1263 command_flags
|= COMMAND_SETCOMPRESSIONPARAMS
;
1264 } else if (MATCH("toplight")) {
1265 if (!retval
&& MATCH("on"))
1266 new_params
.qx3
.toplight
= 1;
1267 else if (!retval
&& MATCH("off"))
1268 new_params
.qx3
.toplight
= 0;
1271 command_flags
|= COMMAND_SETLIGHTS
;
1272 } else if (MATCH("bottomlight")) {
1273 if (!retval
&& MATCH("on"))
1274 new_params
.qx3
.bottomlight
= 1;
1275 else if (!retval
&& MATCH("off"))
1276 new_params
.qx3
.bottomlight
= 0;
1279 command_flags
|= COMMAND_SETLIGHTS
;
1281 DBG("No match found\n");
1286 while (count
&& isspace(*buffer
) && *buffer
!= '\n') {
1291 if (*buffer
== '\0' && count
!= 1)
1293 else if (*buffer
!= '\n' && *buffer
!= ';' &&
1305 #undef FIRMWARE_VERSION
1307 if (command_flags
& COMMAND_SETCOLOURPARAMS
) {
1308 /* Adjust cam->vp to reflect these changes */
1309 cam
->vp
.brightness
=
1310 new_params
.colourParams
.brightness
*65535/100;
1312 new_params
.colourParams
.contrast
*65535/100;
1314 new_params
.colourParams
.saturation
*65535/100;
1316 if((command_flags
& COMMAND_SETEXPOSURE
) &&
1317 new_params
.exposure
.expMode
== 2)
1318 cam
->exposure_status
= EXPOSURE_NORMAL
;
1320 memcpy(&cam
->params
, &new_params
, sizeof(struct cam_params
));
1321 cam
->mainsFreq
= new_mains
;
1322 cam
->cmd_queue
|= command_flags
;
1325 DBG("error: %d\n", retval
);
1327 mutex_unlock(&cam
->param_lock
);
1330 free_page((unsigned long)page
);
1334 static const struct file_operations cpia_proc_fops
= {
1335 .owner
= THIS_MODULE
,
1336 .open
= cpia_proc_open
,
1338 .llseek
= seq_lseek
,
1339 .release
= single_release
,
1340 .write
= cpia_proc_write
,
1343 static void create_proc_cpia_cam(struct cam_data
*cam
)
1345 struct proc_dir_entry
*ent
;
1347 if (!cpia_proc_root
|| !cam
)
1350 ent
= proc_create_data(video_device_node_name(&cam
->vdev
),
1351 S_IRUGO
|S_IWUSR
, cpia_proc_root
,
1352 &cpia_proc_fops
, cam
);
1357 size of the proc entry is 3736 bytes for the standard webcam;
1358 the extra features of the QX3 microscope add 189 bytes.
1359 (we have not yet probed the camera to see which type it is).
1361 ent
->size
= 3736 + 189;
1362 cam
->proc_entry
= ent
;
1365 static void destroy_proc_cpia_cam(struct cam_data
*cam
)
1367 if (!cam
|| !cam
->proc_entry
)
1370 remove_proc_entry(video_device_node_name(&cam
->vdev
), cpia_proc_root
);
1371 cam
->proc_entry
= NULL
;
1374 static void proc_cpia_create(void)
1376 cpia_proc_root
= proc_mkdir("cpia", NULL
);
1378 if (!cpia_proc_root
)
1379 LOG("Unable to initialise /proc/cpia\n");
1382 static void __exit
proc_cpia_destroy(void)
1384 remove_proc_entry("cpia", NULL
);
1386 #endif /* CONFIG_PROC_FS */
1388 /* ----------------------- debug functions ---------------------- */
1390 #define printstatus(cam) \
1391 DBG("%02x %02x %02x %02x %02x %02x %02x %02x\n",\
1392 cam->params.status.systemState, cam->params.status.grabState, \
1393 cam->params.status.streamState, cam->params.status.fatalError, \
1394 cam->params.status.cmdError, cam->params.status.debugFlags, \
1395 cam->params.status.vpStatus, cam->params.status.errorCode);
1397 /* ----------------------- v4l helpers -------------------------- */
1399 /* supported frame palettes and depths */
1400 static inline int valid_mode(u16 palette
, u16 depth
)
1402 if ((palette
== VIDEO_PALETTE_YUV422
&& depth
== 16) ||
1403 (palette
== VIDEO_PALETTE_YUYV
&& depth
== 16))
1406 if (colorspace_conv
)
1407 return (palette
== VIDEO_PALETTE_GREY
&& depth
== 8) ||
1408 (palette
== VIDEO_PALETTE_RGB555
&& depth
== 16) ||
1409 (palette
== VIDEO_PALETTE_RGB565
&& depth
== 16) ||
1410 (palette
== VIDEO_PALETTE_RGB24
&& depth
== 24) ||
1411 (palette
== VIDEO_PALETTE_RGB32
&& depth
== 32) ||
1412 (palette
== VIDEO_PALETTE_UYVY
&& depth
== 16);
1417 static int match_videosize( int width
, int height
)
1419 /* return the best match, where 'best' is as always
1420 * the largest that is not bigger than what is requested. */
1421 if (width
>=352 && height
>=288)
1422 return VIDEOSIZE_352_288
; /* CIF */
1424 if (width
>=320 && height
>=240)
1425 return VIDEOSIZE_320_240
; /* SIF */
1427 if (width
>=288 && height
>=216)
1428 return VIDEOSIZE_288_216
;
1430 if (width
>=256 && height
>=192)
1431 return VIDEOSIZE_256_192
;
1433 if (width
>=224 && height
>=168)
1434 return VIDEOSIZE_224_168
;
1436 if (width
>=192 && height
>=144)
1437 return VIDEOSIZE_192_144
;
1439 if (width
>=176 && height
>=144)
1440 return VIDEOSIZE_176_144
; /* QCIF */
1442 if (width
>=160 && height
>=120)
1443 return VIDEOSIZE_160_120
; /* QSIF */
1445 if (width
>=128 && height
>=96)
1446 return VIDEOSIZE_128_96
;
1448 if (width
>=88 && height
>=72)
1449 return VIDEOSIZE_88_72
;
1451 if (width
>=64 && height
>=48)
1452 return VIDEOSIZE_64_48
;
1454 if (width
>=48 && height
>=48)
1455 return VIDEOSIZE_48_48
;
1460 /* these are the capture sizes we support */
1461 static void set_vw_size(struct cam_data
*cam
)
1463 /* the col/row/start/end values are the result of simple math */
1464 /* study the SetROI-command in cpia developers guide p 2-22 */
1465 /* streamStartLine is set to the recommended value in the cpia */
1466 /* developers guide p 3-37 */
1467 switch(cam
->video_size
) {
1469 cam
->vw
.width
= 352;
1470 cam
->vw
.height
= 288;
1471 cam
->params
.format
.videoSize
=VIDEOSIZE_CIF
;
1472 cam
->params
.roi
.colStart
=0;
1473 cam
->params
.roi
.rowStart
=0;
1474 cam
->params
.streamStartLine
= 120;
1477 cam
->vw
.width
= 320;
1478 cam
->vw
.height
= 240;
1479 cam
->params
.format
.videoSize
=VIDEOSIZE_CIF
;
1480 cam
->params
.roi
.colStart
=2;
1481 cam
->params
.roi
.rowStart
=6;
1482 cam
->params
.streamStartLine
= 120;
1484 case VIDEOSIZE_288_216
:
1485 cam
->vw
.width
= 288;
1486 cam
->vw
.height
= 216;
1487 cam
->params
.format
.videoSize
=VIDEOSIZE_CIF
;
1488 cam
->params
.roi
.colStart
=4;
1489 cam
->params
.roi
.rowStart
=9;
1490 cam
->params
.streamStartLine
= 120;
1492 case VIDEOSIZE_256_192
:
1493 cam
->vw
.width
= 256;
1494 cam
->vw
.height
= 192;
1495 cam
->params
.format
.videoSize
=VIDEOSIZE_CIF
;
1496 cam
->params
.roi
.colStart
=6;
1497 cam
->params
.roi
.rowStart
=12;
1498 cam
->params
.streamStartLine
= 120;
1500 case VIDEOSIZE_224_168
:
1501 cam
->vw
.width
= 224;
1502 cam
->vw
.height
= 168;
1503 cam
->params
.format
.videoSize
=VIDEOSIZE_CIF
;
1504 cam
->params
.roi
.colStart
=8;
1505 cam
->params
.roi
.rowStart
=15;
1506 cam
->params
.streamStartLine
= 120;
1508 case VIDEOSIZE_192_144
:
1509 cam
->vw
.width
= 192;
1510 cam
->vw
.height
= 144;
1511 cam
->params
.format
.videoSize
=VIDEOSIZE_CIF
;
1512 cam
->params
.roi
.colStart
=10;
1513 cam
->params
.roi
.rowStart
=18;
1514 cam
->params
.streamStartLine
= 120;
1516 case VIDEOSIZE_QCIF
:
1517 cam
->vw
.width
= 176;
1518 cam
->vw
.height
= 144;
1519 cam
->params
.format
.videoSize
=VIDEOSIZE_QCIF
;
1520 cam
->params
.roi
.colStart
=0;
1521 cam
->params
.roi
.rowStart
=0;
1522 cam
->params
.streamStartLine
= 60;
1524 case VIDEOSIZE_QSIF
:
1525 cam
->vw
.width
= 160;
1526 cam
->vw
.height
= 120;
1527 cam
->params
.format
.videoSize
=VIDEOSIZE_QCIF
;
1528 cam
->params
.roi
.colStart
=1;
1529 cam
->params
.roi
.rowStart
=3;
1530 cam
->params
.streamStartLine
= 60;
1532 case VIDEOSIZE_128_96
:
1533 cam
->vw
.width
= 128;
1534 cam
->vw
.height
= 96;
1535 cam
->params
.format
.videoSize
=VIDEOSIZE_QCIF
;
1536 cam
->params
.roi
.colStart
=3;
1537 cam
->params
.roi
.rowStart
=6;
1538 cam
->params
.streamStartLine
= 60;
1540 case VIDEOSIZE_88_72
:
1542 cam
->vw
.height
= 72;
1543 cam
->params
.format
.videoSize
=VIDEOSIZE_QCIF
;
1544 cam
->params
.roi
.colStart
=5;
1545 cam
->params
.roi
.rowStart
=9;
1546 cam
->params
.streamStartLine
= 60;
1548 case VIDEOSIZE_64_48
:
1550 cam
->vw
.height
= 48;
1551 cam
->params
.format
.videoSize
=VIDEOSIZE_QCIF
;
1552 cam
->params
.roi
.colStart
=7;
1553 cam
->params
.roi
.rowStart
=12;
1554 cam
->params
.streamStartLine
= 60;
1556 case VIDEOSIZE_48_48
:
1558 cam
->vw
.height
= 48;
1559 cam
->params
.format
.videoSize
=VIDEOSIZE_QCIF
;
1560 cam
->params
.roi
.colStart
=8;
1561 cam
->params
.roi
.rowStart
=6;
1562 cam
->params
.streamStartLine
= 60;
1565 LOG("bad videosize value: %d\n", cam
->video_size
);
1569 if(cam
->vc
.width
== 0)
1570 cam
->vc
.width
= cam
->vw
.width
;
1571 if(cam
->vc
.height
== 0)
1572 cam
->vc
.height
= cam
->vw
.height
;
1574 cam
->params
.roi
.colStart
+= cam
->vc
.x
>> 3;
1575 cam
->params
.roi
.colEnd
= cam
->params
.roi
.colStart
+
1576 (cam
->vc
.width
>> 3);
1577 cam
->params
.roi
.rowStart
+= cam
->vc
.y
>> 2;
1578 cam
->params
.roi
.rowEnd
= cam
->params
.roi
.rowStart
+
1579 (cam
->vc
.height
>> 2);
1584 static int allocate_frame_buf(struct cam_data
*cam
)
1588 cam
->frame_buf
= rvmalloc(FRAME_NUM
* CPIA_MAX_FRAME_SIZE
);
1589 if (!cam
->frame_buf
)
1592 for (i
= 0; i
< FRAME_NUM
; i
++)
1593 cam
->frame
[i
].data
= cam
->frame_buf
+ i
* CPIA_MAX_FRAME_SIZE
;
1598 static int free_frame_buf(struct cam_data
*cam
)
1602 rvfree(cam
->frame_buf
, FRAME_NUM
*CPIA_MAX_FRAME_SIZE
);
1603 cam
->frame_buf
= NULL
;
1604 for (i
=0; i
< FRAME_NUM
; i
++)
1605 cam
->frame
[i
].data
= NULL
;
1611 static inline void free_frames(struct cpia_frame frame
[FRAME_NUM
])
1615 for (i
=0; i
< FRAME_NUM
; i
++)
1616 frame
[i
].state
= FRAME_UNUSED
;
1620 /**********************************************************************
1624 **********************************************************************/
1625 /* send an arbitrary command to the camera */
1626 static int do_command(struct cam_data
*cam
, u16 command
, u8 a
, u8 b
, u8 c
, u8 d
)
1628 int retval
, datasize
;
1632 case CPIA_COMMAND_GetCPIAVersion
:
1633 case CPIA_COMMAND_GetPnPID
:
1634 case CPIA_COMMAND_GetCameraStatus
:
1635 case CPIA_COMMAND_GetVPVersion
:
1638 case CPIA_COMMAND_GetColourParams
:
1639 case CPIA_COMMAND_GetColourBalance
:
1640 case CPIA_COMMAND_GetExposure
:
1641 mutex_lock(&cam
->param_lock
);
1644 case CPIA_COMMAND_ReadMCPorts
:
1645 case CPIA_COMMAND_ReadVCRegs
:
1653 cmd
[0] = command
>>8;
1654 cmd
[1] = command
&0xff;
1662 retval
= cam
->ops
->transferCmd(cam
->lowlevel_data
, cmd
, data
);
1664 DBG("%x - failed, retval=%d\n", command
, retval
);
1665 if (command
== CPIA_COMMAND_GetColourParams
||
1666 command
== CPIA_COMMAND_GetColourBalance
||
1667 command
== CPIA_COMMAND_GetExposure
)
1668 mutex_unlock(&cam
->param_lock
);
1671 case CPIA_COMMAND_GetCPIAVersion
:
1672 cam
->params
.version
.firmwareVersion
= data
[0];
1673 cam
->params
.version
.firmwareRevision
= data
[1];
1674 cam
->params
.version
.vcVersion
= data
[2];
1675 cam
->params
.version
.vcRevision
= data
[3];
1677 case CPIA_COMMAND_GetPnPID
:
1678 cam
->params
.pnpID
.vendor
= data
[0]+(((u16
)data
[1])<<8);
1679 cam
->params
.pnpID
.product
= data
[2]+(((u16
)data
[3])<<8);
1680 cam
->params
.pnpID
.deviceRevision
=
1681 data
[4]+(((u16
)data
[5])<<8);
1683 case CPIA_COMMAND_GetCameraStatus
:
1684 cam
->params
.status
.systemState
= data
[0];
1685 cam
->params
.status
.grabState
= data
[1];
1686 cam
->params
.status
.streamState
= data
[2];
1687 cam
->params
.status
.fatalError
= data
[3];
1688 cam
->params
.status
.cmdError
= data
[4];
1689 cam
->params
.status
.debugFlags
= data
[5];
1690 cam
->params
.status
.vpStatus
= data
[6];
1691 cam
->params
.status
.errorCode
= data
[7];
1693 case CPIA_COMMAND_GetVPVersion
:
1694 cam
->params
.vpVersion
.vpVersion
= data
[0];
1695 cam
->params
.vpVersion
.vpRevision
= data
[1];
1696 cam
->params
.vpVersion
.cameraHeadID
=
1697 data
[2]+(((u16
)data
[3])<<8);
1699 case CPIA_COMMAND_GetColourParams
:
1700 cam
->params
.colourParams
.brightness
= data
[0];
1701 cam
->params
.colourParams
.contrast
= data
[1];
1702 cam
->params
.colourParams
.saturation
= data
[2];
1703 mutex_unlock(&cam
->param_lock
);
1705 case CPIA_COMMAND_GetColourBalance
:
1706 cam
->params
.colourBalance
.redGain
= data
[0];
1707 cam
->params
.colourBalance
.greenGain
= data
[1];
1708 cam
->params
.colourBalance
.blueGain
= data
[2];
1709 mutex_unlock(&cam
->param_lock
);
1711 case CPIA_COMMAND_GetExposure
:
1712 cam
->params
.exposure
.gain
= data
[0];
1713 cam
->params
.exposure
.fineExp
= data
[1];
1714 cam
->params
.exposure
.coarseExpLo
= data
[2];
1715 cam
->params
.exposure
.coarseExpHi
= data
[3];
1716 cam
->params
.exposure
.redComp
= data
[4];
1717 cam
->params
.exposure
.green1Comp
= data
[5];
1718 cam
->params
.exposure
.green2Comp
= data
[6];
1719 cam
->params
.exposure
.blueComp
= data
[7];
1720 mutex_unlock(&cam
->param_lock
);
1723 case CPIA_COMMAND_ReadMCPorts
:
1724 if (!cam
->params
.qx3
.qx3_detected
)
1726 /* test button press */
1727 cam
->params
.qx3
.button
= ((data
[1] & 0x02) == 0);
1728 if (cam
->params
.qx3
.button
) {
1729 /* button pressed - unlock the latch */
1730 do_command(cam
,CPIA_COMMAND_WriteMCPort
,3,0xDF,0xDF,0);
1731 do_command(cam
,CPIA_COMMAND_WriteMCPort
,3,0xFF,0xFF,0);
1734 /* test whether microscope is cradled */
1735 cam
->params
.qx3
.cradled
= ((data
[2] & 0x40) == 0);
1745 /* send a command to the camera with an additional data transaction */
1746 static int do_command_extended(struct cam_data
*cam
, u16 command
,
1747 u8 a
, u8 b
, u8 c
, u8 d
,
1748 u8 e
, u8 f
, u8 g
, u8 h
,
1749 u8 i
, u8 j
, u8 k
, u8 l
)
1754 cmd
[0] = command
>>8;
1755 cmd
[1] = command
&0xff;
1771 retval
= cam
->ops
->transferCmd(cam
->lowlevel_data
, cmd
, data
);
1773 DBG("%x - failed\n", command
);
1778 /**********************************************************************
1780 * Colorspace conversion
1782 **********************************************************************/
1783 #define LIMIT(x) ((((x)>0xffffff)?0xff0000:(((x)<=0xffff)?0:(x)&0xff0000))>>16)
1785 static int convert420(unsigned char *yuv
, unsigned char *rgb
, int out_fmt
,
1786 int linesize
, int mmap_kludge
)
1788 int y
, u
, v
, r
, g
, b
, y1
;
1790 /* Odd lines use the same u and v as the previous line.
1791 * Because of compression, it is necessary to get this
1792 * information from the decoded image. */
1794 case VIDEO_PALETTE_RGB555
:
1795 y
= (*yuv
++ - 16) * 76310;
1796 y1
= (*yuv
- 16) * 76310;
1797 r
= ((*(rgb
+1-linesize
)) & 0x7c) << 1;
1798 g
= ((*(rgb
-linesize
)) & 0xe0) >> 4 |
1799 ((*(rgb
+1-linesize
)) & 0x03) << 6;
1800 b
= ((*(rgb
-linesize
)) & 0x1f) << 3;
1801 u
= (-53294 * r
- 104635 * g
+ 157929 * b
) / 5756495;
1802 v
= (157968 * r
- 132278 * g
- 25690 * b
) / 5366159;
1804 g
= -25690 * u
- 53294 * v
;
1806 *rgb
++ = ((LIMIT(g
+y
) & 0xf8) << 2) | (LIMIT(b
+y
) >> 3);
1807 *rgb
++ = ((LIMIT(r
+y
) & 0xf8) >> 1) | (LIMIT(g
+y
) >> 6);
1808 *rgb
++ = ((LIMIT(g
+y1
) & 0xf8) << 2) | (LIMIT(b
+y1
) >> 3);
1809 *rgb
= ((LIMIT(r
+y1
) & 0xf8) >> 1) | (LIMIT(g
+y1
) >> 6);
1811 case VIDEO_PALETTE_RGB565
:
1812 y
= (*yuv
++ - 16) * 76310;
1813 y1
= (*yuv
- 16) * 76310;
1814 r
= (*(rgb
+1-linesize
)) & 0xf8;
1815 g
= ((*(rgb
-linesize
)) & 0xe0) >> 3 |
1816 ((*(rgb
+1-linesize
)) & 0x07) << 5;
1817 b
= ((*(rgb
-linesize
)) & 0x1f) << 3;
1818 u
= (-53294 * r
- 104635 * g
+ 157929 * b
) / 5756495;
1819 v
= (157968 * r
- 132278 * g
- 25690 * b
) / 5366159;
1821 g
= -25690 * u
- 53294 * v
;
1823 *rgb
++ = ((LIMIT(g
+y
) & 0xfc) << 3) | (LIMIT(b
+y
) >> 3);
1824 *rgb
++ = (LIMIT(r
+y
) & 0xf8) | (LIMIT(g
+y
) >> 5);
1825 *rgb
++ = ((LIMIT(g
+y1
) & 0xfc) << 3) | (LIMIT(b
+y1
) >> 3);
1826 *rgb
= (LIMIT(r
+y1
) & 0xf8) | (LIMIT(g
+y1
) >> 5);
1829 case VIDEO_PALETTE_RGB24
:
1830 case VIDEO_PALETTE_RGB32
:
1831 y
= (*yuv
++ - 16) * 76310;
1832 y1
= (*yuv
- 16) * 76310;
1834 r
= *(rgb
+2-linesize
);
1835 g
= *(rgb
+1-linesize
);
1836 b
= *(rgb
-linesize
);
1838 r
= *(rgb
-linesize
);
1839 g
= *(rgb
+1-linesize
);
1840 b
= *(rgb
+2-linesize
);
1842 u
= (-53294 * r
- 104635 * g
+ 157929 * b
) / 5756495;
1843 v
= (157968 * r
- 132278 * g
- 25690 * b
) / 5366159;
1845 g
= -25690 * u
+ -53294 * v
;
1848 *rgb
++ = LIMIT(b
+y
);
1849 *rgb
++ = LIMIT(g
+y
);
1850 *rgb
++ = LIMIT(r
+y
);
1851 if(out_fmt
== VIDEO_PALETTE_RGB32
)
1853 *rgb
++ = LIMIT(b
+y1
);
1854 *rgb
++ = LIMIT(g
+y1
);
1857 *rgb
++ = LIMIT(r
+y
);
1858 *rgb
++ = LIMIT(g
+y
);
1859 *rgb
++ = LIMIT(b
+y
);
1860 if(out_fmt
== VIDEO_PALETTE_RGB32
)
1862 *rgb
++ = LIMIT(r
+y1
);
1863 *rgb
++ = LIMIT(g
+y1
);
1866 if(out_fmt
== VIDEO_PALETTE_RGB32
)
1869 case VIDEO_PALETTE_YUV422
:
1870 case VIDEO_PALETTE_YUYV
:
1872 u
= *(rgb
+1-linesize
);
1874 v
= *(rgb
+3-linesize
);
1880 case VIDEO_PALETTE_UYVY
:
1881 u
= *(rgb
-linesize
);
1883 v
= *(rgb
+2-linesize
);
1890 case VIDEO_PALETTE_GREY
:
1895 DBG("Empty: %d\n", out_fmt
);
1901 static int yuvconvert(unsigned char *yuv
, unsigned char *rgb
, int out_fmt
,
1902 int in_uyvy
, int mmap_kludge
)
1904 int y
, u
, v
, r
, g
, b
, y1
;
1907 case VIDEO_PALETTE_RGB555
:
1908 case VIDEO_PALETTE_RGB565
:
1909 case VIDEO_PALETTE_RGB24
:
1910 case VIDEO_PALETTE_RGB32
:
1913 y
= (*yuv
++ - 16) * 76310;
1915 y1
= (*yuv
- 16) * 76310;
1917 y
= (*yuv
++ - 16) * 76310;
1919 y1
= (*yuv
++ - 16) * 76310;
1923 g
= -25690 * u
+ -53294 * v
;
1931 /* Just to avoid compiler warnings */
1938 case VIDEO_PALETTE_RGB555
:
1939 *rgb
++ = ((LIMIT(g
+y
) & 0xf8) << 2) | (LIMIT(b
+y
) >> 3);
1940 *rgb
++ = ((LIMIT(r
+y
) & 0xf8) >> 1) | (LIMIT(g
+y
) >> 6);
1941 *rgb
++ = ((LIMIT(g
+y1
) & 0xf8) << 2) | (LIMIT(b
+y1
) >> 3);
1942 *rgb
= ((LIMIT(r
+y1
) & 0xf8) >> 1) | (LIMIT(g
+y1
) >> 6);
1944 case VIDEO_PALETTE_RGB565
:
1945 *rgb
++ = ((LIMIT(g
+y
) & 0xfc) << 3) | (LIMIT(b
+y
) >> 3);
1946 *rgb
++ = (LIMIT(r
+y
) & 0xf8) | (LIMIT(g
+y
) >> 5);
1947 *rgb
++ = ((LIMIT(g
+y1
) & 0xfc) << 3) | (LIMIT(b
+y1
) >> 3);
1948 *rgb
= (LIMIT(r
+y1
) & 0xf8) | (LIMIT(g
+y1
) >> 5);
1950 case VIDEO_PALETTE_RGB24
:
1952 *rgb
++ = LIMIT(b
+y
);
1953 *rgb
++ = LIMIT(g
+y
);
1954 *rgb
++ = LIMIT(r
+y
);
1955 *rgb
++ = LIMIT(b
+y1
);
1956 *rgb
++ = LIMIT(g
+y1
);
1959 *rgb
++ = LIMIT(r
+y
);
1960 *rgb
++ = LIMIT(g
+y
);
1961 *rgb
++ = LIMIT(b
+y
);
1962 *rgb
++ = LIMIT(r
+y1
);
1963 *rgb
++ = LIMIT(g
+y1
);
1967 case VIDEO_PALETTE_RGB32
:
1969 *rgb
++ = LIMIT(b
+y
);
1970 *rgb
++ = LIMIT(g
+y
);
1971 *rgb
++ = LIMIT(r
+y
);
1973 *rgb
++ = LIMIT(b
+y1
);
1974 *rgb
++ = LIMIT(g
+y1
);
1977 *rgb
++ = LIMIT(r
+y
);
1978 *rgb
++ = LIMIT(g
+y
);
1979 *rgb
++ = LIMIT(b
+y
);
1981 *rgb
++ = LIMIT(r
+y1
);
1982 *rgb
++ = LIMIT(g
+y1
);
1986 case VIDEO_PALETTE_GREY
:
1990 case VIDEO_PALETTE_YUV422
:
1991 case VIDEO_PALETTE_YUYV
:
1997 case VIDEO_PALETTE_UYVY
:
2004 DBG("Empty: %d\n", out_fmt
);
2009 static int skipcount(int count
, int fmt
)
2012 case VIDEO_PALETTE_GREY
:
2014 case VIDEO_PALETTE_RGB555
:
2015 case VIDEO_PALETTE_RGB565
:
2016 case VIDEO_PALETTE_YUV422
:
2017 case VIDEO_PALETTE_YUYV
:
2018 case VIDEO_PALETTE_UYVY
:
2020 case VIDEO_PALETTE_RGB24
:
2022 case VIDEO_PALETTE_RGB32
:
2029 static int parse_picture(struct cam_data
*cam
, int size
)
2031 u8
*obuf
, *ibuf
, *end_obuf
;
2032 int ll
, in_uyvy
, compressed
, decimation
, even_line
, origsize
, out_fmt
;
2033 int rows
, cols
, linesize
, subsample_422
;
2035 /* make sure params don't change while we are decoding */
2036 mutex_lock(&cam
->param_lock
);
2038 obuf
= cam
->decompressed_frame
.data
;
2039 end_obuf
= obuf
+CPIA_MAX_FRAME_SIZE
;
2040 ibuf
= cam
->raw_image
;
2042 out_fmt
= cam
->vp
.palette
;
2044 if ((ibuf
[0] != MAGIC_0
) || (ibuf
[1] != MAGIC_1
)) {
2045 LOG("header not found\n");
2046 mutex_unlock(&cam
->param_lock
);
2050 if ((ibuf
[16] != VIDEOSIZE_QCIF
) && (ibuf
[16] != VIDEOSIZE_CIF
)) {
2051 LOG("wrong video size\n");
2052 mutex_unlock(&cam
->param_lock
);
2056 if (ibuf
[17] != SUBSAMPLE_420
&& ibuf
[17] != SUBSAMPLE_422
) {
2057 LOG("illegal subtype %d\n",ibuf
[17]);
2058 mutex_unlock(&cam
->param_lock
);
2061 subsample_422
= ibuf
[17] == SUBSAMPLE_422
;
2063 if (ibuf
[18] != YUVORDER_YUYV
&& ibuf
[18] != YUVORDER_UYVY
) {
2064 LOG("illegal yuvorder %d\n",ibuf
[18]);
2065 mutex_unlock(&cam
->param_lock
);
2068 in_uyvy
= ibuf
[18] == YUVORDER_UYVY
;
2070 if ((ibuf
[24] != cam
->params
.roi
.colStart
) ||
2071 (ibuf
[25] != cam
->params
.roi
.colEnd
) ||
2072 (ibuf
[26] != cam
->params
.roi
.rowStart
) ||
2073 (ibuf
[27] != cam
->params
.roi
.rowEnd
)) {
2074 LOG("ROI mismatch\n");
2075 mutex_unlock(&cam
->param_lock
);
2078 cols
= 8*(ibuf
[25] - ibuf
[24]);
2079 rows
= 4*(ibuf
[27] - ibuf
[26]);
2082 if ((ibuf
[28] != NOT_COMPRESSED
) && (ibuf
[28] != COMPRESSED
)) {
2083 LOG("illegal compression %d\n",ibuf
[28]);
2084 mutex_unlock(&cam
->param_lock
);
2087 compressed
= (ibuf
[28] == COMPRESSED
);
2089 if (ibuf
[29] != NO_DECIMATION
&& ibuf
[29] != DECIMATION_ENAB
) {
2090 LOG("illegal decimation %d\n",ibuf
[29]);
2091 mutex_unlock(&cam
->param_lock
);
2094 decimation
= (ibuf
[29] == DECIMATION_ENAB
);
2096 cam
->params
.yuvThreshold
.yThreshold
= ibuf
[30];
2097 cam
->params
.yuvThreshold
.uvThreshold
= ibuf
[31];
2098 cam
->params
.status
.systemState
= ibuf
[32];
2099 cam
->params
.status
.grabState
= ibuf
[33];
2100 cam
->params
.status
.streamState
= ibuf
[34];
2101 cam
->params
.status
.fatalError
= ibuf
[35];
2102 cam
->params
.status
.cmdError
= ibuf
[36];
2103 cam
->params
.status
.debugFlags
= ibuf
[37];
2104 cam
->params
.status
.vpStatus
= ibuf
[38];
2105 cam
->params
.status
.errorCode
= ibuf
[39];
2106 cam
->fps
= ibuf
[41];
2107 mutex_unlock(&cam
->param_lock
);
2109 linesize
= skipcount(cols
, out_fmt
);
2110 ibuf
+= FRAME_HEADER_SIZE
;
2111 size
-= FRAME_HEADER_SIZE
;
2112 ll
= ibuf
[0] | (ibuf
[1] << 8);
2119 LOG("Insufficient data in buffer\n");
2124 if (!compressed
|| (compressed
&& !(*ibuf
& 1))) {
2125 if(subsample_422
|| even_line
) {
2126 obuf
+= yuvconvert(ibuf
, obuf
, out_fmt
,
2127 in_uyvy
, cam
->mmap_kludge
);
2131 /* SUBSAMPLE_420 on an odd line */
2132 obuf
+= convert420(ibuf
, obuf
,
2139 /*skip compressed interval from previous frame*/
2140 obuf
+= skipcount(*ibuf
>> 1, out_fmt
);
2141 if (obuf
> end_obuf
) {
2142 LOG("Insufficient buffer size\n");
2151 DBG("EOL not found giving up after %d/%d"
2152 " bytes\n", origsize
-size
, origsize
);
2156 ++ibuf
; /* skip over EOL */
2158 if ((size
> 3) && (ibuf
[0] == EOI
) && (ibuf
[1] == EOI
) &&
2159 (ibuf
[2] == EOI
) && (ibuf
[3] == EOI
)) {
2165 /* skip the odd lines for now */
2170 ll
= ibuf
[0] | (ibuf
[1] << 8);
2171 ibuf
+= 2; /* skip over line length */
2174 even_line
= !even_line
;
2176 LOG("line length was not 1 but %d after %d/%d bytes\n",
2177 ll
, origsize
-size
, origsize
);
2183 /* interpolate odd rows */
2186 prev
= cam
->decompressed_frame
.data
;
2187 obuf
= prev
+linesize
;
2188 next
= obuf
+linesize
;
2189 for(i
=1; i
<rows
-1; i
+=2) {
2190 for(j
=0; j
<linesize
; ++j
) {
2191 *obuf
++ = ((int)*prev
++ + *next
++) / 2;
2197 /* last row is odd, just copy previous row */
2198 memcpy(obuf
, prev
, linesize
);
2201 cam
->decompressed_frame
.count
= obuf
-cam
->decompressed_frame
.data
;
2203 return cam
->decompressed_frame
.count
;
2206 /* InitStreamCap wrapper to select correct start line */
2207 static inline int init_stream_cap(struct cam_data
*cam
)
2209 return do_command(cam
, CPIA_COMMAND_InitStreamCap
,
2210 0, cam
->params
.streamStartLine
, 0, 0);
2214 /* find_over_exposure
2215 * Finds a suitable value of OverExposure for use with SetFlickerCtrl
2216 * Some calculation is required because this value changes with the brightness
2217 * set with SetColourParameters
2219 * Parameters: Brightness - last brightness value set with SetColourParameters
2221 * Returns: OverExposure value to use with SetFlickerCtrl
2223 #define FLICKER_MAX_EXPOSURE 250
2224 #define FLICKER_ALLOWABLE_OVER_EXPOSURE 146
2225 #define FLICKER_BRIGHTNESS_CONSTANT 59
2226 static int find_over_exposure(int brightness
)
2228 int MaxAllowableOverExposure
, OverExposure
;
2230 MaxAllowableOverExposure
= FLICKER_MAX_EXPOSURE
- brightness
-
2231 FLICKER_BRIGHTNESS_CONSTANT
;
2233 if (MaxAllowableOverExposure
< FLICKER_ALLOWABLE_OVER_EXPOSURE
) {
2234 OverExposure
= MaxAllowableOverExposure
;
2236 OverExposure
= FLICKER_ALLOWABLE_OVER_EXPOSURE
;
2239 return OverExposure
;
2241 #undef FLICKER_MAX_EXPOSURE
2242 #undef FLICKER_ALLOWABLE_OVER_EXPOSURE
2243 #undef FLICKER_BRIGHTNESS_CONSTANT
2245 /* update various camera modes and settings */
2246 static void dispatch_commands(struct cam_data
*cam
)
2248 mutex_lock(&cam
->param_lock
);
2249 if (cam
->cmd_queue
==COMMAND_NONE
) {
2250 mutex_unlock(&cam
->param_lock
);
2253 DEB_BYTE(cam
->cmd_queue
);
2254 DEB_BYTE(cam
->cmd_queue
>>8);
2255 if (cam
->cmd_queue
& COMMAND_SETFORMAT
) {
2256 do_command(cam
, CPIA_COMMAND_SetFormat
,
2257 cam
->params
.format
.videoSize
,
2258 cam
->params
.format
.subSample
,
2259 cam
->params
.format
.yuvOrder
, 0);
2260 do_command(cam
, CPIA_COMMAND_SetROI
,
2261 cam
->params
.roi
.colStart
, cam
->params
.roi
.colEnd
,
2262 cam
->params
.roi
.rowStart
, cam
->params
.roi
.rowEnd
);
2263 cam
->first_frame
= 1;
2266 if (cam
->cmd_queue
& COMMAND_SETCOLOURPARAMS
)
2267 do_command(cam
, CPIA_COMMAND_SetColourParams
,
2268 cam
->params
.colourParams
.brightness
,
2269 cam
->params
.colourParams
.contrast
,
2270 cam
->params
.colourParams
.saturation
, 0);
2272 if (cam
->cmd_queue
& COMMAND_SETAPCOR
)
2273 do_command(cam
, CPIA_COMMAND_SetApcor
,
2274 cam
->params
.apcor
.gain1
,
2275 cam
->params
.apcor
.gain2
,
2276 cam
->params
.apcor
.gain4
,
2277 cam
->params
.apcor
.gain8
);
2279 if (cam
->cmd_queue
& COMMAND_SETVLOFFSET
)
2280 do_command(cam
, CPIA_COMMAND_SetVLOffset
,
2281 cam
->params
.vlOffset
.gain1
,
2282 cam
->params
.vlOffset
.gain2
,
2283 cam
->params
.vlOffset
.gain4
,
2284 cam
->params
.vlOffset
.gain8
);
2286 if (cam
->cmd_queue
& COMMAND_SETEXPOSURE
) {
2287 do_command_extended(cam
, CPIA_COMMAND_SetExposure
,
2288 cam
->params
.exposure
.gainMode
,
2290 cam
->params
.exposure
.compMode
,
2291 cam
->params
.exposure
.centreWeight
,
2292 cam
->params
.exposure
.gain
,
2293 cam
->params
.exposure
.fineExp
,
2294 cam
->params
.exposure
.coarseExpLo
,
2295 cam
->params
.exposure
.coarseExpHi
,
2296 cam
->params
.exposure
.redComp
,
2297 cam
->params
.exposure
.green1Comp
,
2298 cam
->params
.exposure
.green2Comp
,
2299 cam
->params
.exposure
.blueComp
);
2300 if(cam
->params
.exposure
.expMode
!= 1) {
2301 do_command_extended(cam
, CPIA_COMMAND_SetExposure
,
2303 cam
->params
.exposure
.expMode
,
2305 cam
->params
.exposure
.gain
,
2306 cam
->params
.exposure
.fineExp
,
2307 cam
->params
.exposure
.coarseExpLo
,
2308 cam
->params
.exposure
.coarseExpHi
,
2313 if (cam
->cmd_queue
& COMMAND_SETCOLOURBALANCE
) {
2314 if (cam
->params
.colourBalance
.balanceMode
== 1) {
2315 do_command(cam
, CPIA_COMMAND_SetColourBalance
,
2317 cam
->params
.colourBalance
.redGain
,
2318 cam
->params
.colourBalance
.greenGain
,
2319 cam
->params
.colourBalance
.blueGain
);
2320 do_command(cam
, CPIA_COMMAND_SetColourBalance
,
2323 if (cam
->params
.colourBalance
.balanceMode
== 2) {
2324 do_command(cam
, CPIA_COMMAND_SetColourBalance
,
2327 if (cam
->params
.colourBalance
.balanceMode
== 3) {
2328 do_command(cam
, CPIA_COMMAND_SetColourBalance
,
2333 if (cam
->cmd_queue
& COMMAND_SETCOMPRESSIONTARGET
)
2334 do_command(cam
, CPIA_COMMAND_SetCompressionTarget
,
2335 cam
->params
.compressionTarget
.frTargeting
,
2336 cam
->params
.compressionTarget
.targetFR
,
2337 cam
->params
.compressionTarget
.targetQ
, 0);
2339 if (cam
->cmd_queue
& COMMAND_SETYUVTHRESH
)
2340 do_command(cam
, CPIA_COMMAND_SetYUVThresh
,
2341 cam
->params
.yuvThreshold
.yThreshold
,
2342 cam
->params
.yuvThreshold
.uvThreshold
, 0, 0);
2344 if (cam
->cmd_queue
& COMMAND_SETCOMPRESSIONPARAMS
)
2345 do_command_extended(cam
, CPIA_COMMAND_SetCompressionParams
,
2347 cam
->params
.compressionParams
.hysteresis
,
2348 cam
->params
.compressionParams
.threshMax
,
2349 cam
->params
.compressionParams
.smallStep
,
2350 cam
->params
.compressionParams
.largeStep
,
2351 cam
->params
.compressionParams
.decimationHysteresis
,
2352 cam
->params
.compressionParams
.frDiffStepThresh
,
2353 cam
->params
.compressionParams
.qDiffStepThresh
,
2354 cam
->params
.compressionParams
.decimationThreshMod
);
2356 if (cam
->cmd_queue
& COMMAND_SETCOMPRESSION
)
2357 do_command(cam
, CPIA_COMMAND_SetCompression
,
2358 cam
->params
.compression
.mode
,
2359 cam
->params
.compression
.decimation
, 0, 0);
2361 if (cam
->cmd_queue
& COMMAND_SETSENSORFPS
)
2362 do_command(cam
, CPIA_COMMAND_SetSensorFPS
,
2363 cam
->params
.sensorFps
.divisor
,
2364 cam
->params
.sensorFps
.baserate
, 0, 0);
2366 if (cam
->cmd_queue
& COMMAND_SETFLICKERCTRL
)
2367 do_command(cam
, CPIA_COMMAND_SetFlickerCtrl
,
2368 cam
->params
.flickerControl
.flickerMode
,
2369 cam
->params
.flickerControl
.coarseJump
,
2370 abs(cam
->params
.flickerControl
.allowableOverExposure
),
2373 if (cam
->cmd_queue
& COMMAND_SETECPTIMING
)
2374 do_command(cam
, CPIA_COMMAND_SetECPTiming
,
2375 cam
->params
.ecpTiming
, 0, 0, 0);
2377 if (cam
->cmd_queue
& COMMAND_PAUSE
)
2378 do_command(cam
, CPIA_COMMAND_EndStreamCap
, 0, 0, 0, 0);
2380 if (cam
->cmd_queue
& COMMAND_RESUME
)
2381 init_stream_cap(cam
);
2383 if (cam
->cmd_queue
& COMMAND_SETLIGHTS
&& cam
->params
.qx3
.qx3_detected
)
2385 int p1
= (cam
->params
.qx3
.bottomlight
== 0) << 1;
2386 int p2
= (cam
->params
.qx3
.toplight
== 0) << 3;
2387 do_command(cam
, CPIA_COMMAND_WriteVCReg
, 0x90, 0x8F, 0x50, 0);
2388 do_command(cam
, CPIA_COMMAND_WriteMCPort
, 2, 0, (p1
|p2
|0xE0), 0);
2391 cam
->cmd_queue
= COMMAND_NONE
;
2392 mutex_unlock(&cam
->param_lock
);
2398 static void set_flicker(struct cam_params
*params
, volatile u32
*command_flags
,
2401 /* Everything in here is from the Windows driver */
2402 #define FIRMWARE_VERSION(x,y) (params->version.firmwareVersion == (x) && \
2403 params->version.firmwareRevision == (y))
2404 /* define for compgain calculation */
2406 #define COMPGAIN(base, curexp, newexp) \
2407 (u8) ((((float) base - 128.0) * ((float) curexp / (float) newexp)) + 128.5)
2408 #define EXP_FROM_COMP(basecomp, curcomp, curexp) \
2409 (u16)((float)curexp * (float)(u8)(curcomp + 128) / (float)(u8)(basecomp - 128))
2411 /* equivalent functions without floating point math */
2412 #define COMPGAIN(base, curexp, newexp) \
2413 (u8)(128 + (((u32)(2*(base-128)*curexp + newexp)) / (2* newexp)) )
2414 #define EXP_FROM_COMP(basecomp, curcomp, curexp) \
2415 (u16)(((u32)(curexp * (u8)(curcomp + 128)) / (u8)(basecomp - 128)))
2419 int currentexp
= params
->exposure
.coarseExpLo
+
2420 params
->exposure
.coarseExpHi
*256;
2423 int cj
= params
->flickerControl
.coarseJump
;
2424 params
->flickerControl
.flickerMode
= 1;
2425 params
->flickerControl
.disabled
= 0;
2426 if(params
->exposure
.expMode
!= 2)
2427 *command_flags
|= COMMAND_SETEXPOSURE
;
2428 params
->exposure
.expMode
= 2;
2429 currentexp
= currentexp
<< params
->exposure
.gain
;
2430 params
->exposure
.gain
= 0;
2431 /* round down current exposure to nearest value */
2432 startexp
= (currentexp
+ ROUND_UP_EXP_FOR_FLICKER
) / cj
;
2435 startexp
= (startexp
* cj
) - 1;
2436 if(FIRMWARE_VERSION(1,2))
2437 while(startexp
> MAX_EXP_102
)
2440 while(startexp
> MAX_EXP
)
2442 params
->exposure
.coarseExpLo
= startexp
& 0xff;
2443 params
->exposure
.coarseExpHi
= startexp
>> 8;
2444 if (currentexp
> startexp
) {
2445 if (currentexp
> (2 * startexp
))
2446 currentexp
= 2 * startexp
;
2447 params
->exposure
.redComp
= COMPGAIN (COMP_RED
, currentexp
, startexp
);
2448 params
->exposure
.green1Comp
= COMPGAIN (COMP_GREEN1
, currentexp
, startexp
);
2449 params
->exposure
.green2Comp
= COMPGAIN (COMP_GREEN2
, currentexp
, startexp
);
2450 params
->exposure
.blueComp
= COMPGAIN (COMP_BLUE
, currentexp
, startexp
);
2452 params
->exposure
.redComp
= COMP_RED
;
2453 params
->exposure
.green1Comp
= COMP_GREEN1
;
2454 params
->exposure
.green2Comp
= COMP_GREEN2
;
2455 params
->exposure
.blueComp
= COMP_BLUE
;
2457 if(FIRMWARE_VERSION(1,2))
2458 params
->exposure
.compMode
= 0;
2460 params
->exposure
.compMode
= 1;
2462 params
->apcor
.gain1
= 0x18;
2463 params
->apcor
.gain2
= 0x18;
2464 params
->apcor
.gain4
= 0x16;
2465 params
->apcor
.gain8
= 0x14;
2466 *command_flags
|= COMMAND_SETAPCOR
;
2468 params
->flickerControl
.flickerMode
= 0;
2469 params
->flickerControl
.disabled
= 1;
2470 /* Coarse = average of equivalent coarse for each comp channel */
2471 startexp
= EXP_FROM_COMP(COMP_RED
, params
->exposure
.redComp
, currentexp
);
2472 startexp
+= EXP_FROM_COMP(COMP_GREEN1
, params
->exposure
.green1Comp
, currentexp
);
2473 startexp
+= EXP_FROM_COMP(COMP_GREEN2
, params
->exposure
.green2Comp
, currentexp
);
2474 startexp
+= EXP_FROM_COMP(COMP_BLUE
, params
->exposure
.blueComp
, currentexp
);
2475 startexp
= startexp
>> 2;
2476 while(startexp
> MAX_EXP
&&
2477 params
->exposure
.gain
< params
->exposure
.gainMode
-1) {
2478 startexp
= startexp
>> 1;
2479 ++params
->exposure
.gain
;
2481 if(FIRMWARE_VERSION(1,2) && startexp
> MAX_EXP_102
)
2482 startexp
= MAX_EXP_102
;
2483 if(startexp
> MAX_EXP
)
2485 params
->exposure
.coarseExpLo
= startexp
&0xff;
2486 params
->exposure
.coarseExpHi
= startexp
>> 8;
2487 params
->exposure
.redComp
= COMP_RED
;
2488 params
->exposure
.green1Comp
= COMP_GREEN1
;
2489 params
->exposure
.green2Comp
= COMP_GREEN2
;
2490 params
->exposure
.blueComp
= COMP_BLUE
;
2491 params
->exposure
.compMode
= 1;
2492 *command_flags
|= COMMAND_SETEXPOSURE
;
2493 params
->apcor
.gain1
= 0x18;
2494 params
->apcor
.gain2
= 0x16;
2495 params
->apcor
.gain4
= 0x24;
2496 params
->apcor
.gain8
= 0x34;
2497 *command_flags
|= COMMAND_SETAPCOR
;
2499 params
->vlOffset
.gain1
= 20;
2500 params
->vlOffset
.gain2
= 24;
2501 params
->vlOffset
.gain4
= 26;
2502 params
->vlOffset
.gain8
= 26;
2503 *command_flags
|= COMMAND_SETVLOFFSET
;
2504 #undef FIRMWARE_VERSION
2505 #undef EXP_FROM_COMP
2509 #define FIRMWARE_VERSION(x,y) (cam->params.version.firmwareVersion == (x) && \
2510 cam->params.version.firmwareRevision == (y))
2511 /* monitor the exposure and adjust the sensor frame rate if needed */
2512 static void monitor_exposure(struct cam_data
*cam
)
2514 u8 exp_acc
, bcomp
, gain
, coarseL
, cmd
[8], data
[8];
2515 int retval
, light_exp
, dark_exp
, very_dark_exp
;
2516 int old_exposure
, new_exposure
, framerate
;
2518 /* get necessary stats and register settings from camera */
2519 /* do_command can't handle this, so do it ourselves */
2520 cmd
[0] = CPIA_COMMAND_ReadVPRegs
>>8;
2521 cmd
[1] = CPIA_COMMAND_ReadVPRegs
&0xff;
2528 retval
= cam
->ops
->transferCmd(cam
->lowlevel_data
, cmd
, data
);
2530 LOG("ReadVPRegs(30,4,9,8) - failed, retval=%d\n",
2539 mutex_lock(&cam
->param_lock
);
2540 light_exp
= cam
->params
.colourParams
.brightness
+
2541 TC
- 50 + EXP_ACC_LIGHT
;
2544 dark_exp
= cam
->params
.colourParams
.brightness
+
2545 TC
- 50 - EXP_ACC_DARK
;
2548 very_dark_exp
= dark_exp
/2;
2550 old_exposure
= cam
->params
.exposure
.coarseExpHi
* 256 +
2551 cam
->params
.exposure
.coarseExpLo
;
2553 if(!cam
->params
.flickerControl
.disabled
) {
2554 /* Flicker control on */
2555 int max_comp
= FIRMWARE_VERSION(1,2) ? MAX_COMP
: HIGH_COMP_102
;
2556 bcomp
+= 128; /* decode */
2557 if(bcomp
>= max_comp
&& exp_acc
< dark_exp
) {
2559 if(exp_acc
< very_dark_exp
) {
2561 if(cam
->exposure_status
== EXPOSURE_VERY_DARK
)
2562 ++cam
->exposure_count
;
2564 cam
->exposure_status
= EXPOSURE_VERY_DARK
;
2565 cam
->exposure_count
= 1;
2569 if(cam
->exposure_status
== EXPOSURE_DARK
)
2570 ++cam
->exposure_count
;
2572 cam
->exposure_status
= EXPOSURE_DARK
;
2573 cam
->exposure_count
= 1;
2576 } else if(old_exposure
<= LOW_EXP
|| exp_acc
> light_exp
) {
2578 if(old_exposure
<= VERY_LOW_EXP
) {
2580 if(cam
->exposure_status
== EXPOSURE_VERY_LIGHT
)
2581 ++cam
->exposure_count
;
2583 cam
->exposure_status
= EXPOSURE_VERY_LIGHT
;
2584 cam
->exposure_count
= 1;
2588 if(cam
->exposure_status
== EXPOSURE_LIGHT
)
2589 ++cam
->exposure_count
;
2591 cam
->exposure_status
= EXPOSURE_LIGHT
;
2592 cam
->exposure_count
= 1;
2596 /* not dark or light */
2597 cam
->exposure_status
= EXPOSURE_NORMAL
;
2600 /* Flicker control off */
2601 if(old_exposure
>= MAX_EXP
&& exp_acc
< dark_exp
) {
2603 if(exp_acc
< very_dark_exp
) {
2605 if(cam
->exposure_status
== EXPOSURE_VERY_DARK
)
2606 ++cam
->exposure_count
;
2608 cam
->exposure_status
= EXPOSURE_VERY_DARK
;
2609 cam
->exposure_count
= 1;
2613 if(cam
->exposure_status
== EXPOSURE_DARK
)
2614 ++cam
->exposure_count
;
2616 cam
->exposure_status
= EXPOSURE_DARK
;
2617 cam
->exposure_count
= 1;
2620 } else if(old_exposure
<= LOW_EXP
|| exp_acc
> light_exp
) {
2622 if(old_exposure
<= VERY_LOW_EXP
) {
2624 if(cam
->exposure_status
== EXPOSURE_VERY_LIGHT
)
2625 ++cam
->exposure_count
;
2627 cam
->exposure_status
= EXPOSURE_VERY_LIGHT
;
2628 cam
->exposure_count
= 1;
2632 if(cam
->exposure_status
== EXPOSURE_LIGHT
)
2633 ++cam
->exposure_count
;
2635 cam
->exposure_status
= EXPOSURE_LIGHT
;
2636 cam
->exposure_count
= 1;
2640 /* not dark or light */
2641 cam
->exposure_status
= EXPOSURE_NORMAL
;
2645 framerate
= cam
->fps
;
2646 if(framerate
> 30 || framerate
< 1)
2649 if(!cam
->params
.flickerControl
.disabled
) {
2650 /* Flicker control on */
2651 if((cam
->exposure_status
== EXPOSURE_VERY_DARK
||
2652 cam
->exposure_status
== EXPOSURE_DARK
) &&
2653 cam
->exposure_count
>= DARK_TIME
*framerate
&&
2654 cam
->params
.sensorFps
.divisor
< 3) {
2656 /* dark for too long */
2657 ++cam
->params
.sensorFps
.divisor
;
2658 cam
->cmd_queue
|= COMMAND_SETSENSORFPS
;
2660 cam
->params
.flickerControl
.coarseJump
=
2661 flicker_jumps
[cam
->mainsFreq
]
2662 [cam
->params
.sensorFps
.baserate
]
2663 [cam
->params
.sensorFps
.divisor
];
2664 cam
->cmd_queue
|= COMMAND_SETFLICKERCTRL
;
2666 new_exposure
= cam
->params
.flickerControl
.coarseJump
-1;
2667 while(new_exposure
< old_exposure
/2)
2668 new_exposure
+= cam
->params
.flickerControl
.coarseJump
;
2669 cam
->params
.exposure
.coarseExpLo
= new_exposure
& 0xff;
2670 cam
->params
.exposure
.coarseExpHi
= new_exposure
>> 8;
2671 cam
->cmd_queue
|= COMMAND_SETEXPOSURE
;
2672 cam
->exposure_status
= EXPOSURE_NORMAL
;
2673 LOG("Automatically decreasing sensor_fps\n");
2675 } else if((cam
->exposure_status
== EXPOSURE_VERY_LIGHT
||
2676 cam
->exposure_status
== EXPOSURE_LIGHT
) &&
2677 cam
->exposure_count
>= LIGHT_TIME
*framerate
&&
2678 cam
->params
.sensorFps
.divisor
> 0) {
2680 /* light for too long */
2681 int max_exp
= FIRMWARE_VERSION(1,2) ? MAX_EXP_102
: MAX_EXP
;
2683 --cam
->params
.sensorFps
.divisor
;
2684 cam
->cmd_queue
|= COMMAND_SETSENSORFPS
;
2686 cam
->params
.flickerControl
.coarseJump
=
2687 flicker_jumps
[cam
->mainsFreq
]
2688 [cam
->params
.sensorFps
.baserate
]
2689 [cam
->params
.sensorFps
.divisor
];
2690 cam
->cmd_queue
|= COMMAND_SETFLICKERCTRL
;
2692 new_exposure
= cam
->params
.flickerControl
.coarseJump
-1;
2693 while(new_exposure
< 2*old_exposure
&&
2695 cam
->params
.flickerControl
.coarseJump
< max_exp
)
2696 new_exposure
+= cam
->params
.flickerControl
.coarseJump
;
2697 cam
->params
.exposure
.coarseExpLo
= new_exposure
& 0xff;
2698 cam
->params
.exposure
.coarseExpHi
= new_exposure
>> 8;
2699 cam
->cmd_queue
|= COMMAND_SETEXPOSURE
;
2700 cam
->exposure_status
= EXPOSURE_NORMAL
;
2701 LOG("Automatically increasing sensor_fps\n");
2704 /* Flicker control off */
2705 if((cam
->exposure_status
== EXPOSURE_VERY_DARK
||
2706 cam
->exposure_status
== EXPOSURE_DARK
) &&
2707 cam
->exposure_count
>= DARK_TIME
*framerate
&&
2708 cam
->params
.sensorFps
.divisor
< 3) {
2710 /* dark for too long */
2711 ++cam
->params
.sensorFps
.divisor
;
2712 cam
->cmd_queue
|= COMMAND_SETSENSORFPS
;
2714 if(cam
->params
.exposure
.gain
> 0) {
2715 --cam
->params
.exposure
.gain
;
2716 cam
->cmd_queue
|= COMMAND_SETEXPOSURE
;
2718 cam
->exposure_status
= EXPOSURE_NORMAL
;
2719 LOG("Automatically decreasing sensor_fps\n");
2721 } else if((cam
->exposure_status
== EXPOSURE_VERY_LIGHT
||
2722 cam
->exposure_status
== EXPOSURE_LIGHT
) &&
2723 cam
->exposure_count
>= LIGHT_TIME
*framerate
&&
2724 cam
->params
.sensorFps
.divisor
> 0) {
2726 /* light for too long */
2727 --cam
->params
.sensorFps
.divisor
;
2728 cam
->cmd_queue
|= COMMAND_SETSENSORFPS
;
2730 if(cam
->params
.exposure
.gain
<
2731 cam
->params
.exposure
.gainMode
-1) {
2732 ++cam
->params
.exposure
.gain
;
2733 cam
->cmd_queue
|= COMMAND_SETEXPOSURE
;
2735 cam
->exposure_status
= EXPOSURE_NORMAL
;
2736 LOG("Automatically increasing sensor_fps\n");
2739 mutex_unlock(&cam
->param_lock
);
2742 /*-----------------------------------------------------------------*/
2743 /* if flicker is switched off, this function switches it back on.It checks,
2744 however, that conditions are suitable before restarting it.
2745 This should only be called for firmware version 1.2.
2747 It also adjust the colour balance when an exposure step is detected - as
2748 long as flicker is running
2750 static void restart_flicker(struct cam_data
*cam
)
2752 int cam_exposure
, old_exp
;
2753 if(!FIRMWARE_VERSION(1,2))
2755 mutex_lock(&cam
->param_lock
);
2756 if(cam
->params
.flickerControl
.flickerMode
== 0 ||
2757 cam
->raw_image
[39] == 0) {
2758 mutex_unlock(&cam
->param_lock
);
2761 cam_exposure
= cam
->raw_image
[39]*2;
2762 old_exp
= cam
->params
.exposure
.coarseExpLo
+
2763 cam
->params
.exposure
.coarseExpHi
*256;
2765 see how far away camera exposure is from a valid
2766 flicker exposure value
2768 cam_exposure
%= cam
->params
.flickerControl
.coarseJump
;
2769 if(!cam
->params
.flickerControl
.disabled
&&
2770 cam_exposure
<= cam
->params
.flickerControl
.coarseJump
- 3) {
2771 /* Flicker control auto-disabled */
2772 cam
->params
.flickerControl
.disabled
= 1;
2775 if(cam
->params
.flickerControl
.disabled
&&
2776 cam
->params
.flickerControl
.flickerMode
&&
2777 old_exp
> cam
->params
.flickerControl
.coarseJump
+
2778 ROUND_UP_EXP_FOR_FLICKER
) {
2779 /* exposure is now high enough to switch
2780 flicker control back on */
2781 set_flicker(&cam
->params
, &cam
->cmd_queue
, 1);
2782 if((cam
->cmd_queue
& COMMAND_SETEXPOSURE
) &&
2783 cam
->params
.exposure
.expMode
== 2)
2784 cam
->exposure_status
= EXPOSURE_NORMAL
;
2787 mutex_unlock(&cam
->param_lock
);
2789 #undef FIRMWARE_VERSION
2791 static int clear_stall(struct cam_data
*cam
)
2793 /* FIXME: Does this actually work? */
2794 LOG("Clearing stall\n");
2796 cam
->ops
->streamRead(cam
->lowlevel_data
, cam
->raw_image
, 0);
2797 do_command(cam
, CPIA_COMMAND_GetCameraStatus
,0,0,0,0);
2798 return cam
->params
.status
.streamState
!= STREAM_PAUSED
;
2801 /* kernel thread function to read image from camera */
2802 static int fetch_frame(void *data
)
2804 int image_size
, retry
;
2805 struct cam_data
*cam
= (struct cam_data
*)data
;
2806 unsigned long oldjif
, rate
, diff
;
2808 /* Allow up to two bad images in a row to be read and
2809 * ignored before an error is reported */
2810 for (retry
= 0; retry
< 3; ++retry
) {
2812 DBG("retry=%d\n", retry
);
2817 /* load first frame always uncompressed */
2818 if (cam
->first_frame
&&
2819 cam
->params
.compression
.mode
!= CPIA_COMPRESSION_NONE
) {
2820 do_command(cam
, CPIA_COMMAND_SetCompression
,
2821 CPIA_COMPRESSION_NONE
,
2822 NO_DECIMATION
, 0, 0);
2823 /* Trial & error - Discarding a frame prevents the
2824 first frame from having an error in the data. */
2825 do_command(cam
, CPIA_COMMAND_DiscardFrame
, 0, 0, 0, 0);
2828 /* init camera upload */
2829 if (do_command(cam
, CPIA_COMMAND_GrabFrame
, 0,
2830 cam
->params
.streamStartLine
, 0, 0))
2833 if (cam
->ops
->wait_for_stream_ready
) {
2834 /* loop until image ready */
2836 do_command(cam
, CPIA_COMMAND_GetCameraStatus
,0,0,0,0);
2837 while (cam
->params
.status
.streamState
!= STREAM_READY
) {
2838 if(++count
> READY_TIMEOUT
)
2840 if(cam
->params
.status
.streamState
==
2843 if(!clear_stall(cam
))
2849 /* sleep for 10 ms, hopefully ;) */
2850 msleep_interruptible(10);
2851 if (signal_pending(current
))
2854 do_command(cam
, CPIA_COMMAND_GetCameraStatus
,
2857 if(cam
->params
.status
.streamState
!= STREAM_READY
) {
2864 /* grab image from camera */
2866 image_size
= cam
->ops
->streamRead(cam
->lowlevel_data
,
2868 if (image_size
<= 0) {
2869 DBG("streamRead failed: %d\n", image_size
);
2873 rate
= image_size
* HZ
/ 1024;
2874 diff
= jiffies
-oldjif
;
2875 cam
->transfer_rate
= diff
==0 ? rate
: rate
/diff
;
2876 /* diff==0 ? unlikely but possible */
2878 /* Switch flicker control back on if it got turned off */
2879 restart_flicker(cam
);
2881 /* If AEC is enabled, monitor the exposure and
2882 adjust the sensor frame rate if needed */
2883 if(cam
->params
.exposure
.expMode
== 2)
2884 monitor_exposure(cam
);
2886 /* camera idle now so dispatch queued commands */
2887 dispatch_commands(cam
);
2889 /* Update our knowledge of the camera state */
2890 do_command(cam
, CPIA_COMMAND_GetColourBalance
, 0, 0, 0, 0);
2891 do_command(cam
, CPIA_COMMAND_GetExposure
, 0, 0, 0, 0);
2892 do_command(cam
, CPIA_COMMAND_ReadMCPorts
, 0, 0, 0, 0);
2894 /* decompress and convert image to by copying it from
2895 * raw_image to decompressed_frame
2900 cam
->image_size
= parse_picture(cam
, image_size
);
2901 if (cam
->image_size
<= 0) {
2902 DBG("parse_picture failed %d\n", cam
->image_size
);
2903 if(cam
->params
.compression
.mode
!=
2904 CPIA_COMPRESSION_NONE
) {
2905 /* Compression may not work right if we
2906 had a bad frame, get the next one
2908 cam
->first_frame
= 1;
2909 do_command(cam
, CPIA_COMMAND_SetGrabMode
,
2910 CPIA_GRAB_SINGLE
, 0, 0, 0);
2911 /* FIXME: Trial & error - need up to 70ms for
2912 the grab mode change to complete ? */
2913 msleep_interruptible(70);
2914 if (signal_pending(current
))
2922 /* FIXME: this only works for double buffering */
2923 if (cam
->frame
[cam
->curframe
].state
== FRAME_READY
) {
2924 memcpy(cam
->frame
[cam
->curframe
].data
,
2925 cam
->decompressed_frame
.data
,
2926 cam
->decompressed_frame
.count
);
2927 cam
->frame
[cam
->curframe
].state
= FRAME_DONE
;
2929 cam
->decompressed_frame
.state
= FRAME_DONE
;
2931 if (cam
->first_frame
) {
2932 cam
->first_frame
= 0;
2933 do_command(cam
, CPIA_COMMAND_SetCompression
,
2934 cam
->params
.compression
.mode
,
2935 cam
->params
.compression
.decimation
, 0, 0);
2937 /* Switch from single-grab to continuous grab */
2938 do_command(cam
, CPIA_COMMAND_SetGrabMode
,
2939 CPIA_GRAB_CONTINUOUS
, 0, 0, 0);
2946 static int capture_frame(struct cam_data
*cam
, struct video_mmap
*vm
)
2948 if (!cam
->frame_buf
) {
2949 /* we do lazy allocation */
2951 if ((err
= allocate_frame_buf(cam
)))
2955 cam
->curframe
= vm
->frame
;
2956 cam
->frame
[cam
->curframe
].state
= FRAME_READY
;
2957 return fetch_frame(cam
);
2960 static int goto_high_power(struct cam_data
*cam
)
2962 if (do_command(cam
, CPIA_COMMAND_GotoHiPower
, 0, 0, 0, 0))
2964 msleep_interruptible(40); /* windows driver does it too */
2965 if(signal_pending(current
))
2967 if (do_command(cam
, CPIA_COMMAND_GetCameraStatus
, 0, 0, 0, 0))
2969 if (cam
->params
.status
.systemState
== HI_POWER_STATE
) {
2970 DBG("camera now in HIGH power state\n");
2977 static int goto_low_power(struct cam_data
*cam
)
2979 if (do_command(cam
, CPIA_COMMAND_GotoLoPower
, 0, 0, 0, 0))
2981 if (do_command(cam
, CPIA_COMMAND_GetCameraStatus
, 0, 0, 0, 0))
2983 if (cam
->params
.status
.systemState
== LO_POWER_STATE
) {
2984 DBG("camera now in LOW power state\n");
2991 static void save_camera_state(struct cam_data
*cam
)
2993 if(!(cam
->cmd_queue
& COMMAND_SETCOLOURBALANCE
))
2994 do_command(cam
, CPIA_COMMAND_GetColourBalance
, 0, 0, 0, 0);
2995 if(!(cam
->cmd_queue
& COMMAND_SETEXPOSURE
))
2996 do_command(cam
, CPIA_COMMAND_GetExposure
, 0, 0, 0, 0);
2998 DBG("%d/%d/%d/%d/%d/%d/%d/%d\n",
2999 cam
->params
.exposure
.gain
,
3000 cam
->params
.exposure
.fineExp
,
3001 cam
->params
.exposure
.coarseExpLo
,
3002 cam
->params
.exposure
.coarseExpHi
,
3003 cam
->params
.exposure
.redComp
,
3004 cam
->params
.exposure
.green1Comp
,
3005 cam
->params
.exposure
.green2Comp
,
3006 cam
->params
.exposure
.blueComp
);
3008 cam
->params
.colourBalance
.redGain
,
3009 cam
->params
.colourBalance
.greenGain
,
3010 cam
->params
.colourBalance
.blueGain
);
3013 static int set_camera_state(struct cam_data
*cam
)
3015 cam
->cmd_queue
= COMMAND_SETCOMPRESSION
|
3016 COMMAND_SETCOMPRESSIONTARGET
|
3017 COMMAND_SETCOLOURPARAMS
|
3019 COMMAND_SETYUVTHRESH
|
3020 COMMAND_SETECPTIMING
|
3021 COMMAND_SETCOMPRESSIONPARAMS
|
3022 COMMAND_SETEXPOSURE
|
3023 COMMAND_SETCOLOURBALANCE
|
3024 COMMAND_SETSENSORFPS
|
3026 COMMAND_SETFLICKERCTRL
|
3027 COMMAND_SETVLOFFSET
;
3029 do_command(cam
, CPIA_COMMAND_SetGrabMode
, CPIA_GRAB_SINGLE
,0,0,0);
3030 dispatch_commands(cam
);
3032 /* Wait 6 frames for the sensor to get all settings and
3033 AEC/ACB to settle */
3034 msleep_interruptible(6*(cam
->params
.sensorFps
.baserate
? 33 : 40) *
3035 (1 << cam
->params
.sensorFps
.divisor
) + 10);
3037 if(signal_pending(current
))
3040 save_camera_state(cam
);
3045 static void get_version_information(struct cam_data
*cam
)
3047 /* GetCPIAVersion */
3048 do_command(cam
, CPIA_COMMAND_GetCPIAVersion
, 0, 0, 0, 0);
3051 do_command(cam
, CPIA_COMMAND_GetPnPID
, 0, 0, 0, 0);
3054 /* initialize camera */
3055 static int reset_camera(struct cam_data
*cam
)
3058 /* Start the camera in low power mode */
3059 if (goto_low_power(cam
)) {
3060 if (cam
->params
.status
.systemState
!= WARM_BOOT_STATE
)
3063 /* FIXME: this is just dirty trial and error */
3064 err
= goto_high_power(cam
);
3067 do_command(cam
, CPIA_COMMAND_DiscardFrame
, 0, 0, 0, 0);
3068 if (goto_low_power(cam
))
3072 /* procedure described in developer's guide p3-28 */
3074 /* Check the firmware version. */
3075 cam
->params
.version
.firmwareVersion
= 0;
3076 get_version_information(cam
);
3077 if (cam
->params
.version
.firmwareVersion
!= 1)
3080 /* A bug in firmware 1-02 limits gainMode to 2 */
3081 if(cam
->params
.version
.firmwareRevision
<= 2 &&
3082 cam
->params
.exposure
.gainMode
> 2) {
3083 cam
->params
.exposure
.gainMode
= 2;
3086 /* set QX3 detected flag */
3087 cam
->params
.qx3
.qx3_detected
= (cam
->params
.pnpID
.vendor
== 0x0813 &&
3088 cam
->params
.pnpID
.product
== 0x0001);
3090 /* The fatal error checking should be done after
3091 * the camera powers up (developer's guide p 3-38) */
3093 /* Set streamState before transition to high power to avoid bug
3094 * in firmware 1-02 */
3095 do_command(cam
, CPIA_COMMAND_ModifyCameraStatus
, STREAMSTATE
, 0,
3096 STREAM_NOT_READY
, 0);
3099 err
= goto_high_power(cam
);
3103 /* Check the camera status */
3104 if (do_command(cam
, CPIA_COMMAND_GetCameraStatus
, 0, 0, 0, 0))
3107 if (cam
->params
.status
.fatalError
) {
3108 DBG("fatal_error: %#04x\n",
3109 cam
->params
.status
.fatalError
);
3110 DBG("vp_status: %#04x\n",
3111 cam
->params
.status
.vpStatus
);
3112 if (cam
->params
.status
.fatalError
& ~(COM_FLAG
|CPIA_FLAG
)) {
3113 /* Fatal error in camera */
3115 } else if (cam
->params
.status
.fatalError
& (COM_FLAG
|CPIA_FLAG
)) {
3116 /* Firmware 1-02 may do this for parallel port cameras,
3117 * just clear the flags (developer's guide p 3-38) */
3118 do_command(cam
, CPIA_COMMAND_ModifyCameraStatus
,
3119 FATALERROR
, ~(COM_FLAG
|CPIA_FLAG
), 0, 0);
3123 /* Check the camera status again */
3124 if (cam
->params
.status
.fatalError
) {
3125 if (cam
->params
.status
.fatalError
)
3129 /* VPVersion can't be retrieved before the camera is in HiPower,
3130 * so get it here instead of in get_version_information. */
3131 do_command(cam
, CPIA_COMMAND_GetVPVersion
, 0, 0, 0, 0);
3133 /* set camera to a known state */
3134 return set_camera_state(cam
);
3137 static void put_cam(struct cpia_camera_ops
* ops
)
3139 module_put(ops
->owner
);
3142 /* ------------------------- V4L interface --------------------- */
3143 static int cpia_open(struct file
*file
)
3145 struct video_device
*dev
= video_devdata(file
);
3146 struct cam_data
*cam
= video_get_drvdata(dev
);
3150 DBG("Internal error, cam_data not found!\n");
3154 if (cam
->open_count
> 0) {
3155 DBG("Camera already open\n");
3159 if (!try_module_get(cam
->ops
->owner
))
3162 mutex_lock(&cam
->busy_lock
);
3164 if (!cam
->raw_image
) {
3165 cam
->raw_image
= rvmalloc(CPIA_MAX_IMAGE_SIZE
);
3166 if (!cam
->raw_image
)
3170 if (!cam
->decompressed_frame
.data
) {
3171 cam
->decompressed_frame
.data
= rvmalloc(CPIA_MAX_FRAME_SIZE
);
3172 if (!cam
->decompressed_frame
.data
)
3178 if (cam
->ops
->open(cam
->lowlevel_data
))
3181 /* reset the camera */
3182 if ((err
= reset_camera(cam
)) != 0) {
3183 cam
->ops
->close(cam
->lowlevel_data
);
3188 if(signal_pending(current
))
3191 /* Set ownership of /proc/cpia/videoX to current user */
3193 cam
->proc_entry
->uid
= current_uid();
3195 /* set mark for loading first frame uncompressed */
3196 cam
->first_frame
= 1;
3198 /* init it to something */
3199 cam
->mmap_kludge
= 0;
3202 file
->private_data
= dev
;
3203 mutex_unlock(&cam
->busy_lock
);
3207 if (cam
->decompressed_frame
.data
) {
3208 rvfree(cam
->decompressed_frame
.data
, CPIA_MAX_FRAME_SIZE
);
3209 cam
->decompressed_frame
.data
= NULL
;
3211 if (cam
->raw_image
) {
3212 rvfree(cam
->raw_image
, CPIA_MAX_IMAGE_SIZE
);
3213 cam
->raw_image
= NULL
;
3215 mutex_unlock(&cam
->busy_lock
);
3220 static int cpia_close(struct file
*file
)
3222 struct video_device
*dev
= file
->private_data
;
3223 struct cam_data
*cam
= video_get_drvdata(dev
);
3226 /* Return ownership of /proc/cpia/videoX to root */
3228 cam
->proc_entry
->uid
= 0;
3230 /* save camera state for later open (developers guide ch 3.5.3) */
3231 save_camera_state(cam
);
3234 goto_low_power(cam
);
3236 /* Update the camera status */
3237 do_command(cam
, CPIA_COMMAND_GetCameraStatus
, 0, 0, 0, 0);
3239 /* cleanup internal state stuff */
3240 free_frames(cam
->frame
);
3243 cam
->ops
->close(cam
->lowlevel_data
);
3248 if (--cam
->open_count
== 0) {
3249 /* clean up capture-buffers */
3250 if (cam
->raw_image
) {
3251 rvfree(cam
->raw_image
, CPIA_MAX_IMAGE_SIZE
);
3252 cam
->raw_image
= NULL
;
3255 if (cam
->decompressed_frame
.data
) {
3256 rvfree(cam
->decompressed_frame
.data
, CPIA_MAX_FRAME_SIZE
);
3257 cam
->decompressed_frame
.data
= NULL
;
3261 free_frame_buf(cam
);
3266 file
->private_data
= NULL
;
3271 static ssize_t
cpia_read(struct file
*file
, char __user
*buf
,
3272 size_t count
, loff_t
*ppos
)
3274 struct video_device
*dev
= file
->private_data
;
3275 struct cam_data
*cam
= video_get_drvdata(dev
);
3278 /* make this _really_ smp and multithread-safe */
3279 if (mutex_lock_interruptible(&cam
->busy_lock
))
3284 mutex_unlock(&cam
->busy_lock
);
3290 mutex_unlock(&cam
->busy_lock
);
3296 mutex_unlock(&cam
->busy_lock
);
3301 cam
->decompressed_frame
.state
= FRAME_READY
;
3303 if((err
= fetch_frame(cam
)) != 0) {
3304 DBG("ERROR from fetch_frame: %d\n", err
);
3305 mutex_unlock(&cam
->busy_lock
);
3308 cam
->decompressed_frame
.state
= FRAME_UNUSED
;
3310 /* copy data to user space */
3311 if (cam
->decompressed_frame
.count
> count
) {
3312 DBG("count wrong: %d, %lu\n", cam
->decompressed_frame
.count
,
3313 (unsigned long) count
);
3314 mutex_unlock(&cam
->busy_lock
);
3317 if (copy_to_user(buf
, cam
->decompressed_frame
.data
,
3318 cam
->decompressed_frame
.count
)) {
3319 DBG("copy_to_user failed\n");
3320 mutex_unlock(&cam
->busy_lock
);
3324 mutex_unlock(&cam
->busy_lock
);
3325 return cam
->decompressed_frame
.count
;
3328 static long cpia_do_ioctl(struct file
*file
, unsigned int cmd
, void *arg
)
3330 struct video_device
*dev
= file
->private_data
;
3331 struct cam_data
*cam
= video_get_drvdata(dev
);
3334 if (!cam
|| !cam
->ops
)
3337 /* make this _really_ smp-safe */
3338 if (mutex_lock_interruptible(&cam
->busy_lock
))
3341 /* DBG("cpia_ioctl: %u\n", cmd); */
3344 /* query capabilities */
3347 struct video_capability
*b
= arg
;
3349 DBG("VIDIOCGCAP\n");
3350 strcpy(b
->name
, "CPiA Camera");
3351 b
->type
= VID_TYPE_CAPTURE
| VID_TYPE_SUBCAPTURE
;
3354 b
->maxwidth
= 352; /* VIDEOSIZE_CIF */
3356 b
->minwidth
= 48; /* VIDEOSIZE_48_48 */
3361 /* get/set video source - we are a camera and nothing else */
3364 struct video_channel
*v
= arg
;
3366 DBG("VIDIOCGCHAN\n");
3367 if (v
->channel
!= 0) {
3373 strcpy(v
->name
, "Camera");
3376 v
->type
= VIDEO_TYPE_CAMERA
;
3383 struct video_channel
*v
= arg
;
3385 DBG("VIDIOCSCHAN\n");
3386 if (v
->channel
!= 0)
3391 /* image properties */
3394 struct video_picture
*pic
= arg
;
3395 DBG("VIDIOCGPICT\n");
3402 struct video_picture
*vp
= arg
;
3404 DBG("VIDIOCSPICT\n");
3406 /* check validity */
3407 DBG("palette: %d\n", vp
->palette
);
3408 DBG("depth: %d\n", vp
->depth
);
3409 if (!valid_mode(vp
->palette
, vp
->depth
)) {
3414 mutex_lock(&cam
->param_lock
);
3415 /* brightness, colour, contrast need no check 0-65535 */
3417 /* update cam->params.colourParams */
3418 cam
->params
.colourParams
.brightness
= vp
->brightness
*100/65535;
3419 cam
->params
.colourParams
.contrast
= vp
->contrast
*100/65535;
3420 cam
->params
.colourParams
.saturation
= vp
->colour
*100/65535;
3421 /* contrast is in steps of 8, so round */
3422 cam
->params
.colourParams
.contrast
=
3423 ((cam
->params
.colourParams
.contrast
+ 3) / 8) * 8;
3424 if (cam
->params
.version
.firmwareVersion
== 1 &&
3425 cam
->params
.version
.firmwareRevision
== 2 &&
3426 cam
->params
.colourParams
.contrast
> 80) {
3427 /* 1-02 firmware limits contrast to 80 */
3428 cam
->params
.colourParams
.contrast
= 80;
3431 /* Adjust flicker control if necessary */
3432 if(cam
->params
.flickerControl
.allowableOverExposure
< 0)
3433 cam
->params
.flickerControl
.allowableOverExposure
=
3434 -find_over_exposure(cam
->params
.colourParams
.brightness
);
3435 if(cam
->params
.flickerControl
.flickerMode
!= 0)
3436 cam
->cmd_queue
|= COMMAND_SETFLICKERCTRL
;
3439 /* queue command to update camera */
3440 cam
->cmd_queue
|= COMMAND_SETCOLOURPARAMS
;
3441 mutex_unlock(&cam
->param_lock
);
3442 DBG("VIDIOCSPICT: %d / %d // %d / %d / %d / %d\n",
3443 vp
->depth
, vp
->palette
, vp
->brightness
, vp
->hue
, vp
->colour
,
3448 /* get/set capture window */
3451 struct video_window
*vw
= arg
;
3452 DBG("VIDIOCGWIN\n");
3460 /* copy_from_user, check validity, copy to internal structure */
3461 struct video_window
*vw
= arg
;
3462 DBG("VIDIOCSWIN\n");
3464 if (vw
->clipcount
!= 0) { /* clipping not supported */
3468 if (vw
->clips
!= NULL
) { /* clipping not supported */
3473 /* we set the video window to something smaller or equal to what
3474 * is requested by the user???
3476 mutex_lock(&cam
->param_lock
);
3477 if (vw
->width
!= cam
->vw
.width
|| vw
->height
!= cam
->vw
.height
) {
3478 int video_size
= match_videosize(vw
->width
, vw
->height
);
3480 if (video_size
< 0) {
3482 mutex_unlock(&cam
->param_lock
);
3485 cam
->video_size
= video_size
;
3487 /* video size is changing, reset the subcapture area */
3488 memset(&cam
->vc
, 0, sizeof(cam
->vc
));
3491 DBG("%d / %d\n", cam
->vw
.width
, cam
->vw
.height
);
3492 cam
->cmd_queue
|= COMMAND_SETFORMAT
;
3495 mutex_unlock(&cam
->param_lock
);
3497 /* setformat ignored by camera during streaming,
3498 * so stop/dispatch/start */
3499 if (cam
->cmd_queue
& COMMAND_SETFORMAT
) {
3501 dispatch_commands(cam
);
3503 DBG("%d/%d:%d\n", cam
->video_size
,
3504 cam
->vw
.width
, cam
->vw
.height
);
3508 /* mmap interface */
3511 struct video_mbuf
*vm
= arg
;
3514 DBG("VIDIOCGMBUF\n");
3515 memset(vm
, 0, sizeof(*vm
));
3516 vm
->size
= CPIA_MAX_FRAME_SIZE
*FRAME_NUM
;
3517 vm
->frames
= FRAME_NUM
;
3518 for (i
= 0; i
< FRAME_NUM
; i
++)
3519 vm
->offsets
[i
] = CPIA_MAX_FRAME_SIZE
* i
;
3523 case VIDIOCMCAPTURE
:
3525 struct video_mmap
*vm
= arg
;
3528 DBG("VIDIOCMCAPTURE: %d / %d / %dx%d\n", vm
->format
, vm
->frame
,
3529 vm
->width
, vm
->height
);
3530 if (vm
->frame
<0||vm
->frame
>=FRAME_NUM
) {
3535 /* set video format */
3536 cam
->vp
.palette
= vm
->format
;
3537 switch(vm
->format
) {
3538 case VIDEO_PALETTE_GREY
:
3541 case VIDEO_PALETTE_RGB555
:
3542 case VIDEO_PALETTE_RGB565
:
3543 case VIDEO_PALETTE_YUV422
:
3544 case VIDEO_PALETTE_YUYV
:
3545 case VIDEO_PALETTE_UYVY
:
3548 case VIDEO_PALETTE_RGB24
:
3551 case VIDEO_PALETTE_RGB32
:
3561 /* set video size */
3562 video_size
= match_videosize(vm
->width
, vm
->height
);
3563 if (video_size
< 0) {
3567 if (video_size
!= cam
->video_size
) {
3568 cam
->video_size
= video_size
;
3570 /* video size is changing, reset the subcapture area */
3571 memset(&cam
->vc
, 0, sizeof(cam
->vc
));
3574 cam
->cmd_queue
|= COMMAND_SETFORMAT
;
3575 dispatch_commands(cam
);
3577 /* according to v4l-spec we must start streaming here */
3578 cam
->mmap_kludge
= 1;
3579 retval
= capture_frame(cam
, vm
);
3588 //DBG("VIDIOCSYNC: %d\n", *frame);
3590 if (*frame
<0 || *frame
>= FRAME_NUM
) {
3595 switch (cam
->frame
[*frame
].state
) {
3598 case FRAME_GRABBING
:
3599 DBG("sync to unused frame %d\n", *frame
);
3604 cam
->frame
[*frame
].state
= FRAME_UNUSED
;
3605 //DBG("VIDIOCSYNC: %d synced\n", *frame);
3608 if (retval
== -EINTR
) {
3609 /* FIXME - xawtv does not handle this nice */
3615 case VIDIOCGCAPTURE
:
3617 struct video_capture
*vc
= arg
;
3619 DBG("VIDIOCGCAPTURE\n");
3626 case VIDIOCSCAPTURE
:
3628 struct video_capture
*vc
= arg
;
3630 DBG("VIDIOCSCAPTURE\n");
3632 if (vc
->decimation
!= 0) { /* How should this be used? */
3636 if (vc
->flags
!= 0) { /* Even/odd grab not supported */
3641 /* Clip to the resolution we can set for the ROI
3642 (every 8 columns and 4 rows) */
3643 vc
->x
= vc
->x
& ~(__u32
)7;
3644 vc
->y
= vc
->y
& ~(__u32
)3;
3645 vc
->width
= vc
->width
& ~(__u32
)7;
3646 vc
->height
= vc
->height
& ~(__u32
)3;
3648 if(vc
->width
== 0 || vc
->height
== 0 ||
3649 vc
->x
+ vc
->width
> cam
->vw
.width
||
3650 vc
->y
+ vc
->height
> cam
->vw
.height
) {
3655 DBG("%d,%d/%dx%d\n", vc
->x
,vc
->y
,vc
->width
, vc
->height
);
3657 mutex_lock(&cam
->param_lock
);
3661 cam
->vc
.width
= vc
->width
;
3662 cam
->vc
.height
= vc
->height
;
3665 cam
->cmd_queue
|= COMMAND_SETFORMAT
;
3667 mutex_unlock(&cam
->param_lock
);
3669 /* setformat ignored by camera during streaming,
3670 * so stop/dispatch/start */
3671 dispatch_commands(cam
);
3677 struct video_unit
*vu
= arg
;
3679 DBG("VIDIOCGUNIT\n");
3681 vu
->video
= cam
->vdev
.minor
;
3682 vu
->vbi
= VIDEO_NO_UNIT
;
3683 vu
->radio
= VIDEO_NO_UNIT
;
3684 vu
->audio
= VIDEO_NO_UNIT
;
3685 vu
->teletext
= VIDEO_NO_UNIT
;
3691 /* pointless to implement overlay with this camera */
3696 /* tuner interface - we have none */
3701 /* audio interface - we have none */
3707 retval
= -ENOIOCTLCMD
;
3711 mutex_unlock(&cam
->busy_lock
);
3715 static long cpia_ioctl(struct file
*file
,
3716 unsigned int cmd
, unsigned long arg
)
3718 return video_usercopy(file
, cmd
, arg
, cpia_do_ioctl
);
3723 static int cpia_mmap(struct file
*file
, struct vm_area_struct
*vma
)
3725 struct video_device
*dev
= file
->private_data
;
3726 unsigned long start
= vma
->vm_start
;
3727 unsigned long size
= vma
->vm_end
- vma
->vm_start
;
3728 unsigned long page
, pos
;
3729 struct cam_data
*cam
= video_get_drvdata(dev
);
3732 if (!cam
|| !cam
->ops
)
3735 DBG("cpia_mmap: %ld\n", size
);
3737 if (size
> FRAME_NUM
*CPIA_MAX_FRAME_SIZE
)
3740 /* make this _really_ smp-safe */
3741 if (mutex_lock_interruptible(&cam
->busy_lock
))
3744 if (!cam
->frame_buf
) { /* we do lazy allocation */
3745 if ((retval
= allocate_frame_buf(cam
))) {
3746 mutex_unlock(&cam
->busy_lock
);
3751 pos
= (unsigned long)(cam
->frame_buf
);
3753 page
= vmalloc_to_pfn((void *)pos
);
3754 if (remap_pfn_range(vma
, start
, page
, PAGE_SIZE
, PAGE_SHARED
)) {
3755 mutex_unlock(&cam
->busy_lock
);
3760 if (size
> PAGE_SIZE
)
3766 DBG("cpia_mmap: %ld\n", size
);
3767 mutex_unlock(&cam
->busy_lock
);
3772 static const struct v4l2_file_operations cpia_fops
= {
3773 .owner
= THIS_MODULE
,
3775 .release
= cpia_close
,
3778 .ioctl
= cpia_ioctl
,
3781 static struct video_device cpia_template
= {
3782 .name
= "CPiA Camera",
3784 .release
= video_device_release_empty
,
3787 /* initialise cam_data structure */
3788 static void reset_camera_struct(struct cam_data
*cam
)
3790 /* The following parameter values are the defaults from
3791 * "Software Developer's Guide for CPiA Cameras". Any changes
3792 * to the defaults are noted in comments. */
3793 cam
->params
.colourParams
.brightness
= 50;
3794 cam
->params
.colourParams
.contrast
= 48;
3795 cam
->params
.colourParams
.saturation
= 50;
3796 cam
->params
.exposure
.gainMode
= 4;
3797 cam
->params
.exposure
.expMode
= 2; /* AEC */
3798 cam
->params
.exposure
.compMode
= 1;
3799 cam
->params
.exposure
.centreWeight
= 1;
3800 cam
->params
.exposure
.gain
= 0;
3801 cam
->params
.exposure
.fineExp
= 0;
3802 cam
->params
.exposure
.coarseExpLo
= 185;
3803 cam
->params
.exposure
.coarseExpHi
= 0;
3804 cam
->params
.exposure
.redComp
= COMP_RED
;
3805 cam
->params
.exposure
.green1Comp
= COMP_GREEN1
;
3806 cam
->params
.exposure
.green2Comp
= COMP_GREEN2
;
3807 cam
->params
.exposure
.blueComp
= COMP_BLUE
;
3808 cam
->params
.colourBalance
.balanceMode
= 2; /* ACB */
3809 cam
->params
.colourBalance
.redGain
= 32;
3810 cam
->params
.colourBalance
.greenGain
= 6;
3811 cam
->params
.colourBalance
.blueGain
= 92;
3812 cam
->params
.apcor
.gain1
= 0x18;
3813 cam
->params
.apcor
.gain2
= 0x16;
3814 cam
->params
.apcor
.gain4
= 0x24;
3815 cam
->params
.apcor
.gain8
= 0x34;
3816 cam
->params
.flickerControl
.flickerMode
= 0;
3817 cam
->params
.flickerControl
.disabled
= 1;
3819 cam
->params
.flickerControl
.coarseJump
=
3820 flicker_jumps
[cam
->mainsFreq
]
3821 [cam
->params
.sensorFps
.baserate
]
3822 [cam
->params
.sensorFps
.divisor
];
3823 cam
->params
.flickerControl
.allowableOverExposure
=
3824 -find_over_exposure(cam
->params
.colourParams
.brightness
);
3825 cam
->params
.vlOffset
.gain1
= 20;
3826 cam
->params
.vlOffset
.gain2
= 24;
3827 cam
->params
.vlOffset
.gain4
= 26;
3828 cam
->params
.vlOffset
.gain8
= 26;
3829 cam
->params
.compressionParams
.hysteresis
= 3;
3830 cam
->params
.compressionParams
.threshMax
= 11;
3831 cam
->params
.compressionParams
.smallStep
= 1;
3832 cam
->params
.compressionParams
.largeStep
= 3;
3833 cam
->params
.compressionParams
.decimationHysteresis
= 2;
3834 cam
->params
.compressionParams
.frDiffStepThresh
= 5;
3835 cam
->params
.compressionParams
.qDiffStepThresh
= 3;
3836 cam
->params
.compressionParams
.decimationThreshMod
= 2;
3837 /* End of default values from Software Developer's Guide */
3839 cam
->transfer_rate
= 0;
3840 cam
->exposure_status
= EXPOSURE_NORMAL
;
3842 /* Set Sensor FPS to 15fps. This seems better than 30fps
3843 * for indoor lighting. */
3844 cam
->params
.sensorFps
.divisor
= 1;
3845 cam
->params
.sensorFps
.baserate
= 1;
3847 cam
->params
.yuvThreshold
.yThreshold
= 6; /* From windows driver */
3848 cam
->params
.yuvThreshold
.uvThreshold
= 6; /* From windows driver */
3850 cam
->params
.format
.subSample
= SUBSAMPLE_422
;
3851 cam
->params
.format
.yuvOrder
= YUVORDER_YUYV
;
3853 cam
->params
.compression
.mode
= CPIA_COMPRESSION_AUTO
;
3854 cam
->params
.compressionTarget
.frTargeting
=
3855 CPIA_COMPRESSION_TARGET_QUALITY
;
3856 cam
->params
.compressionTarget
.targetFR
= 15; /* From windows driver */
3857 cam
->params
.compressionTarget
.targetQ
= 5; /* From windows driver */
3859 cam
->params
.qx3
.qx3_detected
= 0;
3860 cam
->params
.qx3
.toplight
= 0;
3861 cam
->params
.qx3
.bottomlight
= 0;
3862 cam
->params
.qx3
.button
= 0;
3863 cam
->params
.qx3
.cradled
= 0;
3865 cam
->video_size
= VIDEOSIZE_CIF
;
3867 cam
->vp
.colour
= 32768; /* 50% */
3868 cam
->vp
.hue
= 32768; /* 50% */
3869 cam
->vp
.brightness
= 32768; /* 50% */
3870 cam
->vp
.contrast
= 32768; /* 50% */
3871 cam
->vp
.whiteness
= 0; /* not used -> grayscale only */
3872 cam
->vp
.depth
= 24; /* to be set by user */
3873 cam
->vp
.palette
= VIDEO_PALETTE_RGB24
; /* to be set by user */
3883 cam
->vw
.chromakey
= 0;
3885 cam
->vw
.clipcount
= 0;
3886 cam
->vw
.clips
= NULL
;
3888 cam
->cmd_queue
= COMMAND_NONE
;
3889 cam
->first_frame
= 1;
3894 /* initialize cam_data structure */
3895 static void init_camera_struct(struct cam_data
*cam
,
3896 struct cpia_camera_ops
*ops
)
3900 /* Default everything to 0 */
3901 memset(cam
, 0, sizeof(struct cam_data
));
3904 mutex_init(&cam
->param_lock
);
3905 mutex_init(&cam
->busy_lock
);
3907 reset_camera_struct(cam
);
3909 cam
->proc_entry
= NULL
;
3911 memcpy(&cam
->vdev
, &cpia_template
, sizeof(cpia_template
));
3912 video_set_drvdata(&cam
->vdev
, cam
);
3915 for (i
= 0; i
< FRAME_NUM
; i
++) {
3916 cam
->frame
[i
].width
= 0;
3917 cam
->frame
[i
].height
= 0;
3918 cam
->frame
[i
].state
= FRAME_UNUSED
;
3919 cam
->frame
[i
].data
= NULL
;
3921 cam
->decompressed_frame
.width
= 0;
3922 cam
->decompressed_frame
.height
= 0;
3923 cam
->decompressed_frame
.state
= FRAME_UNUSED
;
3924 cam
->decompressed_frame
.data
= NULL
;
3927 struct cam_data
*cpia_register_camera(struct cpia_camera_ops
*ops
, void *lowlevel
)
3929 struct cam_data
*camera
;
3931 if ((camera
= kmalloc(sizeof(struct cam_data
), GFP_KERNEL
)) == NULL
)
3935 init_camera_struct( camera
, ops
);
3936 camera
->lowlevel_data
= lowlevel
;
3938 /* register v4l device */
3939 if (video_register_device(&camera
->vdev
, VFL_TYPE_GRABBER
, video_nr
) < 0) {
3941 printk(KERN_DEBUG
"video_register_device failed\n");
3945 /* get version information from camera: open/reset/close */
3948 if (camera
->ops
->open(camera
->lowlevel_data
))
3951 /* reset the camera */
3952 if (reset_camera(camera
) != 0) {
3953 camera
->ops
->close(camera
->lowlevel_data
);
3958 camera
->ops
->close(camera
->lowlevel_data
);
3960 #ifdef CONFIG_PROC_FS
3961 create_proc_cpia_cam(camera
);
3964 printk(KERN_INFO
" CPiA Version: %d.%02d (%d.%d)\n",
3965 camera
->params
.version
.firmwareVersion
,
3966 camera
->params
.version
.firmwareRevision
,
3967 camera
->params
.version
.vcVersion
,
3968 camera
->params
.version
.vcRevision
);
3969 printk(KERN_INFO
" CPiA PnP-ID: %04x:%04x:%04x\n",
3970 camera
->params
.pnpID
.vendor
,
3971 camera
->params
.pnpID
.product
,
3972 camera
->params
.pnpID
.deviceRevision
);
3973 printk(KERN_INFO
" VP-Version: %d.%d %04x\n",
3974 camera
->params
.vpVersion
.vpVersion
,
3975 camera
->params
.vpVersion
.vpRevision
,
3976 camera
->params
.vpVersion
.cameraHeadID
);
3981 void cpia_unregister_camera(struct cam_data
*cam
)
3983 DBG("unregistering video\n");
3984 video_unregister_device(&cam
->vdev
);
3985 if (cam
->open_count
) {
3987 DBG("camera open -- setting ops to NULL\n");
3991 #ifdef CONFIG_PROC_FS
3992 DBG("destroying /proc/cpia/%s\n", video_device_node_name(&cam
->vdev
));
3993 destroy_proc_cpia_cam(cam
);
3995 if (!cam
->open_count
) {
3996 DBG("freeing camera\n");
4001 static int __init
cpia_init(void)
4003 printk(KERN_INFO
"%s v%d.%d.%d\n", ABOUT
,
4004 CPIA_MAJ_VER
, CPIA_MIN_VER
, CPIA_PATCH_VER
);
4006 printk(KERN_WARNING
"Since in-kernel colorspace conversion is not "
4007 "allowed, it is disabled by default now. Users should fix the "
4008 "applications in case they don't work without conversion "
4009 "reenabled by setting the 'colorspace_conv' module "
4010 "parameter to 1\n");
4012 #ifdef CONFIG_PROC_FS
4019 static void __exit
cpia_exit(void)
4021 #ifdef CONFIG_PROC_FS
4022 proc_cpia_destroy();
4026 module_init(cpia_init
);
4027 module_exit(cpia_exit
);
4029 /* Exported symbols for modules. */
4031 EXPORT_SYMBOL(cpia_register_camera
);
4032 EXPORT_SYMBOL(cpia_unregister_camera
);