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/slab.h>
35 #include <linux/proc_fs.h>
36 #include <linux/ctype.h>
37 #include <linux/pagemap.h>
38 #include <linux/delay.h>
40 #include <linux/mutex.h>
44 static int video_nr
= -1;
47 module_param(video_nr
, int, 0);
48 MODULE_AUTHOR("Scott J. Bertin <sbertin@securenym.net> & Peter Pregler <Peter_Pregler@email.com> & Johannes Erdfelt <johannes@erdfelt.com>");
49 MODULE_DESCRIPTION("V4L-driver for Vision CPiA based cameras");
50 MODULE_LICENSE("GPL");
51 MODULE_SUPPORTED_DEVICE("video");
54 static unsigned short colorspace_conv
;
55 module_param(colorspace_conv
, ushort
, 0444);
56 MODULE_PARM_DESC(colorspace_conv
,
57 " Colorspace conversion:"
58 "\n 0 = disable, 1 = enable"
59 "\n Default value is 0"
62 #define ABOUT "V4L-Driver for Vision CPiA based cameras"
64 #define CPIA_MODULE_CPIA (0<<5)
65 #define CPIA_MODULE_SYSTEM (1<<5)
66 #define CPIA_MODULE_VP_CTRL (5<<5)
67 #define CPIA_MODULE_CAPTURE (6<<5)
68 #define CPIA_MODULE_DEBUG (7<<5)
70 #define INPUT (DATA_IN << 8)
71 #define OUTPUT (DATA_OUT << 8)
73 #define CPIA_COMMAND_GetCPIAVersion (INPUT | CPIA_MODULE_CPIA | 1)
74 #define CPIA_COMMAND_GetPnPID (INPUT | CPIA_MODULE_CPIA | 2)
75 #define CPIA_COMMAND_GetCameraStatus (INPUT | CPIA_MODULE_CPIA | 3)
76 #define CPIA_COMMAND_GotoHiPower (OUTPUT | CPIA_MODULE_CPIA | 4)
77 #define CPIA_COMMAND_GotoLoPower (OUTPUT | CPIA_MODULE_CPIA | 5)
78 #define CPIA_COMMAND_GotoSuspend (OUTPUT | CPIA_MODULE_CPIA | 7)
79 #define CPIA_COMMAND_GotoPassThrough (OUTPUT | CPIA_MODULE_CPIA | 8)
80 #define CPIA_COMMAND_ModifyCameraStatus (OUTPUT | CPIA_MODULE_CPIA | 10)
82 #define CPIA_COMMAND_ReadVCRegs (INPUT | CPIA_MODULE_SYSTEM | 1)
83 #define CPIA_COMMAND_WriteVCReg (OUTPUT | CPIA_MODULE_SYSTEM | 2)
84 #define CPIA_COMMAND_ReadMCPorts (INPUT | CPIA_MODULE_SYSTEM | 3)
85 #define CPIA_COMMAND_WriteMCPort (OUTPUT | CPIA_MODULE_SYSTEM | 4)
86 #define CPIA_COMMAND_SetBaudRate (OUTPUT | CPIA_MODULE_SYSTEM | 5)
87 #define CPIA_COMMAND_SetECPTiming (OUTPUT | CPIA_MODULE_SYSTEM | 6)
88 #define CPIA_COMMAND_ReadIDATA (INPUT | CPIA_MODULE_SYSTEM | 7)
89 #define CPIA_COMMAND_WriteIDATA (OUTPUT | CPIA_MODULE_SYSTEM | 8)
90 #define CPIA_COMMAND_GenericCall (OUTPUT | CPIA_MODULE_SYSTEM | 9)
91 #define CPIA_COMMAND_I2CStart (OUTPUT | CPIA_MODULE_SYSTEM | 10)
92 #define CPIA_COMMAND_I2CStop (OUTPUT | CPIA_MODULE_SYSTEM | 11)
93 #define CPIA_COMMAND_I2CWrite (OUTPUT | CPIA_MODULE_SYSTEM | 12)
94 #define CPIA_COMMAND_I2CRead (INPUT | CPIA_MODULE_SYSTEM | 13)
96 #define CPIA_COMMAND_GetVPVersion (INPUT | CPIA_MODULE_VP_CTRL | 1)
97 #define CPIA_COMMAND_ResetFrameCounter (INPUT | CPIA_MODULE_VP_CTRL | 2)
98 #define CPIA_COMMAND_SetColourParams (OUTPUT | CPIA_MODULE_VP_CTRL | 3)
99 #define CPIA_COMMAND_SetExposure (OUTPUT | CPIA_MODULE_VP_CTRL | 4)
100 #define CPIA_COMMAND_SetColourBalance (OUTPUT | CPIA_MODULE_VP_CTRL | 6)
101 #define CPIA_COMMAND_SetSensorFPS (OUTPUT | CPIA_MODULE_VP_CTRL | 7)
102 #define CPIA_COMMAND_SetVPDefaults (OUTPUT | CPIA_MODULE_VP_CTRL | 8)
103 #define CPIA_COMMAND_SetApcor (OUTPUT | CPIA_MODULE_VP_CTRL | 9)
104 #define CPIA_COMMAND_SetFlickerCtrl (OUTPUT | CPIA_MODULE_VP_CTRL | 10)
105 #define CPIA_COMMAND_SetVLOffset (OUTPUT | CPIA_MODULE_VP_CTRL | 11)
106 #define CPIA_COMMAND_GetColourParams (INPUT | CPIA_MODULE_VP_CTRL | 16)
107 #define CPIA_COMMAND_GetColourBalance (INPUT | CPIA_MODULE_VP_CTRL | 17)
108 #define CPIA_COMMAND_GetExposure (INPUT | CPIA_MODULE_VP_CTRL | 18)
109 #define CPIA_COMMAND_SetSensorMatrix (OUTPUT | CPIA_MODULE_VP_CTRL | 19)
110 #define CPIA_COMMAND_ColourBars (OUTPUT | CPIA_MODULE_VP_CTRL | 25)
111 #define CPIA_COMMAND_ReadVPRegs (INPUT | CPIA_MODULE_VP_CTRL | 30)
112 #define CPIA_COMMAND_WriteVPReg (OUTPUT | CPIA_MODULE_VP_CTRL | 31)
114 #define CPIA_COMMAND_GrabFrame (OUTPUT | CPIA_MODULE_CAPTURE | 1)
115 #define CPIA_COMMAND_UploadFrame (OUTPUT | CPIA_MODULE_CAPTURE | 2)
116 #define CPIA_COMMAND_SetGrabMode (OUTPUT | CPIA_MODULE_CAPTURE | 3)
117 #define CPIA_COMMAND_InitStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 4)
118 #define CPIA_COMMAND_FiniStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 5)
119 #define CPIA_COMMAND_StartStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 6)
120 #define CPIA_COMMAND_EndStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 7)
121 #define CPIA_COMMAND_SetFormat (OUTPUT | CPIA_MODULE_CAPTURE | 8)
122 #define CPIA_COMMAND_SetROI (OUTPUT | CPIA_MODULE_CAPTURE | 9)
123 #define CPIA_COMMAND_SetCompression (OUTPUT | CPIA_MODULE_CAPTURE | 10)
124 #define CPIA_COMMAND_SetCompressionTarget (OUTPUT | CPIA_MODULE_CAPTURE | 11)
125 #define CPIA_COMMAND_SetYUVThresh (OUTPUT | CPIA_MODULE_CAPTURE | 12)
126 #define CPIA_COMMAND_SetCompressionParams (OUTPUT | CPIA_MODULE_CAPTURE | 13)
127 #define CPIA_COMMAND_DiscardFrame (OUTPUT | CPIA_MODULE_CAPTURE | 14)
128 #define CPIA_COMMAND_GrabReset (OUTPUT | CPIA_MODULE_CAPTURE | 15)
130 #define CPIA_COMMAND_OutputRS232 (OUTPUT | CPIA_MODULE_DEBUG | 1)
131 #define CPIA_COMMAND_AbortProcess (OUTPUT | CPIA_MODULE_DEBUG | 4)
132 #define CPIA_COMMAND_SetDramPage (OUTPUT | CPIA_MODULE_DEBUG | 5)
133 #define CPIA_COMMAND_StartDramUpload (OUTPUT | CPIA_MODULE_DEBUG | 6)
134 #define CPIA_COMMAND_StartDummyDtream (OUTPUT | CPIA_MODULE_DEBUG | 8)
135 #define CPIA_COMMAND_AbortStream (OUTPUT | CPIA_MODULE_DEBUG | 9)
136 #define CPIA_COMMAND_DownloadDRAM (OUTPUT | CPIA_MODULE_DEBUG | 10)
137 #define CPIA_COMMAND_Null (OUTPUT | CPIA_MODULE_DEBUG | 11)
140 FRAME_READY
, /* Ready to grab into */
141 FRAME_GRABBING
, /* In the process of being grabbed into */
142 FRAME_DONE
, /* Finished grabbing, but not been synced yet */
143 FRAME_UNUSED
, /* Unused (no MCAPTURE) */
146 #define COMMAND_NONE 0x0000
147 #define COMMAND_SETCOMPRESSION 0x0001
148 #define COMMAND_SETCOMPRESSIONTARGET 0x0002
149 #define COMMAND_SETCOLOURPARAMS 0x0004
150 #define COMMAND_SETFORMAT 0x0008
151 #define COMMAND_PAUSE 0x0010
152 #define COMMAND_RESUME 0x0020
153 #define COMMAND_SETYUVTHRESH 0x0040
154 #define COMMAND_SETECPTIMING 0x0080
155 #define COMMAND_SETCOMPRESSIONPARAMS 0x0100
156 #define COMMAND_SETEXPOSURE 0x0200
157 #define COMMAND_SETCOLOURBALANCE 0x0400
158 #define COMMAND_SETSENSORFPS 0x0800
159 #define COMMAND_SETAPCOR 0x1000
160 #define COMMAND_SETFLICKERCTRL 0x2000
161 #define COMMAND_SETVLOFFSET 0x4000
162 #define COMMAND_SETLIGHTS 0x8000
164 #define ROUND_UP_EXP_FOR_FLICKER 15
166 /* Constants for automatic frame rate adjustment */
168 #define MAX_EXP_102 255
170 #define VERY_LOW_EXP 70
172 #define EXP_ACC_DARK 50
173 #define EXP_ACC_LIGHT 90
174 #define HIGH_COMP_102 160
179 /* Maximum number of 10ms loops to wait for the stream to become ready */
180 #define READY_TIMEOUT 100
182 /* Developer's Guide Table 5 p 3-34
183 * indexed by [mains][sensorFps.baserate][sensorFps.divisor]*/
184 static u8 flicker_jumps
[2][2][4] =
185 { { { 76, 38, 19, 9 }, { 92, 46, 23, 11 } },
186 { { 64, 32, 16, 8 }, { 76, 38, 19, 9} }
189 /* forward declaration of local function */
190 static void reset_camera_struct(struct cam_data
*cam
);
191 static int find_over_exposure(int brightness
);
192 static void set_flicker(struct cam_params
*params
, volatile u32
*command_flags
,
196 /**********************************************************************
200 **********************************************************************/
201 static void *rvmalloc(unsigned long size
)
206 size
= PAGE_ALIGN(size
);
207 mem
= vmalloc_32(size
);
211 memset(mem
, 0, size
); /* Clear the ram out, no junk to the user */
212 adr
= (unsigned long) mem
;
214 SetPageReserved(vmalloc_to_page((void *)adr
));
222 static void rvfree(void *mem
, unsigned long size
)
229 adr
= (unsigned long) mem
;
230 while ((long) size
> 0) {
231 ClearPageReserved(vmalloc_to_page((void *)adr
));
238 /**********************************************************************
242 **********************************************************************/
243 #ifdef CONFIG_PROC_FS
244 static struct proc_dir_entry
*cpia_proc_root
=NULL
;
246 static int cpia_read_proc(char *page
, char **start
, off_t off
,
247 int count
, int *eof
, void *data
)
251 struct cam_data
*cam
= data
;
254 /* IMPORTANT: This output MUST be kept under PAGE_SIZE
255 * or we need to get more sophisticated. */
257 out
+= sprintf(out
, "read-only\n-----------------------\n");
258 out
+= sprintf(out
, "V4L Driver version: %d.%d.%d\n",
259 CPIA_MAJ_VER
, CPIA_MIN_VER
, CPIA_PATCH_VER
);
260 out
+= sprintf(out
, "CPIA Version: %d.%02d (%d.%d)\n",
261 cam
->params
.version
.firmwareVersion
,
262 cam
->params
.version
.firmwareRevision
,
263 cam
->params
.version
.vcVersion
,
264 cam
->params
.version
.vcRevision
);
265 out
+= sprintf(out
, "CPIA PnP-ID: %04x:%04x:%04x\n",
266 cam
->params
.pnpID
.vendor
, cam
->params
.pnpID
.product
,
267 cam
->params
.pnpID
.deviceRevision
);
268 out
+= sprintf(out
, "VP-Version: %d.%d %04x\n",
269 cam
->params
.vpVersion
.vpVersion
,
270 cam
->params
.vpVersion
.vpRevision
,
271 cam
->params
.vpVersion
.cameraHeadID
);
273 out
+= sprintf(out
, "system_state: %#04x\n",
274 cam
->params
.status
.systemState
);
275 out
+= sprintf(out
, "grab_state: %#04x\n",
276 cam
->params
.status
.grabState
);
277 out
+= sprintf(out
, "stream_state: %#04x\n",
278 cam
->params
.status
.streamState
);
279 out
+= sprintf(out
, "fatal_error: %#04x\n",
280 cam
->params
.status
.fatalError
);
281 out
+= sprintf(out
, "cmd_error: %#04x\n",
282 cam
->params
.status
.cmdError
);
283 out
+= sprintf(out
, "debug_flags: %#04x\n",
284 cam
->params
.status
.debugFlags
);
285 out
+= sprintf(out
, "vp_status: %#04x\n",
286 cam
->params
.status
.vpStatus
);
287 out
+= sprintf(out
, "error_code: %#04x\n",
288 cam
->params
.status
.errorCode
);
289 /* QX3 specific entries */
290 if (cam
->params
.qx3
.qx3_detected
) {
291 out
+= sprintf(out
, "button: %4d\n",
292 cam
->params
.qx3
.button
);
293 out
+= sprintf(out
, "cradled: %4d\n",
294 cam
->params
.qx3
.cradled
);
296 out
+= sprintf(out
, "video_size: %s\n",
297 cam
->params
.format
.videoSize
== VIDEOSIZE_CIF
?
299 out
+= sprintf(out
, "roi: (%3d, %3d) to (%3d, %3d)\n",
300 cam
->params
.roi
.colStart
*8,
301 cam
->params
.roi
.rowStart
*4,
302 cam
->params
.roi
.colEnd
*8,
303 cam
->params
.roi
.rowEnd
*4);
304 out
+= sprintf(out
, "actual_fps: %3d\n", cam
->fps
);
305 out
+= sprintf(out
, "transfer_rate: %4dkB/s\n",
308 out
+= sprintf(out
, "\nread-write\n");
309 out
+= sprintf(out
, "----------------------- current min"
310 " max default comment\n");
311 out
+= sprintf(out
, "brightness: %8d %8d %8d %8d\n",
312 cam
->params
.colourParams
.brightness
, 0, 100, 50);
313 if (cam
->params
.version
.firmwareVersion
== 1 &&
314 cam
->params
.version
.firmwareRevision
== 2)
315 /* 1-02 firmware limits contrast to 80 */
320 out
+= sprintf(out
, "contrast: %8d %8d %8d %8d"
322 cam
->params
.colourParams
.contrast
, 0, tmp
, 48);
323 out
+= sprintf(out
, "saturation: %8d %8d %8d %8d\n",
324 cam
->params
.colourParams
.saturation
, 0, 100, 50);
325 tmp
= (25000+5000*cam
->params
.sensorFps
.baserate
)/
326 (1<<cam
->params
.sensorFps
.divisor
);
327 out
+= sprintf(out
, "sensor_fps: %4d.%03d %8d %8d %8d\n",
328 tmp
/1000, tmp
%1000, 3, 30, 15);
329 out
+= sprintf(out
, "stream_start_line: %8d %8d %8d %8d\n",
330 2*cam
->params
.streamStartLine
, 0,
331 cam
->params
.format
.videoSize
== VIDEOSIZE_CIF
? 288:144,
332 cam
->params
.format
.videoSize
== VIDEOSIZE_CIF
? 240:120);
333 out
+= sprintf(out
, "sub_sample: %8s %8s %8s %8s\n",
334 cam
->params
.format
.subSample
== SUBSAMPLE_420
?
335 "420" : "422", "420", "422", "422");
336 out
+= sprintf(out
, "yuv_order: %8s %8s %8s %8s\n",
337 cam
->params
.format
.yuvOrder
== YUVORDER_YUYV
?
338 "YUYV" : "UYVY", "YUYV" , "UYVY", "YUYV");
339 out
+= sprintf(out
, "ecp_timing: %8s %8s %8s %8s\n",
340 cam
->params
.ecpTiming
? "slow" : "normal", "slow",
343 if (cam
->params
.colourBalance
.balanceMode
== 2) {
344 sprintf(tmpstr
, "auto");
346 sprintf(tmpstr
, "manual");
348 out
+= sprintf(out
, "color_balance_mode: %8s %8s %8s"
349 " %8s\n", tmpstr
, "manual", "auto", "auto");
350 out
+= sprintf(out
, "red_gain: %8d %8d %8d %8d\n",
351 cam
->params
.colourBalance
.redGain
, 0, 212, 32);
352 out
+= sprintf(out
, "green_gain: %8d %8d %8d %8d\n",
353 cam
->params
.colourBalance
.greenGain
, 0, 212, 6);
354 out
+= sprintf(out
, "blue_gain: %8d %8d %8d %8d\n",
355 cam
->params
.colourBalance
.blueGain
, 0, 212, 92);
357 if (cam
->params
.version
.firmwareVersion
== 1 &&
358 cam
->params
.version
.firmwareRevision
== 2)
359 /* 1-02 firmware limits gain to 2 */
360 sprintf(tmpstr
, "%8d %8d %8d", 1, 2, 2);
362 sprintf(tmpstr
, "%8d %8d %8d", 1, 8, 2);
364 if (cam
->params
.exposure
.gainMode
== 0)
365 out
+= sprintf(out
, "max_gain: unknown %28s"
366 " powers of 2\n", tmpstr
);
368 out
+= sprintf(out
, "max_gain: %8d %28s"
370 1<<(cam
->params
.exposure
.gainMode
-1), tmpstr
);
372 switch(cam
->params
.exposure
.expMode
) {
375 sprintf(tmpstr
, "manual");
378 sprintf(tmpstr
, "auto");
381 sprintf(tmpstr
, "unknown");
384 out
+= sprintf(out
, "exposure_mode: %8s %8s %8s"
385 " %8s\n", tmpstr
, "manual", "auto", "auto");
386 out
+= sprintf(out
, "centre_weight: %8s %8s %8s %8s\n",
387 (2-cam
->params
.exposure
.centreWeight
) ? "on" : "off",
389 out
+= sprintf(out
, "gain: %8d %8d max_gain %8d 1,2,4,8 possible\n",
390 1<<cam
->params
.exposure
.gain
, 1, 1);
391 if (cam
->params
.version
.firmwareVersion
== 1 &&
392 cam
->params
.version
.firmwareRevision
== 2)
393 /* 1-02 firmware limits fineExp/2 to 127 */
398 out
+= sprintf(out
, "fine_exp: %8d %8d %8d %8d\n",
399 cam
->params
.exposure
.fineExp
*2, 0, tmp
, 0);
400 if (cam
->params
.version
.firmwareVersion
== 1 &&
401 cam
->params
.version
.firmwareRevision
== 2)
402 /* 1-02 firmware limits coarseExpHi to 0 */
407 out
+= sprintf(out
, "coarse_exp: %8d %8d %8d"
408 " %8d\n", cam
->params
.exposure
.coarseExpLo
+
409 256*cam
->params
.exposure
.coarseExpHi
, 0, tmp
, 185);
410 out
+= sprintf(out
, "red_comp: %8d %8d %8d %8d\n",
411 cam
->params
.exposure
.redComp
, COMP_RED
, 255, COMP_RED
);
412 out
+= sprintf(out
, "green1_comp: %8d %8d %8d %8d\n",
413 cam
->params
.exposure
.green1Comp
, COMP_GREEN1
, 255,
415 out
+= sprintf(out
, "green2_comp: %8d %8d %8d %8d\n",
416 cam
->params
.exposure
.green2Comp
, COMP_GREEN2
, 255,
418 out
+= sprintf(out
, "blue_comp: %8d %8d %8d %8d\n",
419 cam
->params
.exposure
.blueComp
, COMP_BLUE
, 255, COMP_BLUE
);
421 out
+= sprintf(out
, "apcor_gain1: %#8x %#8x %#8x %#8x\n",
422 cam
->params
.apcor
.gain1
, 0, 0xff, 0x1c);
423 out
+= sprintf(out
, "apcor_gain2: %#8x %#8x %#8x %#8x\n",
424 cam
->params
.apcor
.gain2
, 0, 0xff, 0x1a);
425 out
+= sprintf(out
, "apcor_gain4: %#8x %#8x %#8x %#8x\n",
426 cam
->params
.apcor
.gain4
, 0, 0xff, 0x2d);
427 out
+= sprintf(out
, "apcor_gain8: %#8x %#8x %#8x %#8x\n",
428 cam
->params
.apcor
.gain8
, 0, 0xff, 0x2a);
429 out
+= sprintf(out
, "vl_offset_gain1: %8d %8d %8d %8d\n",
430 cam
->params
.vlOffset
.gain1
, 0, 255, 24);
431 out
+= sprintf(out
, "vl_offset_gain2: %8d %8d %8d %8d\n",
432 cam
->params
.vlOffset
.gain2
, 0, 255, 28);
433 out
+= sprintf(out
, "vl_offset_gain4: %8d %8d %8d %8d\n",
434 cam
->params
.vlOffset
.gain4
, 0, 255, 30);
435 out
+= sprintf(out
, "vl_offset_gain8: %8d %8d %8d %8d\n",
436 cam
->params
.vlOffset
.gain8
, 0, 255, 30);
437 out
+= sprintf(out
, "flicker_control: %8s %8s %8s %8s\n",
438 cam
->params
.flickerControl
.flickerMode
? "on" : "off",
440 out
+= sprintf(out
, "mains_frequency: %8d %8d %8d %8d"
442 cam
->mainsFreq
? 60 : 50, 50, 60, 50);
443 if(cam
->params
.flickerControl
.allowableOverExposure
< 0)
444 out
+= sprintf(out
, "allowable_overexposure: %4dauto auto %8d auto\n",
445 -cam
->params
.flickerControl
.allowableOverExposure
,
448 out
+= sprintf(out
, "allowable_overexposure: %8d auto %8d auto\n",
449 cam
->params
.flickerControl
.allowableOverExposure
,
451 out
+= sprintf(out
, "compression_mode: ");
452 switch(cam
->params
.compression
.mode
) {
453 case CPIA_COMPRESSION_NONE
:
454 out
+= sprintf(out
, "%8s", "none");
456 case CPIA_COMPRESSION_AUTO
:
457 out
+= sprintf(out
, "%8s", "auto");
459 case CPIA_COMPRESSION_MANUAL
:
460 out
+= sprintf(out
, "%8s", "manual");
463 out
+= sprintf(out
, "%8s", "unknown");
466 out
+= sprintf(out
, " none,auto,manual auto\n");
467 out
+= sprintf(out
, "decimation_enable: %8s %8s %8s %8s\n",
468 cam
->params
.compression
.decimation
==
469 DECIMATION_ENAB
? "on":"off", "off", "on",
471 out
+= sprintf(out
, "compression_target: %9s %9s %9s %9s\n",
472 cam
->params
.compressionTarget
.frTargeting
==
473 CPIA_COMPRESSION_TARGET_FRAMERATE
?
474 "framerate":"quality",
475 "framerate", "quality", "quality");
476 out
+= sprintf(out
, "target_framerate: %8d %8d %8d %8d\n",
477 cam
->params
.compressionTarget
.targetFR
, 1, 30, 15);
478 out
+= sprintf(out
, "target_quality: %8d %8d %8d %8d\n",
479 cam
->params
.compressionTarget
.targetQ
, 1, 64, 5);
480 out
+= sprintf(out
, "y_threshold: %8d %8d %8d %8d\n",
481 cam
->params
.yuvThreshold
.yThreshold
, 0, 31, 6);
482 out
+= sprintf(out
, "uv_threshold: %8d %8d %8d %8d\n",
483 cam
->params
.yuvThreshold
.uvThreshold
, 0, 31, 6);
484 out
+= sprintf(out
, "hysteresis: %8d %8d %8d %8d\n",
485 cam
->params
.compressionParams
.hysteresis
, 0, 255, 3);
486 out
+= sprintf(out
, "threshold_max: %8d %8d %8d %8d\n",
487 cam
->params
.compressionParams
.threshMax
, 0, 255, 11);
488 out
+= sprintf(out
, "small_step: %8d %8d %8d %8d\n",
489 cam
->params
.compressionParams
.smallStep
, 0, 255, 1);
490 out
+= sprintf(out
, "large_step: %8d %8d %8d %8d\n",
491 cam
->params
.compressionParams
.largeStep
, 0, 255, 3);
492 out
+= sprintf(out
, "decimation_hysteresis: %8d %8d %8d %8d\n",
493 cam
->params
.compressionParams
.decimationHysteresis
,
495 out
+= sprintf(out
, "fr_diff_step_thresh: %8d %8d %8d %8d\n",
496 cam
->params
.compressionParams
.frDiffStepThresh
,
498 out
+= sprintf(out
, "q_diff_step_thresh: %8d %8d %8d %8d\n",
499 cam
->params
.compressionParams
.qDiffStepThresh
,
501 out
+= sprintf(out
, "decimation_thresh_mod: %8d %8d %8d %8d\n",
502 cam
->params
.compressionParams
.decimationThreshMod
,
504 /* QX3 specific entries */
505 if (cam
->params
.qx3
.qx3_detected
) {
506 out
+= sprintf(out
, "toplight: %8s %8s %8s %8s\n",
507 cam
->params
.qx3
.toplight
? "on" : "off",
509 out
+= sprintf(out
, "bottomlight: %8s %8s %8s %8s\n",
510 cam
->params
.qx3
.bottomlight
? "on" : "off",
518 if (len
<= 0) return 0;
527 static int match(char *checkstr
, char **buffer
, unsigned long *count
,
528 int *find_colon
, int *err
)
530 int ret
, colon_found
= 1;
531 int len
= strlen(checkstr
);
532 ret
= (len
<= *count
&& strncmp(*buffer
, checkstr
, len
) == 0);
538 while (*count
&& (**buffer
== ' ' || **buffer
== '\t' ||
539 (!colon_found
&& **buffer
== ':'))) {
545 if (!*count
|| !colon_found
)
553 static unsigned long int value(char **buffer
, unsigned long *count
, int *err
)
556 unsigned long int ret
;
557 ret
= simple_strtoul(*buffer
, &p
, 0);
561 *count
-= p
- *buffer
;
567 static int cpia_write_proc(struct file
*file
, const char __user
*buf
,
568 unsigned long count
, void *data
)
570 struct cam_data
*cam
= data
;
571 struct cam_params new_params
;
573 int retval
, find_colon
;
575 unsigned long val
= 0;
576 u32 command_flags
= 0;
580 * This code to copy from buf to page is shamelessly copied
581 * from the comx driver
583 if (count
> PAGE_SIZE
) {
584 printk(KERN_ERR
"count is %lu > %d!!!\n", count
, (int)PAGE_SIZE
);
588 if (!(page
= (char *)__get_free_page(GFP_KERNEL
))) return -ENOMEM
;
590 if(copy_from_user(page
, buf
, count
))
596 if (page
[count
-1] == '\n')
597 page
[count
-1] = '\0';
598 else if (count
< PAGE_SIZE
)
600 else if (page
[count
]) {
607 if (mutex_lock_interruptible(&cam
->param_lock
))
611 * Skip over leading whitespace
613 while (count
&& isspace(*buffer
)) {
618 memcpy(&new_params
, &cam
->params
, sizeof(struct cam_params
));
619 new_mains
= cam
->mainsFreq
;
621 #define MATCH(x) (match(x, &buffer, &count, &find_colon, &retval))
622 #define VALUE (value(&buffer,&count, &retval))
623 #define FIRMWARE_VERSION(x,y) (new_params.version.firmwareVersion == (x) && \
624 new_params.version.firmwareRevision == (y))
627 while (count
&& !retval
) {
629 if (MATCH("brightness")) {
635 new_params
.colourParams
.brightness
= val
;
639 command_flags
|= COMMAND_SETCOLOURPARAMS
;
640 if(new_params
.flickerControl
.allowableOverExposure
< 0)
641 new_params
.flickerControl
.allowableOverExposure
=
642 -find_over_exposure(new_params
.colourParams
.brightness
);
643 if(new_params
.flickerControl
.flickerMode
!= 0)
644 command_flags
|= COMMAND_SETFLICKERCTRL
;
646 } else if (MATCH("contrast")) {
652 /* contrast is in steps of 8, so round*/
653 val
= ((val
+ 3) / 8) * 8;
654 /* 1-02 firmware limits contrast to 80*/
655 if (FIRMWARE_VERSION(1,2) && val
> 80)
658 new_params
.colourParams
.contrast
= val
;
662 command_flags
|= COMMAND_SETCOLOURPARAMS
;
663 } else if (MATCH("saturation")) {
669 new_params
.colourParams
.saturation
= val
;
673 command_flags
|= COMMAND_SETCOLOURPARAMS
;
674 } else if (MATCH("sensor_fps")) {
679 /* find values so that sensorFPS is minimized,
684 new_params
.sensorFps
.divisor
= 0;
685 new_params
.sensorFps
.baserate
= 1;
686 } else if (val
> 15) {
687 new_params
.sensorFps
.divisor
= 0;
688 new_params
.sensorFps
.baserate
= 0;
689 } else if (val
> 12) {
690 new_params
.sensorFps
.divisor
= 1;
691 new_params
.sensorFps
.baserate
= 1;
692 } else if (val
> 7) {
693 new_params
.sensorFps
.divisor
= 1;
694 new_params
.sensorFps
.baserate
= 0;
695 } else if (val
> 6) {
696 new_params
.sensorFps
.divisor
= 2;
697 new_params
.sensorFps
.baserate
= 1;
698 } else if (val
> 3) {
699 new_params
.sensorFps
.divisor
= 2;
700 new_params
.sensorFps
.baserate
= 0;
702 new_params
.sensorFps
.divisor
= 3;
703 /* Either base rate would work here */
704 new_params
.sensorFps
.baserate
= 1;
706 new_params
.flickerControl
.coarseJump
=
707 flicker_jumps
[new_mains
]
708 [new_params
.sensorFps
.baserate
]
709 [new_params
.sensorFps
.divisor
];
710 if (new_params
.flickerControl
.flickerMode
)
711 command_flags
|= COMMAND_SETFLICKERCTRL
;
713 command_flags
|= COMMAND_SETSENSORFPS
;
714 cam
->exposure_status
= EXPOSURE_NORMAL
;
715 } else if (MATCH("stream_start_line")) {
722 if (new_params
.format
.videoSize
== VIDEOSIZE_QCIF
)
725 new_params
.streamStartLine
= val
/2;
729 } else if (MATCH("sub_sample")) {
730 if (!retval
&& MATCH("420"))
731 new_params
.format
.subSample
= SUBSAMPLE_420
;
732 else if (!retval
&& MATCH("422"))
733 new_params
.format
.subSample
= SUBSAMPLE_422
;
737 command_flags
|= COMMAND_SETFORMAT
;
738 } else if (MATCH("yuv_order")) {
739 if (!retval
&& MATCH("YUYV"))
740 new_params
.format
.yuvOrder
= YUVORDER_YUYV
;
741 else if (!retval
&& MATCH("UYVY"))
742 new_params
.format
.yuvOrder
= YUVORDER_UYVY
;
746 command_flags
|= COMMAND_SETFORMAT
;
747 } else if (MATCH("ecp_timing")) {
748 if (!retval
&& MATCH("normal"))
749 new_params
.ecpTiming
= 0;
750 else if (!retval
&& MATCH("slow"))
751 new_params
.ecpTiming
= 1;
755 command_flags
|= COMMAND_SETECPTIMING
;
756 } else if (MATCH("color_balance_mode")) {
757 if (!retval
&& MATCH("manual"))
758 new_params
.colourBalance
.balanceMode
= 3;
759 else if (!retval
&& MATCH("auto"))
760 new_params
.colourBalance
.balanceMode
= 2;
764 command_flags
|= COMMAND_SETCOLOURBALANCE
;
765 } else if (MATCH("red_gain")) {
771 new_params
.colourBalance
.redGain
= val
;
772 new_params
.colourBalance
.balanceMode
= 1;
776 command_flags
|= COMMAND_SETCOLOURBALANCE
;
777 } else if (MATCH("green_gain")) {
783 new_params
.colourBalance
.greenGain
= val
;
784 new_params
.colourBalance
.balanceMode
= 1;
788 command_flags
|= COMMAND_SETCOLOURBALANCE
;
789 } else if (MATCH("blue_gain")) {
795 new_params
.colourBalance
.blueGain
= val
;
796 new_params
.colourBalance
.balanceMode
= 1;
800 command_flags
|= COMMAND_SETCOLOURBALANCE
;
801 } else if (MATCH("max_gain")) {
806 /* 1-02 firmware limits gain to 2 */
807 if (FIRMWARE_VERSION(1,2) && val
> 2)
811 new_params
.exposure
.gainMode
= 1;
814 new_params
.exposure
.gainMode
= 2;
817 new_params
.exposure
.gainMode
= 3;
820 new_params
.exposure
.gainMode
= 4;
827 command_flags
|= COMMAND_SETEXPOSURE
;
828 } else if (MATCH("exposure_mode")) {
829 if (!retval
&& MATCH("auto"))
830 new_params
.exposure
.expMode
= 2;
831 else if (!retval
&& MATCH("manual")) {
832 if (new_params
.exposure
.expMode
== 2)
833 new_params
.exposure
.expMode
= 3;
834 if(new_params
.flickerControl
.flickerMode
!= 0)
835 command_flags
|= COMMAND_SETFLICKERCTRL
;
836 new_params
.flickerControl
.flickerMode
= 0;
840 command_flags
|= COMMAND_SETEXPOSURE
;
841 } else if (MATCH("centre_weight")) {
842 if (!retval
&& MATCH("on"))
843 new_params
.exposure
.centreWeight
= 1;
844 else if (!retval
&& MATCH("off"))
845 new_params
.exposure
.centreWeight
= 2;
849 command_flags
|= COMMAND_SETEXPOSURE
;
850 } else if (MATCH("gain")) {
857 new_params
.exposure
.gain
= 0;
860 new_params
.exposure
.gain
= 1;
863 new_params
.exposure
.gain
= 2;
866 new_params
.exposure
.gain
= 3;
872 new_params
.exposure
.expMode
= 1;
873 if(new_params
.flickerControl
.flickerMode
!= 0)
874 command_flags
|= COMMAND_SETFLICKERCTRL
;
875 new_params
.flickerControl
.flickerMode
= 0;
876 command_flags
|= COMMAND_SETEXPOSURE
;
877 if (new_params
.exposure
.gain
>
878 new_params
.exposure
.gainMode
-1)
881 } else if (MATCH("fine_exp")) {
887 /* 1-02 firmware limits fineExp/2 to 127*/
888 if (FIRMWARE_VERSION(1,2) && val
> 127)
890 new_params
.exposure
.fineExp
= val
;
891 new_params
.exposure
.expMode
= 1;
892 command_flags
|= COMMAND_SETEXPOSURE
;
893 if(new_params
.flickerControl
.flickerMode
!= 0)
894 command_flags
|= COMMAND_SETFLICKERCTRL
;
895 new_params
.flickerControl
.flickerMode
= 0;
896 command_flags
|= COMMAND_SETFLICKERCTRL
;
900 } else if (MATCH("coarse_exp")) {
905 if (val
<= MAX_EXP
) {
906 if (FIRMWARE_VERSION(1,2) &&
909 new_params
.exposure
.coarseExpLo
=
911 new_params
.exposure
.coarseExpHi
=
913 new_params
.exposure
.expMode
= 1;
914 command_flags
|= COMMAND_SETEXPOSURE
;
915 if(new_params
.flickerControl
.flickerMode
!= 0)
916 command_flags
|= COMMAND_SETFLICKERCTRL
;
917 new_params
.flickerControl
.flickerMode
= 0;
918 command_flags
|= COMMAND_SETFLICKERCTRL
;
922 } else if (MATCH("red_comp")) {
927 if (val
>= COMP_RED
&& val
<= 255) {
928 new_params
.exposure
.redComp
= val
;
929 new_params
.exposure
.compMode
= 1;
930 command_flags
|= COMMAND_SETEXPOSURE
;
934 } else if (MATCH("green1_comp")) {
939 if (val
>= COMP_GREEN1
&& val
<= 255) {
940 new_params
.exposure
.green1Comp
= val
;
941 new_params
.exposure
.compMode
= 1;
942 command_flags
|= COMMAND_SETEXPOSURE
;
946 } else if (MATCH("green2_comp")) {
951 if (val
>= COMP_GREEN2
&& val
<= 255) {
952 new_params
.exposure
.green2Comp
= val
;
953 new_params
.exposure
.compMode
= 1;
954 command_flags
|= COMMAND_SETEXPOSURE
;
958 } else if (MATCH("blue_comp")) {
963 if (val
>= COMP_BLUE
&& val
<= 255) {
964 new_params
.exposure
.blueComp
= val
;
965 new_params
.exposure
.compMode
= 1;
966 command_flags
|= COMMAND_SETEXPOSURE
;
970 } else if (MATCH("apcor_gain1")) {
975 command_flags
|= COMMAND_SETAPCOR
;
977 new_params
.apcor
.gain1
= val
;
981 } else if (MATCH("apcor_gain2")) {
986 command_flags
|= COMMAND_SETAPCOR
;
988 new_params
.apcor
.gain2
= val
;
992 } else if (MATCH("apcor_gain4")) {
997 command_flags
|= COMMAND_SETAPCOR
;
999 new_params
.apcor
.gain4
= val
;
1003 } else if (MATCH("apcor_gain8")) {
1008 command_flags
|= COMMAND_SETAPCOR
;
1010 new_params
.apcor
.gain8
= val
;
1014 } else if (MATCH("vl_offset_gain1")) {
1020 new_params
.vlOffset
.gain1
= val
;
1024 command_flags
|= COMMAND_SETVLOFFSET
;
1025 } else if (MATCH("vl_offset_gain2")) {
1031 new_params
.vlOffset
.gain2
= val
;
1035 command_flags
|= COMMAND_SETVLOFFSET
;
1036 } else if (MATCH("vl_offset_gain4")) {
1042 new_params
.vlOffset
.gain4
= val
;
1046 command_flags
|= COMMAND_SETVLOFFSET
;
1047 } else if (MATCH("vl_offset_gain8")) {
1053 new_params
.vlOffset
.gain8
= val
;
1057 command_flags
|= COMMAND_SETVLOFFSET
;
1058 } else if (MATCH("flicker_control")) {
1059 if (!retval
&& MATCH("on")) {
1060 set_flicker(&new_params
, &command_flags
, 1);
1061 } else if (!retval
&& MATCH("off")) {
1062 set_flicker(&new_params
, &command_flags
, 0);
1066 command_flags
|= COMMAND_SETFLICKERCTRL
;
1067 } else if (MATCH("mains_frequency")) {
1068 if (!retval
&& MATCH("50")) {
1070 new_params
.flickerControl
.coarseJump
=
1071 flicker_jumps
[new_mains
]
1072 [new_params
.sensorFps
.baserate
]
1073 [new_params
.sensorFps
.divisor
];
1074 if (new_params
.flickerControl
.flickerMode
)
1075 command_flags
|= COMMAND_SETFLICKERCTRL
;
1076 } else if (!retval
&& MATCH("60")) {
1078 new_params
.flickerControl
.coarseJump
=
1079 flicker_jumps
[new_mains
]
1080 [new_params
.sensorFps
.baserate
]
1081 [new_params
.sensorFps
.divisor
];
1082 if (new_params
.flickerControl
.flickerMode
)
1083 command_flags
|= COMMAND_SETFLICKERCTRL
;
1086 } else if (MATCH("allowable_overexposure")) {
1087 if (!retval
&& MATCH("auto")) {
1088 new_params
.flickerControl
.allowableOverExposure
=
1089 -find_over_exposure(new_params
.colourParams
.brightness
);
1090 if(new_params
.flickerControl
.flickerMode
!= 0)
1091 command_flags
|= COMMAND_SETFLICKERCTRL
;
1098 new_params
.flickerControl
.
1099 allowableOverExposure
= val
;
1100 if(new_params
.flickerControl
.flickerMode
!= 0)
1101 command_flags
|= COMMAND_SETFLICKERCTRL
;
1106 } else if (MATCH("compression_mode")) {
1107 if (!retval
&& MATCH("none"))
1108 new_params
.compression
.mode
=
1109 CPIA_COMPRESSION_NONE
;
1110 else if (!retval
&& MATCH("auto"))
1111 new_params
.compression
.mode
=
1112 CPIA_COMPRESSION_AUTO
;
1113 else if (!retval
&& MATCH("manual"))
1114 new_params
.compression
.mode
=
1115 CPIA_COMPRESSION_MANUAL
;
1119 command_flags
|= COMMAND_SETCOMPRESSION
;
1120 } else if (MATCH("decimation_enable")) {
1121 if (!retval
&& MATCH("off"))
1122 new_params
.compression
.decimation
= 0;
1123 else if (!retval
&& MATCH("on"))
1124 new_params
.compression
.decimation
= 1;
1128 command_flags
|= COMMAND_SETCOMPRESSION
;
1129 } else if (MATCH("compression_target")) {
1130 if (!retval
&& MATCH("quality"))
1131 new_params
.compressionTarget
.frTargeting
=
1132 CPIA_COMPRESSION_TARGET_QUALITY
;
1133 else if (!retval
&& MATCH("framerate"))
1134 new_params
.compressionTarget
.frTargeting
=
1135 CPIA_COMPRESSION_TARGET_FRAMERATE
;
1139 command_flags
|= COMMAND_SETCOMPRESSIONTARGET
;
1140 } else if (MATCH("target_framerate")) {
1145 if(val
> 0 && val
<= 30)
1146 new_params
.compressionTarget
.targetFR
= val
;
1150 command_flags
|= COMMAND_SETCOMPRESSIONTARGET
;
1151 } else if (MATCH("target_quality")) {
1156 if(val
> 0 && val
<= 64)
1157 new_params
.compressionTarget
.targetQ
= val
;
1161 command_flags
|= COMMAND_SETCOMPRESSIONTARGET
;
1162 } else if (MATCH("y_threshold")) {
1168 new_params
.yuvThreshold
.yThreshold
= val
;
1172 command_flags
|= COMMAND_SETYUVTHRESH
;
1173 } else if (MATCH("uv_threshold")) {
1179 new_params
.yuvThreshold
.uvThreshold
= val
;
1183 command_flags
|= COMMAND_SETYUVTHRESH
;
1184 } else if (MATCH("hysteresis")) {
1190 new_params
.compressionParams
.hysteresis
= val
;
1194 command_flags
|= COMMAND_SETCOMPRESSIONPARAMS
;
1195 } else if (MATCH("threshold_max")) {
1201 new_params
.compressionParams
.threshMax
= val
;
1205 command_flags
|= COMMAND_SETCOMPRESSIONPARAMS
;
1206 } else if (MATCH("small_step")) {
1212 new_params
.compressionParams
.smallStep
= val
;
1216 command_flags
|= COMMAND_SETCOMPRESSIONPARAMS
;
1217 } else if (MATCH("large_step")) {
1223 new_params
.compressionParams
.largeStep
= val
;
1227 command_flags
|= COMMAND_SETCOMPRESSIONPARAMS
;
1228 } else if (MATCH("decimation_hysteresis")) {
1234 new_params
.compressionParams
.decimationHysteresis
= val
;
1238 command_flags
|= COMMAND_SETCOMPRESSIONPARAMS
;
1239 } else if (MATCH("fr_diff_step_thresh")) {
1245 new_params
.compressionParams
.frDiffStepThresh
= val
;
1249 command_flags
|= COMMAND_SETCOMPRESSIONPARAMS
;
1250 } else if (MATCH("q_diff_step_thresh")) {
1256 new_params
.compressionParams
.qDiffStepThresh
= val
;
1260 command_flags
|= COMMAND_SETCOMPRESSIONPARAMS
;
1261 } else if (MATCH("decimation_thresh_mod")) {
1267 new_params
.compressionParams
.decimationThreshMod
= val
;
1271 command_flags
|= COMMAND_SETCOMPRESSIONPARAMS
;
1272 } else if (MATCH("toplight")) {
1273 if (!retval
&& MATCH("on"))
1274 new_params
.qx3
.toplight
= 1;
1275 else if (!retval
&& MATCH("off"))
1276 new_params
.qx3
.toplight
= 0;
1279 command_flags
|= COMMAND_SETLIGHTS
;
1280 } else if (MATCH("bottomlight")) {
1281 if (!retval
&& MATCH("on"))
1282 new_params
.qx3
.bottomlight
= 1;
1283 else if (!retval
&& MATCH("off"))
1284 new_params
.qx3
.bottomlight
= 0;
1287 command_flags
|= COMMAND_SETLIGHTS
;
1289 DBG("No match found\n");
1294 while (count
&& isspace(*buffer
) && *buffer
!= '\n') {
1299 if (*buffer
== '\0' && count
!= 1)
1301 else if (*buffer
!= '\n' && *buffer
!= ';' &&
1313 #undef FIRMWARE_VERSION
1315 if (command_flags
& COMMAND_SETCOLOURPARAMS
) {
1316 /* Adjust cam->vp to reflect these changes */
1317 cam
->vp
.brightness
=
1318 new_params
.colourParams
.brightness
*65535/100;
1320 new_params
.colourParams
.contrast
*65535/100;
1322 new_params
.colourParams
.saturation
*65535/100;
1324 if((command_flags
& COMMAND_SETEXPOSURE
) &&
1325 new_params
.exposure
.expMode
== 2)
1326 cam
->exposure_status
= EXPOSURE_NORMAL
;
1328 memcpy(&cam
->params
, &new_params
, sizeof(struct cam_params
));
1329 cam
->mainsFreq
= new_mains
;
1330 cam
->cmd_queue
|= command_flags
;
1333 DBG("error: %d\n", retval
);
1335 mutex_unlock(&cam
->param_lock
);
1338 free_page((unsigned long)page
);
1342 static void create_proc_cpia_cam(struct cam_data
*cam
)
1344 char name
[5 + 1 + 10 + 1];
1345 struct proc_dir_entry
*ent
;
1347 if (!cpia_proc_root
|| !cam
)
1350 snprintf(name
, sizeof(name
), "video%d", cam
->vdev
.num
);
1352 ent
= create_proc_entry(name
, S_IFREG
|S_IRUGO
|S_IWUSR
, cpia_proc_root
);
1357 ent
->read_proc
= cpia_read_proc
;
1358 ent
->write_proc
= cpia_write_proc
;
1360 size of the proc entry is 3736 bytes for the standard webcam;
1361 the extra features of the QX3 microscope add 189 bytes.
1362 (we have not yet probed the camera to see which type it is).
1364 ent
->size
= 3736 + 189;
1365 cam
->proc_entry
= ent
;
1368 static void destroy_proc_cpia_cam(struct cam_data
*cam
)
1370 char name
[5 + 1 + 10 + 1];
1372 if (!cam
|| !cam
->proc_entry
)
1375 snprintf(name
, sizeof(name
), "video%d", cam
->vdev
.num
);
1376 remove_proc_entry(name
, cpia_proc_root
);
1377 cam
->proc_entry
= NULL
;
1380 static void proc_cpia_create(void)
1382 cpia_proc_root
= proc_mkdir("cpia", NULL
);
1384 if (!cpia_proc_root
)
1385 LOG("Unable to initialise /proc/cpia\n");
1388 static void __exit
proc_cpia_destroy(void)
1390 remove_proc_entry("cpia", NULL
);
1392 #endif /* CONFIG_PROC_FS */
1394 /* ----------------------- debug functions ---------------------- */
1396 #define printstatus(cam) \
1397 DBG("%02x %02x %02x %02x %02x %02x %02x %02x\n",\
1398 cam->params.status.systemState, cam->params.status.grabState, \
1399 cam->params.status.streamState, cam->params.status.fatalError, \
1400 cam->params.status.cmdError, cam->params.status.debugFlags, \
1401 cam->params.status.vpStatus, cam->params.status.errorCode);
1403 /* ----------------------- v4l helpers -------------------------- */
1405 /* supported frame palettes and depths */
1406 static inline int valid_mode(u16 palette
, u16 depth
)
1408 if ((palette
== VIDEO_PALETTE_YUV422
&& depth
== 16) ||
1409 (palette
== VIDEO_PALETTE_YUYV
&& depth
== 16))
1412 if (colorspace_conv
)
1413 return (palette
== VIDEO_PALETTE_GREY
&& depth
== 8) ||
1414 (palette
== VIDEO_PALETTE_RGB555
&& depth
== 16) ||
1415 (palette
== VIDEO_PALETTE_RGB565
&& depth
== 16) ||
1416 (palette
== VIDEO_PALETTE_RGB24
&& depth
== 24) ||
1417 (palette
== VIDEO_PALETTE_RGB32
&& depth
== 32) ||
1418 (palette
== VIDEO_PALETTE_UYVY
&& depth
== 16);
1423 static int match_videosize( int width
, int height
)
1425 /* return the best match, where 'best' is as always
1426 * the largest that is not bigger than what is requested. */
1427 if (width
>=352 && height
>=288)
1428 return VIDEOSIZE_352_288
; /* CIF */
1430 if (width
>=320 && height
>=240)
1431 return VIDEOSIZE_320_240
; /* SIF */
1433 if (width
>=288 && height
>=216)
1434 return VIDEOSIZE_288_216
;
1436 if (width
>=256 && height
>=192)
1437 return VIDEOSIZE_256_192
;
1439 if (width
>=224 && height
>=168)
1440 return VIDEOSIZE_224_168
;
1442 if (width
>=192 && height
>=144)
1443 return VIDEOSIZE_192_144
;
1445 if (width
>=176 && height
>=144)
1446 return VIDEOSIZE_176_144
; /* QCIF */
1448 if (width
>=160 && height
>=120)
1449 return VIDEOSIZE_160_120
; /* QSIF */
1451 if (width
>=128 && height
>=96)
1452 return VIDEOSIZE_128_96
;
1454 if (width
>=88 && height
>=72)
1455 return VIDEOSIZE_88_72
;
1457 if (width
>=64 && height
>=48)
1458 return VIDEOSIZE_64_48
;
1460 if (width
>=48 && height
>=48)
1461 return VIDEOSIZE_48_48
;
1466 /* these are the capture sizes we support */
1467 static void set_vw_size(struct cam_data
*cam
)
1469 /* the col/row/start/end values are the result of simple math */
1470 /* study the SetROI-command in cpia developers guide p 2-22 */
1471 /* streamStartLine is set to the recommended value in the cpia */
1472 /* developers guide p 3-37 */
1473 switch(cam
->video_size
) {
1475 cam
->vw
.width
= 352;
1476 cam
->vw
.height
= 288;
1477 cam
->params
.format
.videoSize
=VIDEOSIZE_CIF
;
1478 cam
->params
.roi
.colStart
=0;
1479 cam
->params
.roi
.rowStart
=0;
1480 cam
->params
.streamStartLine
= 120;
1483 cam
->vw
.width
= 320;
1484 cam
->vw
.height
= 240;
1485 cam
->params
.format
.videoSize
=VIDEOSIZE_CIF
;
1486 cam
->params
.roi
.colStart
=2;
1487 cam
->params
.roi
.rowStart
=6;
1488 cam
->params
.streamStartLine
= 120;
1490 case VIDEOSIZE_288_216
:
1491 cam
->vw
.width
= 288;
1492 cam
->vw
.height
= 216;
1493 cam
->params
.format
.videoSize
=VIDEOSIZE_CIF
;
1494 cam
->params
.roi
.colStart
=4;
1495 cam
->params
.roi
.rowStart
=9;
1496 cam
->params
.streamStartLine
= 120;
1498 case VIDEOSIZE_256_192
:
1499 cam
->vw
.width
= 256;
1500 cam
->vw
.height
= 192;
1501 cam
->params
.format
.videoSize
=VIDEOSIZE_CIF
;
1502 cam
->params
.roi
.colStart
=6;
1503 cam
->params
.roi
.rowStart
=12;
1504 cam
->params
.streamStartLine
= 120;
1506 case VIDEOSIZE_224_168
:
1507 cam
->vw
.width
= 224;
1508 cam
->vw
.height
= 168;
1509 cam
->params
.format
.videoSize
=VIDEOSIZE_CIF
;
1510 cam
->params
.roi
.colStart
=8;
1511 cam
->params
.roi
.rowStart
=15;
1512 cam
->params
.streamStartLine
= 120;
1514 case VIDEOSIZE_192_144
:
1515 cam
->vw
.width
= 192;
1516 cam
->vw
.height
= 144;
1517 cam
->params
.format
.videoSize
=VIDEOSIZE_CIF
;
1518 cam
->params
.roi
.colStart
=10;
1519 cam
->params
.roi
.rowStart
=18;
1520 cam
->params
.streamStartLine
= 120;
1522 case VIDEOSIZE_QCIF
:
1523 cam
->vw
.width
= 176;
1524 cam
->vw
.height
= 144;
1525 cam
->params
.format
.videoSize
=VIDEOSIZE_QCIF
;
1526 cam
->params
.roi
.colStart
=0;
1527 cam
->params
.roi
.rowStart
=0;
1528 cam
->params
.streamStartLine
= 60;
1530 case VIDEOSIZE_QSIF
:
1531 cam
->vw
.width
= 160;
1532 cam
->vw
.height
= 120;
1533 cam
->params
.format
.videoSize
=VIDEOSIZE_QCIF
;
1534 cam
->params
.roi
.colStart
=1;
1535 cam
->params
.roi
.rowStart
=3;
1536 cam
->params
.streamStartLine
= 60;
1538 case VIDEOSIZE_128_96
:
1539 cam
->vw
.width
= 128;
1540 cam
->vw
.height
= 96;
1541 cam
->params
.format
.videoSize
=VIDEOSIZE_QCIF
;
1542 cam
->params
.roi
.colStart
=3;
1543 cam
->params
.roi
.rowStart
=6;
1544 cam
->params
.streamStartLine
= 60;
1546 case VIDEOSIZE_88_72
:
1548 cam
->vw
.height
= 72;
1549 cam
->params
.format
.videoSize
=VIDEOSIZE_QCIF
;
1550 cam
->params
.roi
.colStart
=5;
1551 cam
->params
.roi
.rowStart
=9;
1552 cam
->params
.streamStartLine
= 60;
1554 case VIDEOSIZE_64_48
:
1556 cam
->vw
.height
= 48;
1557 cam
->params
.format
.videoSize
=VIDEOSIZE_QCIF
;
1558 cam
->params
.roi
.colStart
=7;
1559 cam
->params
.roi
.rowStart
=12;
1560 cam
->params
.streamStartLine
= 60;
1562 case VIDEOSIZE_48_48
:
1564 cam
->vw
.height
= 48;
1565 cam
->params
.format
.videoSize
=VIDEOSIZE_QCIF
;
1566 cam
->params
.roi
.colStart
=8;
1567 cam
->params
.roi
.rowStart
=6;
1568 cam
->params
.streamStartLine
= 60;
1571 LOG("bad videosize value: %d\n", cam
->video_size
);
1575 if(cam
->vc
.width
== 0)
1576 cam
->vc
.width
= cam
->vw
.width
;
1577 if(cam
->vc
.height
== 0)
1578 cam
->vc
.height
= cam
->vw
.height
;
1580 cam
->params
.roi
.colStart
+= cam
->vc
.x
>> 3;
1581 cam
->params
.roi
.colEnd
= cam
->params
.roi
.colStart
+
1582 (cam
->vc
.width
>> 3);
1583 cam
->params
.roi
.rowStart
+= cam
->vc
.y
>> 2;
1584 cam
->params
.roi
.rowEnd
= cam
->params
.roi
.rowStart
+
1585 (cam
->vc
.height
>> 2);
1590 static int allocate_frame_buf(struct cam_data
*cam
)
1594 cam
->frame_buf
= rvmalloc(FRAME_NUM
* CPIA_MAX_FRAME_SIZE
);
1595 if (!cam
->frame_buf
)
1598 for (i
= 0; i
< FRAME_NUM
; i
++)
1599 cam
->frame
[i
].data
= cam
->frame_buf
+ i
* CPIA_MAX_FRAME_SIZE
;
1604 static int free_frame_buf(struct cam_data
*cam
)
1608 rvfree(cam
->frame_buf
, FRAME_NUM
*CPIA_MAX_FRAME_SIZE
);
1609 cam
->frame_buf
= NULL
;
1610 for (i
=0; i
< FRAME_NUM
; i
++)
1611 cam
->frame
[i
].data
= NULL
;
1617 static inline void free_frames(struct cpia_frame frame
[FRAME_NUM
])
1621 for (i
=0; i
< FRAME_NUM
; i
++)
1622 frame
[i
].state
= FRAME_UNUSED
;
1626 /**********************************************************************
1630 **********************************************************************/
1631 /* send an arbitrary command to the camera */
1632 static int do_command(struct cam_data
*cam
, u16 command
, u8 a
, u8 b
, u8 c
, u8 d
)
1634 int retval
, datasize
;
1638 case CPIA_COMMAND_GetCPIAVersion
:
1639 case CPIA_COMMAND_GetPnPID
:
1640 case CPIA_COMMAND_GetCameraStatus
:
1641 case CPIA_COMMAND_GetVPVersion
:
1644 case CPIA_COMMAND_GetColourParams
:
1645 case CPIA_COMMAND_GetColourBalance
:
1646 case CPIA_COMMAND_GetExposure
:
1647 mutex_lock(&cam
->param_lock
);
1650 case CPIA_COMMAND_ReadMCPorts
:
1651 case CPIA_COMMAND_ReadVCRegs
:
1659 cmd
[0] = command
>>8;
1660 cmd
[1] = command
&0xff;
1668 retval
= cam
->ops
->transferCmd(cam
->lowlevel_data
, cmd
, data
);
1670 DBG("%x - failed, retval=%d\n", command
, retval
);
1671 if (command
== CPIA_COMMAND_GetColourParams
||
1672 command
== CPIA_COMMAND_GetColourBalance
||
1673 command
== CPIA_COMMAND_GetExposure
)
1674 mutex_unlock(&cam
->param_lock
);
1677 case CPIA_COMMAND_GetCPIAVersion
:
1678 cam
->params
.version
.firmwareVersion
= data
[0];
1679 cam
->params
.version
.firmwareRevision
= data
[1];
1680 cam
->params
.version
.vcVersion
= data
[2];
1681 cam
->params
.version
.vcRevision
= data
[3];
1683 case CPIA_COMMAND_GetPnPID
:
1684 cam
->params
.pnpID
.vendor
= data
[0]+(((u16
)data
[1])<<8);
1685 cam
->params
.pnpID
.product
= data
[2]+(((u16
)data
[3])<<8);
1686 cam
->params
.pnpID
.deviceRevision
=
1687 data
[4]+(((u16
)data
[5])<<8);
1689 case CPIA_COMMAND_GetCameraStatus
:
1690 cam
->params
.status
.systemState
= data
[0];
1691 cam
->params
.status
.grabState
= data
[1];
1692 cam
->params
.status
.streamState
= data
[2];
1693 cam
->params
.status
.fatalError
= data
[3];
1694 cam
->params
.status
.cmdError
= data
[4];
1695 cam
->params
.status
.debugFlags
= data
[5];
1696 cam
->params
.status
.vpStatus
= data
[6];
1697 cam
->params
.status
.errorCode
= data
[7];
1699 case CPIA_COMMAND_GetVPVersion
:
1700 cam
->params
.vpVersion
.vpVersion
= data
[0];
1701 cam
->params
.vpVersion
.vpRevision
= data
[1];
1702 cam
->params
.vpVersion
.cameraHeadID
=
1703 data
[2]+(((u16
)data
[3])<<8);
1705 case CPIA_COMMAND_GetColourParams
:
1706 cam
->params
.colourParams
.brightness
= data
[0];
1707 cam
->params
.colourParams
.contrast
= data
[1];
1708 cam
->params
.colourParams
.saturation
= data
[2];
1709 mutex_unlock(&cam
->param_lock
);
1711 case CPIA_COMMAND_GetColourBalance
:
1712 cam
->params
.colourBalance
.redGain
= data
[0];
1713 cam
->params
.colourBalance
.greenGain
= data
[1];
1714 cam
->params
.colourBalance
.blueGain
= data
[2];
1715 mutex_unlock(&cam
->param_lock
);
1717 case CPIA_COMMAND_GetExposure
:
1718 cam
->params
.exposure
.gain
= data
[0];
1719 cam
->params
.exposure
.fineExp
= data
[1];
1720 cam
->params
.exposure
.coarseExpLo
= data
[2];
1721 cam
->params
.exposure
.coarseExpHi
= data
[3];
1722 cam
->params
.exposure
.redComp
= data
[4];
1723 cam
->params
.exposure
.green1Comp
= data
[5];
1724 cam
->params
.exposure
.green2Comp
= data
[6];
1725 cam
->params
.exposure
.blueComp
= data
[7];
1726 mutex_unlock(&cam
->param_lock
);
1729 case CPIA_COMMAND_ReadMCPorts
:
1730 if (!cam
->params
.qx3
.qx3_detected
)
1732 /* test button press */
1733 cam
->params
.qx3
.button
= ((data
[1] & 0x02) == 0);
1734 if (cam
->params
.qx3
.button
) {
1735 /* button pressed - unlock the latch */
1736 do_command(cam
,CPIA_COMMAND_WriteMCPort
,3,0xDF,0xDF,0);
1737 do_command(cam
,CPIA_COMMAND_WriteMCPort
,3,0xFF,0xFF,0);
1740 /* test whether microscope is cradled */
1741 cam
->params
.qx3
.cradled
= ((data
[2] & 0x40) == 0);
1751 /* send a command to the camera with an additional data transaction */
1752 static int do_command_extended(struct cam_data
*cam
, u16 command
,
1753 u8 a
, u8 b
, u8 c
, u8 d
,
1754 u8 e
, u8 f
, u8 g
, u8 h
,
1755 u8 i
, u8 j
, u8 k
, u8 l
)
1760 cmd
[0] = command
>>8;
1761 cmd
[1] = command
&0xff;
1777 retval
= cam
->ops
->transferCmd(cam
->lowlevel_data
, cmd
, data
);
1779 DBG("%x - failed\n", command
);
1784 /**********************************************************************
1786 * Colorspace conversion
1788 **********************************************************************/
1789 #define LIMIT(x) ((((x)>0xffffff)?0xff0000:(((x)<=0xffff)?0:(x)&0xff0000))>>16)
1791 static int convert420(unsigned char *yuv
, unsigned char *rgb
, int out_fmt
,
1792 int linesize
, int mmap_kludge
)
1794 int y
, u
, v
, r
, g
, b
, y1
;
1796 /* Odd lines use the same u and v as the previous line.
1797 * Because of compression, it is necessary to get this
1798 * information from the decoded image. */
1800 case VIDEO_PALETTE_RGB555
:
1801 y
= (*yuv
++ - 16) * 76310;
1802 y1
= (*yuv
- 16) * 76310;
1803 r
= ((*(rgb
+1-linesize
)) & 0x7c) << 1;
1804 g
= ((*(rgb
-linesize
)) & 0xe0) >> 4 |
1805 ((*(rgb
+1-linesize
)) & 0x03) << 6;
1806 b
= ((*(rgb
-linesize
)) & 0x1f) << 3;
1807 u
= (-53294 * r
- 104635 * g
+ 157929 * b
) / 5756495;
1808 v
= (157968 * r
- 132278 * g
- 25690 * b
) / 5366159;
1810 g
= -25690 * u
- 53294 * v
;
1812 *rgb
++ = ((LIMIT(g
+y
) & 0xf8) << 2) | (LIMIT(b
+y
) >> 3);
1813 *rgb
++ = ((LIMIT(r
+y
) & 0xf8) >> 1) | (LIMIT(g
+y
) >> 6);
1814 *rgb
++ = ((LIMIT(g
+y1
) & 0xf8) << 2) | (LIMIT(b
+y1
) >> 3);
1815 *rgb
= ((LIMIT(r
+y1
) & 0xf8) >> 1) | (LIMIT(g
+y1
) >> 6);
1817 case VIDEO_PALETTE_RGB565
:
1818 y
= (*yuv
++ - 16) * 76310;
1819 y1
= (*yuv
- 16) * 76310;
1820 r
= (*(rgb
+1-linesize
)) & 0xf8;
1821 g
= ((*(rgb
-linesize
)) & 0xe0) >> 3 |
1822 ((*(rgb
+1-linesize
)) & 0x07) << 5;
1823 b
= ((*(rgb
-linesize
)) & 0x1f) << 3;
1824 u
= (-53294 * r
- 104635 * g
+ 157929 * b
) / 5756495;
1825 v
= (157968 * r
- 132278 * g
- 25690 * b
) / 5366159;
1827 g
= -25690 * u
- 53294 * v
;
1829 *rgb
++ = ((LIMIT(g
+y
) & 0xfc) << 3) | (LIMIT(b
+y
) >> 3);
1830 *rgb
++ = (LIMIT(r
+y
) & 0xf8) | (LIMIT(g
+y
) >> 5);
1831 *rgb
++ = ((LIMIT(g
+y1
) & 0xfc) << 3) | (LIMIT(b
+y1
) >> 3);
1832 *rgb
= (LIMIT(r
+y1
) & 0xf8) | (LIMIT(g
+y1
) >> 5);
1835 case VIDEO_PALETTE_RGB24
:
1836 case VIDEO_PALETTE_RGB32
:
1837 y
= (*yuv
++ - 16) * 76310;
1838 y1
= (*yuv
- 16) * 76310;
1840 r
= *(rgb
+2-linesize
);
1841 g
= *(rgb
+1-linesize
);
1842 b
= *(rgb
-linesize
);
1844 r
= *(rgb
-linesize
);
1845 g
= *(rgb
+1-linesize
);
1846 b
= *(rgb
+2-linesize
);
1848 u
= (-53294 * r
- 104635 * g
+ 157929 * b
) / 5756495;
1849 v
= (157968 * r
- 132278 * g
- 25690 * b
) / 5366159;
1851 g
= -25690 * u
+ -53294 * v
;
1854 *rgb
++ = LIMIT(b
+y
);
1855 *rgb
++ = LIMIT(g
+y
);
1856 *rgb
++ = LIMIT(r
+y
);
1857 if(out_fmt
== VIDEO_PALETTE_RGB32
)
1859 *rgb
++ = LIMIT(b
+y1
);
1860 *rgb
++ = LIMIT(g
+y1
);
1863 *rgb
++ = LIMIT(r
+y
);
1864 *rgb
++ = LIMIT(g
+y
);
1865 *rgb
++ = LIMIT(b
+y
);
1866 if(out_fmt
== VIDEO_PALETTE_RGB32
)
1868 *rgb
++ = LIMIT(r
+y1
);
1869 *rgb
++ = LIMIT(g
+y1
);
1872 if(out_fmt
== VIDEO_PALETTE_RGB32
)
1875 case VIDEO_PALETTE_YUV422
:
1876 case VIDEO_PALETTE_YUYV
:
1878 u
= *(rgb
+1-linesize
);
1880 v
= *(rgb
+3-linesize
);
1886 case VIDEO_PALETTE_UYVY
:
1887 u
= *(rgb
-linesize
);
1889 v
= *(rgb
+2-linesize
);
1896 case VIDEO_PALETTE_GREY
:
1901 DBG("Empty: %d\n", out_fmt
);
1907 static int yuvconvert(unsigned char *yuv
, unsigned char *rgb
, int out_fmt
,
1908 int in_uyvy
, int mmap_kludge
)
1910 int y
, u
, v
, r
, g
, b
, y1
;
1913 case VIDEO_PALETTE_RGB555
:
1914 case VIDEO_PALETTE_RGB565
:
1915 case VIDEO_PALETTE_RGB24
:
1916 case VIDEO_PALETTE_RGB32
:
1919 y
= (*yuv
++ - 16) * 76310;
1921 y1
= (*yuv
- 16) * 76310;
1923 y
= (*yuv
++ - 16) * 76310;
1925 y1
= (*yuv
++ - 16) * 76310;
1929 g
= -25690 * u
+ -53294 * v
;
1937 /* Just to avoid compiler warnings */
1944 case VIDEO_PALETTE_RGB555
:
1945 *rgb
++ = ((LIMIT(g
+y
) & 0xf8) << 2) | (LIMIT(b
+y
) >> 3);
1946 *rgb
++ = ((LIMIT(r
+y
) & 0xf8) >> 1) | (LIMIT(g
+y
) >> 6);
1947 *rgb
++ = ((LIMIT(g
+y1
) & 0xf8) << 2) | (LIMIT(b
+y1
) >> 3);
1948 *rgb
= ((LIMIT(r
+y1
) & 0xf8) >> 1) | (LIMIT(g
+y1
) >> 6);
1950 case VIDEO_PALETTE_RGB565
:
1951 *rgb
++ = ((LIMIT(g
+y
) & 0xfc) << 3) | (LIMIT(b
+y
) >> 3);
1952 *rgb
++ = (LIMIT(r
+y
) & 0xf8) | (LIMIT(g
+y
) >> 5);
1953 *rgb
++ = ((LIMIT(g
+y1
) & 0xfc) << 3) | (LIMIT(b
+y1
) >> 3);
1954 *rgb
= (LIMIT(r
+y1
) & 0xf8) | (LIMIT(g
+y1
) >> 5);
1956 case VIDEO_PALETTE_RGB24
:
1958 *rgb
++ = LIMIT(b
+y
);
1959 *rgb
++ = LIMIT(g
+y
);
1960 *rgb
++ = LIMIT(r
+y
);
1961 *rgb
++ = LIMIT(b
+y1
);
1962 *rgb
++ = LIMIT(g
+y1
);
1965 *rgb
++ = LIMIT(r
+y
);
1966 *rgb
++ = LIMIT(g
+y
);
1967 *rgb
++ = LIMIT(b
+y
);
1968 *rgb
++ = LIMIT(r
+y1
);
1969 *rgb
++ = LIMIT(g
+y1
);
1973 case VIDEO_PALETTE_RGB32
:
1975 *rgb
++ = LIMIT(b
+y
);
1976 *rgb
++ = LIMIT(g
+y
);
1977 *rgb
++ = LIMIT(r
+y
);
1979 *rgb
++ = LIMIT(b
+y1
);
1980 *rgb
++ = LIMIT(g
+y1
);
1983 *rgb
++ = LIMIT(r
+y
);
1984 *rgb
++ = LIMIT(g
+y
);
1985 *rgb
++ = LIMIT(b
+y
);
1987 *rgb
++ = LIMIT(r
+y1
);
1988 *rgb
++ = LIMIT(g
+y1
);
1992 case VIDEO_PALETTE_GREY
:
1996 case VIDEO_PALETTE_YUV422
:
1997 case VIDEO_PALETTE_YUYV
:
2003 case VIDEO_PALETTE_UYVY
:
2010 DBG("Empty: %d\n", out_fmt
);
2015 static int skipcount(int count
, int fmt
)
2018 case VIDEO_PALETTE_GREY
:
2020 case VIDEO_PALETTE_RGB555
:
2021 case VIDEO_PALETTE_RGB565
:
2022 case VIDEO_PALETTE_YUV422
:
2023 case VIDEO_PALETTE_YUYV
:
2024 case VIDEO_PALETTE_UYVY
:
2026 case VIDEO_PALETTE_RGB24
:
2028 case VIDEO_PALETTE_RGB32
:
2035 static int parse_picture(struct cam_data
*cam
, int size
)
2037 u8
*obuf
, *ibuf
, *end_obuf
;
2038 int ll
, in_uyvy
, compressed
, decimation
, even_line
, origsize
, out_fmt
;
2039 int rows
, cols
, linesize
, subsample_422
;
2041 /* make sure params don't change while we are decoding */
2042 mutex_lock(&cam
->param_lock
);
2044 obuf
= cam
->decompressed_frame
.data
;
2045 end_obuf
= obuf
+CPIA_MAX_FRAME_SIZE
;
2046 ibuf
= cam
->raw_image
;
2048 out_fmt
= cam
->vp
.palette
;
2050 if ((ibuf
[0] != MAGIC_0
) || (ibuf
[1] != MAGIC_1
)) {
2051 LOG("header not found\n");
2052 mutex_unlock(&cam
->param_lock
);
2056 if ((ibuf
[16] != VIDEOSIZE_QCIF
) && (ibuf
[16] != VIDEOSIZE_CIF
)) {
2057 LOG("wrong video size\n");
2058 mutex_unlock(&cam
->param_lock
);
2062 if (ibuf
[17] != SUBSAMPLE_420
&& ibuf
[17] != SUBSAMPLE_422
) {
2063 LOG("illegal subtype %d\n",ibuf
[17]);
2064 mutex_unlock(&cam
->param_lock
);
2067 subsample_422
= ibuf
[17] == SUBSAMPLE_422
;
2069 if (ibuf
[18] != YUVORDER_YUYV
&& ibuf
[18] != YUVORDER_UYVY
) {
2070 LOG("illegal yuvorder %d\n",ibuf
[18]);
2071 mutex_unlock(&cam
->param_lock
);
2074 in_uyvy
= ibuf
[18] == YUVORDER_UYVY
;
2076 if ((ibuf
[24] != cam
->params
.roi
.colStart
) ||
2077 (ibuf
[25] != cam
->params
.roi
.colEnd
) ||
2078 (ibuf
[26] != cam
->params
.roi
.rowStart
) ||
2079 (ibuf
[27] != cam
->params
.roi
.rowEnd
)) {
2080 LOG("ROI mismatch\n");
2081 mutex_unlock(&cam
->param_lock
);
2084 cols
= 8*(ibuf
[25] - ibuf
[24]);
2085 rows
= 4*(ibuf
[27] - ibuf
[26]);
2088 if ((ibuf
[28] != NOT_COMPRESSED
) && (ibuf
[28] != COMPRESSED
)) {
2089 LOG("illegal compression %d\n",ibuf
[28]);
2090 mutex_unlock(&cam
->param_lock
);
2093 compressed
= (ibuf
[28] == COMPRESSED
);
2095 if (ibuf
[29] != NO_DECIMATION
&& ibuf
[29] != DECIMATION_ENAB
) {
2096 LOG("illegal decimation %d\n",ibuf
[29]);
2097 mutex_unlock(&cam
->param_lock
);
2100 decimation
= (ibuf
[29] == DECIMATION_ENAB
);
2102 cam
->params
.yuvThreshold
.yThreshold
= ibuf
[30];
2103 cam
->params
.yuvThreshold
.uvThreshold
= ibuf
[31];
2104 cam
->params
.status
.systemState
= ibuf
[32];
2105 cam
->params
.status
.grabState
= ibuf
[33];
2106 cam
->params
.status
.streamState
= ibuf
[34];
2107 cam
->params
.status
.fatalError
= ibuf
[35];
2108 cam
->params
.status
.cmdError
= ibuf
[36];
2109 cam
->params
.status
.debugFlags
= ibuf
[37];
2110 cam
->params
.status
.vpStatus
= ibuf
[38];
2111 cam
->params
.status
.errorCode
= ibuf
[39];
2112 cam
->fps
= ibuf
[41];
2113 mutex_unlock(&cam
->param_lock
);
2115 linesize
= skipcount(cols
, out_fmt
);
2116 ibuf
+= FRAME_HEADER_SIZE
;
2117 size
-= FRAME_HEADER_SIZE
;
2118 ll
= ibuf
[0] | (ibuf
[1] << 8);
2125 LOG("Insufficient data in buffer\n");
2130 if (!compressed
|| (compressed
&& !(*ibuf
& 1))) {
2131 if(subsample_422
|| even_line
) {
2132 obuf
+= yuvconvert(ibuf
, obuf
, out_fmt
,
2133 in_uyvy
, cam
->mmap_kludge
);
2137 /* SUBSAMPLE_420 on an odd line */
2138 obuf
+= convert420(ibuf
, obuf
,
2145 /*skip compressed interval from previous frame*/
2146 obuf
+= skipcount(*ibuf
>> 1, out_fmt
);
2147 if (obuf
> end_obuf
) {
2148 LOG("Insufficient buffer size\n");
2157 DBG("EOL not found giving up after %d/%d"
2158 " bytes\n", origsize
-size
, origsize
);
2162 ++ibuf
; /* skip over EOL */
2164 if ((size
> 3) && (ibuf
[0] == EOI
) && (ibuf
[1] == EOI
) &&
2165 (ibuf
[2] == EOI
) && (ibuf
[3] == EOI
)) {
2171 /* skip the odd lines for now */
2176 ll
= ibuf
[0] | (ibuf
[1] << 8);
2177 ibuf
+= 2; /* skip over line length */
2180 even_line
= !even_line
;
2182 LOG("line length was not 1 but %d after %d/%d bytes\n",
2183 ll
, origsize
-size
, origsize
);
2189 /* interpolate odd rows */
2192 prev
= cam
->decompressed_frame
.data
;
2193 obuf
= prev
+linesize
;
2194 next
= obuf
+linesize
;
2195 for(i
=1; i
<rows
-1; i
+=2) {
2196 for(j
=0; j
<linesize
; ++j
) {
2197 *obuf
++ = ((int)*prev
++ + *next
++) / 2;
2203 /* last row is odd, just copy previous row */
2204 memcpy(obuf
, prev
, linesize
);
2207 cam
->decompressed_frame
.count
= obuf
-cam
->decompressed_frame
.data
;
2209 return cam
->decompressed_frame
.count
;
2212 /* InitStreamCap wrapper to select correct start line */
2213 static inline int init_stream_cap(struct cam_data
*cam
)
2215 return do_command(cam
, CPIA_COMMAND_InitStreamCap
,
2216 0, cam
->params
.streamStartLine
, 0, 0);
2220 /* find_over_exposure
2221 * Finds a suitable value of OverExposure for use with SetFlickerCtrl
2222 * Some calculation is required because this value changes with the brightness
2223 * set with SetColourParameters
2225 * Parameters: Brightness - last brightness value set with SetColourParameters
2227 * Returns: OverExposure value to use with SetFlickerCtrl
2229 #define FLICKER_MAX_EXPOSURE 250
2230 #define FLICKER_ALLOWABLE_OVER_EXPOSURE 146
2231 #define FLICKER_BRIGHTNESS_CONSTANT 59
2232 static int find_over_exposure(int brightness
)
2234 int MaxAllowableOverExposure
, OverExposure
;
2236 MaxAllowableOverExposure
= FLICKER_MAX_EXPOSURE
- brightness
-
2237 FLICKER_BRIGHTNESS_CONSTANT
;
2239 if (MaxAllowableOverExposure
< FLICKER_ALLOWABLE_OVER_EXPOSURE
) {
2240 OverExposure
= MaxAllowableOverExposure
;
2242 OverExposure
= FLICKER_ALLOWABLE_OVER_EXPOSURE
;
2245 return OverExposure
;
2247 #undef FLICKER_MAX_EXPOSURE
2248 #undef FLICKER_ALLOWABLE_OVER_EXPOSURE
2249 #undef FLICKER_BRIGHTNESS_CONSTANT
2251 /* update various camera modes and settings */
2252 static void dispatch_commands(struct cam_data
*cam
)
2254 mutex_lock(&cam
->param_lock
);
2255 if (cam
->cmd_queue
==COMMAND_NONE
) {
2256 mutex_unlock(&cam
->param_lock
);
2259 DEB_BYTE(cam
->cmd_queue
);
2260 DEB_BYTE(cam
->cmd_queue
>>8);
2261 if (cam
->cmd_queue
& COMMAND_SETFORMAT
) {
2262 do_command(cam
, CPIA_COMMAND_SetFormat
,
2263 cam
->params
.format
.videoSize
,
2264 cam
->params
.format
.subSample
,
2265 cam
->params
.format
.yuvOrder
, 0);
2266 do_command(cam
, CPIA_COMMAND_SetROI
,
2267 cam
->params
.roi
.colStart
, cam
->params
.roi
.colEnd
,
2268 cam
->params
.roi
.rowStart
, cam
->params
.roi
.rowEnd
);
2269 cam
->first_frame
= 1;
2272 if (cam
->cmd_queue
& COMMAND_SETCOLOURPARAMS
)
2273 do_command(cam
, CPIA_COMMAND_SetColourParams
,
2274 cam
->params
.colourParams
.brightness
,
2275 cam
->params
.colourParams
.contrast
,
2276 cam
->params
.colourParams
.saturation
, 0);
2278 if (cam
->cmd_queue
& COMMAND_SETAPCOR
)
2279 do_command(cam
, CPIA_COMMAND_SetApcor
,
2280 cam
->params
.apcor
.gain1
,
2281 cam
->params
.apcor
.gain2
,
2282 cam
->params
.apcor
.gain4
,
2283 cam
->params
.apcor
.gain8
);
2285 if (cam
->cmd_queue
& COMMAND_SETVLOFFSET
)
2286 do_command(cam
, CPIA_COMMAND_SetVLOffset
,
2287 cam
->params
.vlOffset
.gain1
,
2288 cam
->params
.vlOffset
.gain2
,
2289 cam
->params
.vlOffset
.gain4
,
2290 cam
->params
.vlOffset
.gain8
);
2292 if (cam
->cmd_queue
& COMMAND_SETEXPOSURE
) {
2293 do_command_extended(cam
, CPIA_COMMAND_SetExposure
,
2294 cam
->params
.exposure
.gainMode
,
2296 cam
->params
.exposure
.compMode
,
2297 cam
->params
.exposure
.centreWeight
,
2298 cam
->params
.exposure
.gain
,
2299 cam
->params
.exposure
.fineExp
,
2300 cam
->params
.exposure
.coarseExpLo
,
2301 cam
->params
.exposure
.coarseExpHi
,
2302 cam
->params
.exposure
.redComp
,
2303 cam
->params
.exposure
.green1Comp
,
2304 cam
->params
.exposure
.green2Comp
,
2305 cam
->params
.exposure
.blueComp
);
2306 if(cam
->params
.exposure
.expMode
!= 1) {
2307 do_command_extended(cam
, CPIA_COMMAND_SetExposure
,
2309 cam
->params
.exposure
.expMode
,
2311 cam
->params
.exposure
.gain
,
2312 cam
->params
.exposure
.fineExp
,
2313 cam
->params
.exposure
.coarseExpLo
,
2314 cam
->params
.exposure
.coarseExpHi
,
2319 if (cam
->cmd_queue
& COMMAND_SETCOLOURBALANCE
) {
2320 if (cam
->params
.colourBalance
.balanceMode
== 1) {
2321 do_command(cam
, CPIA_COMMAND_SetColourBalance
,
2323 cam
->params
.colourBalance
.redGain
,
2324 cam
->params
.colourBalance
.greenGain
,
2325 cam
->params
.colourBalance
.blueGain
);
2326 do_command(cam
, CPIA_COMMAND_SetColourBalance
,
2329 if (cam
->params
.colourBalance
.balanceMode
== 2) {
2330 do_command(cam
, CPIA_COMMAND_SetColourBalance
,
2333 if (cam
->params
.colourBalance
.balanceMode
== 3) {
2334 do_command(cam
, CPIA_COMMAND_SetColourBalance
,
2339 if (cam
->cmd_queue
& COMMAND_SETCOMPRESSIONTARGET
)
2340 do_command(cam
, CPIA_COMMAND_SetCompressionTarget
,
2341 cam
->params
.compressionTarget
.frTargeting
,
2342 cam
->params
.compressionTarget
.targetFR
,
2343 cam
->params
.compressionTarget
.targetQ
, 0);
2345 if (cam
->cmd_queue
& COMMAND_SETYUVTHRESH
)
2346 do_command(cam
, CPIA_COMMAND_SetYUVThresh
,
2347 cam
->params
.yuvThreshold
.yThreshold
,
2348 cam
->params
.yuvThreshold
.uvThreshold
, 0, 0);
2350 if (cam
->cmd_queue
& COMMAND_SETCOMPRESSIONPARAMS
)
2351 do_command_extended(cam
, CPIA_COMMAND_SetCompressionParams
,
2353 cam
->params
.compressionParams
.hysteresis
,
2354 cam
->params
.compressionParams
.threshMax
,
2355 cam
->params
.compressionParams
.smallStep
,
2356 cam
->params
.compressionParams
.largeStep
,
2357 cam
->params
.compressionParams
.decimationHysteresis
,
2358 cam
->params
.compressionParams
.frDiffStepThresh
,
2359 cam
->params
.compressionParams
.qDiffStepThresh
,
2360 cam
->params
.compressionParams
.decimationThreshMod
);
2362 if (cam
->cmd_queue
& COMMAND_SETCOMPRESSION
)
2363 do_command(cam
, CPIA_COMMAND_SetCompression
,
2364 cam
->params
.compression
.mode
,
2365 cam
->params
.compression
.decimation
, 0, 0);
2367 if (cam
->cmd_queue
& COMMAND_SETSENSORFPS
)
2368 do_command(cam
, CPIA_COMMAND_SetSensorFPS
,
2369 cam
->params
.sensorFps
.divisor
,
2370 cam
->params
.sensorFps
.baserate
, 0, 0);
2372 if (cam
->cmd_queue
& COMMAND_SETFLICKERCTRL
)
2373 do_command(cam
, CPIA_COMMAND_SetFlickerCtrl
,
2374 cam
->params
.flickerControl
.flickerMode
,
2375 cam
->params
.flickerControl
.coarseJump
,
2376 abs(cam
->params
.flickerControl
.allowableOverExposure
),
2379 if (cam
->cmd_queue
& COMMAND_SETECPTIMING
)
2380 do_command(cam
, CPIA_COMMAND_SetECPTiming
,
2381 cam
->params
.ecpTiming
, 0, 0, 0);
2383 if (cam
->cmd_queue
& COMMAND_PAUSE
)
2384 do_command(cam
, CPIA_COMMAND_EndStreamCap
, 0, 0, 0, 0);
2386 if (cam
->cmd_queue
& COMMAND_RESUME
)
2387 init_stream_cap(cam
);
2389 if (cam
->cmd_queue
& COMMAND_SETLIGHTS
&& cam
->params
.qx3
.qx3_detected
)
2391 int p1
= (cam
->params
.qx3
.bottomlight
== 0) << 1;
2392 int p2
= (cam
->params
.qx3
.toplight
== 0) << 3;
2393 do_command(cam
, CPIA_COMMAND_WriteVCReg
, 0x90, 0x8F, 0x50, 0);
2394 do_command(cam
, CPIA_COMMAND_WriteMCPort
, 2, 0, (p1
|p2
|0xE0), 0);
2397 cam
->cmd_queue
= COMMAND_NONE
;
2398 mutex_unlock(&cam
->param_lock
);
2404 static void set_flicker(struct cam_params
*params
, volatile u32
*command_flags
,
2407 /* Everything in here is from the Windows driver */
2408 #define FIRMWARE_VERSION(x,y) (params->version.firmwareVersion == (x) && \
2409 params->version.firmwareRevision == (y))
2410 /* define for compgain calculation */
2412 #define COMPGAIN(base, curexp, newexp) \
2413 (u8) ((((float) base - 128.0) * ((float) curexp / (float) newexp)) + 128.5)
2414 #define EXP_FROM_COMP(basecomp, curcomp, curexp) \
2415 (u16)((float)curexp * (float)(u8)(curcomp + 128) / (float)(u8)(basecomp - 128))
2417 /* equivalent functions without floating point math */
2418 #define COMPGAIN(base, curexp, newexp) \
2419 (u8)(128 + (((u32)(2*(base-128)*curexp + newexp)) / (2* newexp)) )
2420 #define EXP_FROM_COMP(basecomp, curcomp, curexp) \
2421 (u16)(((u32)(curexp * (u8)(curcomp + 128)) / (u8)(basecomp - 128)))
2425 int currentexp
= params
->exposure
.coarseExpLo
+
2426 params
->exposure
.coarseExpHi
*256;
2429 int cj
= params
->flickerControl
.coarseJump
;
2430 params
->flickerControl
.flickerMode
= 1;
2431 params
->flickerControl
.disabled
= 0;
2432 if(params
->exposure
.expMode
!= 2)
2433 *command_flags
|= COMMAND_SETEXPOSURE
;
2434 params
->exposure
.expMode
= 2;
2435 currentexp
= currentexp
<< params
->exposure
.gain
;
2436 params
->exposure
.gain
= 0;
2437 /* round down current exposure to nearest value */
2438 startexp
= (currentexp
+ ROUND_UP_EXP_FOR_FLICKER
) / cj
;
2441 startexp
= (startexp
* cj
) - 1;
2442 if(FIRMWARE_VERSION(1,2))
2443 while(startexp
> MAX_EXP_102
)
2446 while(startexp
> MAX_EXP
)
2448 params
->exposure
.coarseExpLo
= startexp
& 0xff;
2449 params
->exposure
.coarseExpHi
= startexp
>> 8;
2450 if (currentexp
> startexp
) {
2451 if (currentexp
> (2 * startexp
))
2452 currentexp
= 2 * startexp
;
2453 params
->exposure
.redComp
= COMPGAIN (COMP_RED
, currentexp
, startexp
);
2454 params
->exposure
.green1Comp
= COMPGAIN (COMP_GREEN1
, currentexp
, startexp
);
2455 params
->exposure
.green2Comp
= COMPGAIN (COMP_GREEN2
, currentexp
, startexp
);
2456 params
->exposure
.blueComp
= COMPGAIN (COMP_BLUE
, currentexp
, startexp
);
2458 params
->exposure
.redComp
= COMP_RED
;
2459 params
->exposure
.green1Comp
= COMP_GREEN1
;
2460 params
->exposure
.green2Comp
= COMP_GREEN2
;
2461 params
->exposure
.blueComp
= COMP_BLUE
;
2463 if(FIRMWARE_VERSION(1,2))
2464 params
->exposure
.compMode
= 0;
2466 params
->exposure
.compMode
= 1;
2468 params
->apcor
.gain1
= 0x18;
2469 params
->apcor
.gain2
= 0x18;
2470 params
->apcor
.gain4
= 0x16;
2471 params
->apcor
.gain8
= 0x14;
2472 *command_flags
|= COMMAND_SETAPCOR
;
2474 params
->flickerControl
.flickerMode
= 0;
2475 params
->flickerControl
.disabled
= 1;
2476 /* Coarse = average of equivalent coarse for each comp channel */
2477 startexp
= EXP_FROM_COMP(COMP_RED
, params
->exposure
.redComp
, currentexp
);
2478 startexp
+= EXP_FROM_COMP(COMP_GREEN1
, params
->exposure
.green1Comp
, currentexp
);
2479 startexp
+= EXP_FROM_COMP(COMP_GREEN2
, params
->exposure
.green2Comp
, currentexp
);
2480 startexp
+= EXP_FROM_COMP(COMP_BLUE
, params
->exposure
.blueComp
, currentexp
);
2481 startexp
= startexp
>> 2;
2482 while(startexp
> MAX_EXP
&&
2483 params
->exposure
.gain
< params
->exposure
.gainMode
-1) {
2484 startexp
= startexp
>> 1;
2485 ++params
->exposure
.gain
;
2487 if(FIRMWARE_VERSION(1,2) && startexp
> MAX_EXP_102
)
2488 startexp
= MAX_EXP_102
;
2489 if(startexp
> MAX_EXP
)
2491 params
->exposure
.coarseExpLo
= startexp
&0xff;
2492 params
->exposure
.coarseExpHi
= startexp
>> 8;
2493 params
->exposure
.redComp
= COMP_RED
;
2494 params
->exposure
.green1Comp
= COMP_GREEN1
;
2495 params
->exposure
.green2Comp
= COMP_GREEN2
;
2496 params
->exposure
.blueComp
= COMP_BLUE
;
2497 params
->exposure
.compMode
= 1;
2498 *command_flags
|= COMMAND_SETEXPOSURE
;
2499 params
->apcor
.gain1
= 0x18;
2500 params
->apcor
.gain2
= 0x16;
2501 params
->apcor
.gain4
= 0x24;
2502 params
->apcor
.gain8
= 0x34;
2503 *command_flags
|= COMMAND_SETAPCOR
;
2505 params
->vlOffset
.gain1
= 20;
2506 params
->vlOffset
.gain2
= 24;
2507 params
->vlOffset
.gain4
= 26;
2508 params
->vlOffset
.gain8
= 26;
2509 *command_flags
|= COMMAND_SETVLOFFSET
;
2510 #undef FIRMWARE_VERSION
2511 #undef EXP_FROM_COMP
2515 #define FIRMWARE_VERSION(x,y) (cam->params.version.firmwareVersion == (x) && \
2516 cam->params.version.firmwareRevision == (y))
2517 /* monitor the exposure and adjust the sensor frame rate if needed */
2518 static void monitor_exposure(struct cam_data
*cam
)
2520 u8 exp_acc
, bcomp
, gain
, coarseL
, cmd
[8], data
[8];
2521 int retval
, light_exp
, dark_exp
, very_dark_exp
;
2522 int old_exposure
, new_exposure
, framerate
;
2524 /* get necessary stats and register settings from camera */
2525 /* do_command can't handle this, so do it ourselves */
2526 cmd
[0] = CPIA_COMMAND_ReadVPRegs
>>8;
2527 cmd
[1] = CPIA_COMMAND_ReadVPRegs
&0xff;
2534 retval
= cam
->ops
->transferCmd(cam
->lowlevel_data
, cmd
, data
);
2536 LOG("ReadVPRegs(30,4,9,8) - failed, retval=%d\n",
2545 mutex_lock(&cam
->param_lock
);
2546 light_exp
= cam
->params
.colourParams
.brightness
+
2547 TC
- 50 + EXP_ACC_LIGHT
;
2550 dark_exp
= cam
->params
.colourParams
.brightness
+
2551 TC
- 50 - EXP_ACC_DARK
;
2554 very_dark_exp
= dark_exp
/2;
2556 old_exposure
= cam
->params
.exposure
.coarseExpHi
* 256 +
2557 cam
->params
.exposure
.coarseExpLo
;
2559 if(!cam
->params
.flickerControl
.disabled
) {
2560 /* Flicker control on */
2561 int max_comp
= FIRMWARE_VERSION(1,2) ? MAX_COMP
: HIGH_COMP_102
;
2562 bcomp
+= 128; /* decode */
2563 if(bcomp
>= max_comp
&& exp_acc
< dark_exp
) {
2565 if(exp_acc
< very_dark_exp
) {
2567 if(cam
->exposure_status
== EXPOSURE_VERY_DARK
)
2568 ++cam
->exposure_count
;
2570 cam
->exposure_status
= EXPOSURE_VERY_DARK
;
2571 cam
->exposure_count
= 1;
2575 if(cam
->exposure_status
== EXPOSURE_DARK
)
2576 ++cam
->exposure_count
;
2578 cam
->exposure_status
= EXPOSURE_DARK
;
2579 cam
->exposure_count
= 1;
2582 } else if(old_exposure
<= LOW_EXP
|| exp_acc
> light_exp
) {
2584 if(old_exposure
<= VERY_LOW_EXP
) {
2586 if(cam
->exposure_status
== EXPOSURE_VERY_LIGHT
)
2587 ++cam
->exposure_count
;
2589 cam
->exposure_status
= EXPOSURE_VERY_LIGHT
;
2590 cam
->exposure_count
= 1;
2594 if(cam
->exposure_status
== EXPOSURE_LIGHT
)
2595 ++cam
->exposure_count
;
2597 cam
->exposure_status
= EXPOSURE_LIGHT
;
2598 cam
->exposure_count
= 1;
2602 /* not dark or light */
2603 cam
->exposure_status
= EXPOSURE_NORMAL
;
2606 /* Flicker control off */
2607 if(old_exposure
>= MAX_EXP
&& exp_acc
< dark_exp
) {
2609 if(exp_acc
< very_dark_exp
) {
2611 if(cam
->exposure_status
== EXPOSURE_VERY_DARK
)
2612 ++cam
->exposure_count
;
2614 cam
->exposure_status
= EXPOSURE_VERY_DARK
;
2615 cam
->exposure_count
= 1;
2619 if(cam
->exposure_status
== EXPOSURE_DARK
)
2620 ++cam
->exposure_count
;
2622 cam
->exposure_status
= EXPOSURE_DARK
;
2623 cam
->exposure_count
= 1;
2626 } else if(old_exposure
<= LOW_EXP
|| exp_acc
> light_exp
) {
2628 if(old_exposure
<= VERY_LOW_EXP
) {
2630 if(cam
->exposure_status
== EXPOSURE_VERY_LIGHT
)
2631 ++cam
->exposure_count
;
2633 cam
->exposure_status
= EXPOSURE_VERY_LIGHT
;
2634 cam
->exposure_count
= 1;
2638 if(cam
->exposure_status
== EXPOSURE_LIGHT
)
2639 ++cam
->exposure_count
;
2641 cam
->exposure_status
= EXPOSURE_LIGHT
;
2642 cam
->exposure_count
= 1;
2646 /* not dark or light */
2647 cam
->exposure_status
= EXPOSURE_NORMAL
;
2651 framerate
= cam
->fps
;
2652 if(framerate
> 30 || framerate
< 1)
2655 if(!cam
->params
.flickerControl
.disabled
) {
2656 /* Flicker control on */
2657 if((cam
->exposure_status
== EXPOSURE_VERY_DARK
||
2658 cam
->exposure_status
== EXPOSURE_DARK
) &&
2659 cam
->exposure_count
>= DARK_TIME
*framerate
&&
2660 cam
->params
.sensorFps
.divisor
< 3) {
2662 /* dark for too long */
2663 ++cam
->params
.sensorFps
.divisor
;
2664 cam
->cmd_queue
|= COMMAND_SETSENSORFPS
;
2666 cam
->params
.flickerControl
.coarseJump
=
2667 flicker_jumps
[cam
->mainsFreq
]
2668 [cam
->params
.sensorFps
.baserate
]
2669 [cam
->params
.sensorFps
.divisor
];
2670 cam
->cmd_queue
|= COMMAND_SETFLICKERCTRL
;
2672 new_exposure
= cam
->params
.flickerControl
.coarseJump
-1;
2673 while(new_exposure
< old_exposure
/2)
2674 new_exposure
+= cam
->params
.flickerControl
.coarseJump
;
2675 cam
->params
.exposure
.coarseExpLo
= new_exposure
& 0xff;
2676 cam
->params
.exposure
.coarseExpHi
= new_exposure
>> 8;
2677 cam
->cmd_queue
|= COMMAND_SETEXPOSURE
;
2678 cam
->exposure_status
= EXPOSURE_NORMAL
;
2679 LOG("Automatically decreasing sensor_fps\n");
2681 } else if((cam
->exposure_status
== EXPOSURE_VERY_LIGHT
||
2682 cam
->exposure_status
== EXPOSURE_LIGHT
) &&
2683 cam
->exposure_count
>= LIGHT_TIME
*framerate
&&
2684 cam
->params
.sensorFps
.divisor
> 0) {
2686 /* light for too long */
2687 int max_exp
= FIRMWARE_VERSION(1,2) ? MAX_EXP_102
: MAX_EXP
;
2689 --cam
->params
.sensorFps
.divisor
;
2690 cam
->cmd_queue
|= COMMAND_SETSENSORFPS
;
2692 cam
->params
.flickerControl
.coarseJump
=
2693 flicker_jumps
[cam
->mainsFreq
]
2694 [cam
->params
.sensorFps
.baserate
]
2695 [cam
->params
.sensorFps
.divisor
];
2696 cam
->cmd_queue
|= COMMAND_SETFLICKERCTRL
;
2698 new_exposure
= cam
->params
.flickerControl
.coarseJump
-1;
2699 while(new_exposure
< 2*old_exposure
&&
2701 cam
->params
.flickerControl
.coarseJump
< max_exp
)
2702 new_exposure
+= cam
->params
.flickerControl
.coarseJump
;
2703 cam
->params
.exposure
.coarseExpLo
= new_exposure
& 0xff;
2704 cam
->params
.exposure
.coarseExpHi
= new_exposure
>> 8;
2705 cam
->cmd_queue
|= COMMAND_SETEXPOSURE
;
2706 cam
->exposure_status
= EXPOSURE_NORMAL
;
2707 LOG("Automatically increasing sensor_fps\n");
2710 /* Flicker control off */
2711 if((cam
->exposure_status
== EXPOSURE_VERY_DARK
||
2712 cam
->exposure_status
== EXPOSURE_DARK
) &&
2713 cam
->exposure_count
>= DARK_TIME
*framerate
&&
2714 cam
->params
.sensorFps
.divisor
< 3) {
2716 /* dark for too long */
2717 ++cam
->params
.sensorFps
.divisor
;
2718 cam
->cmd_queue
|= COMMAND_SETSENSORFPS
;
2720 if(cam
->params
.exposure
.gain
> 0) {
2721 --cam
->params
.exposure
.gain
;
2722 cam
->cmd_queue
|= COMMAND_SETEXPOSURE
;
2724 cam
->exposure_status
= EXPOSURE_NORMAL
;
2725 LOG("Automatically decreasing sensor_fps\n");
2727 } else if((cam
->exposure_status
== EXPOSURE_VERY_LIGHT
||
2728 cam
->exposure_status
== EXPOSURE_LIGHT
) &&
2729 cam
->exposure_count
>= LIGHT_TIME
*framerate
&&
2730 cam
->params
.sensorFps
.divisor
> 0) {
2732 /* light for too long */
2733 --cam
->params
.sensorFps
.divisor
;
2734 cam
->cmd_queue
|= COMMAND_SETSENSORFPS
;
2736 if(cam
->params
.exposure
.gain
<
2737 cam
->params
.exposure
.gainMode
-1) {
2738 ++cam
->params
.exposure
.gain
;
2739 cam
->cmd_queue
|= COMMAND_SETEXPOSURE
;
2741 cam
->exposure_status
= EXPOSURE_NORMAL
;
2742 LOG("Automatically increasing sensor_fps\n");
2745 mutex_unlock(&cam
->param_lock
);
2748 /*-----------------------------------------------------------------*/
2749 /* if flicker is switched off, this function switches it back on.It checks,
2750 however, that conditions are suitable before restarting it.
2751 This should only be called for firmware version 1.2.
2753 It also adjust the colour balance when an exposure step is detected - as
2754 long as flicker is running
2756 static void restart_flicker(struct cam_data
*cam
)
2758 int cam_exposure
, old_exp
;
2759 if(!FIRMWARE_VERSION(1,2))
2761 mutex_lock(&cam
->param_lock
);
2762 if(cam
->params
.flickerControl
.flickerMode
== 0 ||
2763 cam
->raw_image
[39] == 0) {
2764 mutex_unlock(&cam
->param_lock
);
2767 cam_exposure
= cam
->raw_image
[39]*2;
2768 old_exp
= cam
->params
.exposure
.coarseExpLo
+
2769 cam
->params
.exposure
.coarseExpHi
*256;
2771 see how far away camera exposure is from a valid
2772 flicker exposure value
2774 cam_exposure
%= cam
->params
.flickerControl
.coarseJump
;
2775 if(!cam
->params
.flickerControl
.disabled
&&
2776 cam_exposure
<= cam
->params
.flickerControl
.coarseJump
- 3) {
2777 /* Flicker control auto-disabled */
2778 cam
->params
.flickerControl
.disabled
= 1;
2781 if(cam
->params
.flickerControl
.disabled
&&
2782 cam
->params
.flickerControl
.flickerMode
&&
2783 old_exp
> cam
->params
.flickerControl
.coarseJump
+
2784 ROUND_UP_EXP_FOR_FLICKER
) {
2785 /* exposure is now high enough to switch
2786 flicker control back on */
2787 set_flicker(&cam
->params
, &cam
->cmd_queue
, 1);
2788 if((cam
->cmd_queue
& COMMAND_SETEXPOSURE
) &&
2789 cam
->params
.exposure
.expMode
== 2)
2790 cam
->exposure_status
= EXPOSURE_NORMAL
;
2793 mutex_unlock(&cam
->param_lock
);
2795 #undef FIRMWARE_VERSION
2797 static int clear_stall(struct cam_data
*cam
)
2799 /* FIXME: Does this actually work? */
2800 LOG("Clearing stall\n");
2802 cam
->ops
->streamRead(cam
->lowlevel_data
, cam
->raw_image
, 0);
2803 do_command(cam
, CPIA_COMMAND_GetCameraStatus
,0,0,0,0);
2804 return cam
->params
.status
.streamState
!= STREAM_PAUSED
;
2807 /* kernel thread function to read image from camera */
2808 static int fetch_frame(void *data
)
2810 int image_size
, retry
;
2811 struct cam_data
*cam
= (struct cam_data
*)data
;
2812 unsigned long oldjif
, rate
, diff
;
2814 /* Allow up to two bad images in a row to be read and
2815 * ignored before an error is reported */
2816 for (retry
= 0; retry
< 3; ++retry
) {
2818 DBG("retry=%d\n", retry
);
2823 /* load first frame always uncompressed */
2824 if (cam
->first_frame
&&
2825 cam
->params
.compression
.mode
!= CPIA_COMPRESSION_NONE
) {
2826 do_command(cam
, CPIA_COMMAND_SetCompression
,
2827 CPIA_COMPRESSION_NONE
,
2828 NO_DECIMATION
, 0, 0);
2829 /* Trial & error - Discarding a frame prevents the
2830 first frame from having an error in the data. */
2831 do_command(cam
, CPIA_COMMAND_DiscardFrame
, 0, 0, 0, 0);
2834 /* init camera upload */
2835 if (do_command(cam
, CPIA_COMMAND_GrabFrame
, 0,
2836 cam
->params
.streamStartLine
, 0, 0))
2839 if (cam
->ops
->wait_for_stream_ready
) {
2840 /* loop until image ready */
2842 do_command(cam
, CPIA_COMMAND_GetCameraStatus
,0,0,0,0);
2843 while (cam
->params
.status
.streamState
!= STREAM_READY
) {
2844 if(++count
> READY_TIMEOUT
)
2846 if(cam
->params
.status
.streamState
==
2849 if(!clear_stall(cam
))
2855 /* sleep for 10 ms, hopefully ;) */
2856 msleep_interruptible(10);
2857 if (signal_pending(current
))
2860 do_command(cam
, CPIA_COMMAND_GetCameraStatus
,
2863 if(cam
->params
.status
.streamState
!= STREAM_READY
) {
2870 /* grab image from camera */
2872 image_size
= cam
->ops
->streamRead(cam
->lowlevel_data
,
2874 if (image_size
<= 0) {
2875 DBG("streamRead failed: %d\n", image_size
);
2879 rate
= image_size
* HZ
/ 1024;
2880 diff
= jiffies
-oldjif
;
2881 cam
->transfer_rate
= diff
==0 ? rate
: rate
/diff
;
2882 /* diff==0 ? unlikely but possible */
2884 /* Switch flicker control back on if it got turned off */
2885 restart_flicker(cam
);
2887 /* If AEC is enabled, monitor the exposure and
2888 adjust the sensor frame rate if needed */
2889 if(cam
->params
.exposure
.expMode
== 2)
2890 monitor_exposure(cam
);
2892 /* camera idle now so dispatch queued commands */
2893 dispatch_commands(cam
);
2895 /* Update our knowledge of the camera state */
2896 do_command(cam
, CPIA_COMMAND_GetColourBalance
, 0, 0, 0, 0);
2897 do_command(cam
, CPIA_COMMAND_GetExposure
, 0, 0, 0, 0);
2898 do_command(cam
, CPIA_COMMAND_ReadMCPorts
, 0, 0, 0, 0);
2900 /* decompress and convert image to by copying it from
2901 * raw_image to decompressed_frame
2906 cam
->image_size
= parse_picture(cam
, image_size
);
2907 if (cam
->image_size
<= 0) {
2908 DBG("parse_picture failed %d\n", cam
->image_size
);
2909 if(cam
->params
.compression
.mode
!=
2910 CPIA_COMPRESSION_NONE
) {
2911 /* Compression may not work right if we
2912 had a bad frame, get the next one
2914 cam
->first_frame
= 1;
2915 do_command(cam
, CPIA_COMMAND_SetGrabMode
,
2916 CPIA_GRAB_SINGLE
, 0, 0, 0);
2917 /* FIXME: Trial & error - need up to 70ms for
2918 the grab mode change to complete ? */
2919 msleep_interruptible(70);
2920 if (signal_pending(current
))
2928 /* FIXME: this only works for double buffering */
2929 if (cam
->frame
[cam
->curframe
].state
== FRAME_READY
) {
2930 memcpy(cam
->frame
[cam
->curframe
].data
,
2931 cam
->decompressed_frame
.data
,
2932 cam
->decompressed_frame
.count
);
2933 cam
->frame
[cam
->curframe
].state
= FRAME_DONE
;
2935 cam
->decompressed_frame
.state
= FRAME_DONE
;
2937 if (cam
->first_frame
) {
2938 cam
->first_frame
= 0;
2939 do_command(cam
, CPIA_COMMAND_SetCompression
,
2940 cam
->params
.compression
.mode
,
2941 cam
->params
.compression
.decimation
, 0, 0);
2943 /* Switch from single-grab to continuous grab */
2944 do_command(cam
, CPIA_COMMAND_SetGrabMode
,
2945 CPIA_GRAB_CONTINUOUS
, 0, 0, 0);
2952 static int capture_frame(struct cam_data
*cam
, struct video_mmap
*vm
)
2954 if (!cam
->frame_buf
) {
2955 /* we do lazy allocation */
2957 if ((err
= allocate_frame_buf(cam
)))
2961 cam
->curframe
= vm
->frame
;
2962 cam
->frame
[cam
->curframe
].state
= FRAME_READY
;
2963 return fetch_frame(cam
);
2966 static int goto_high_power(struct cam_data
*cam
)
2968 if (do_command(cam
, CPIA_COMMAND_GotoHiPower
, 0, 0, 0, 0))
2970 msleep_interruptible(40); /* windows driver does it too */
2971 if(signal_pending(current
))
2973 if (do_command(cam
, CPIA_COMMAND_GetCameraStatus
, 0, 0, 0, 0))
2975 if (cam
->params
.status
.systemState
== HI_POWER_STATE
) {
2976 DBG("camera now in HIGH power state\n");
2983 static int goto_low_power(struct cam_data
*cam
)
2985 if (do_command(cam
, CPIA_COMMAND_GotoLoPower
, 0, 0, 0, 0))
2987 if (do_command(cam
, CPIA_COMMAND_GetCameraStatus
, 0, 0, 0, 0))
2989 if (cam
->params
.status
.systemState
== LO_POWER_STATE
) {
2990 DBG("camera now in LOW power state\n");
2997 static void save_camera_state(struct cam_data
*cam
)
2999 if(!(cam
->cmd_queue
& COMMAND_SETCOLOURBALANCE
))
3000 do_command(cam
, CPIA_COMMAND_GetColourBalance
, 0, 0, 0, 0);
3001 if(!(cam
->cmd_queue
& COMMAND_SETEXPOSURE
))
3002 do_command(cam
, CPIA_COMMAND_GetExposure
, 0, 0, 0, 0);
3004 DBG("%d/%d/%d/%d/%d/%d/%d/%d\n",
3005 cam
->params
.exposure
.gain
,
3006 cam
->params
.exposure
.fineExp
,
3007 cam
->params
.exposure
.coarseExpLo
,
3008 cam
->params
.exposure
.coarseExpHi
,
3009 cam
->params
.exposure
.redComp
,
3010 cam
->params
.exposure
.green1Comp
,
3011 cam
->params
.exposure
.green2Comp
,
3012 cam
->params
.exposure
.blueComp
);
3014 cam
->params
.colourBalance
.redGain
,
3015 cam
->params
.colourBalance
.greenGain
,
3016 cam
->params
.colourBalance
.blueGain
);
3019 static int set_camera_state(struct cam_data
*cam
)
3021 cam
->cmd_queue
= COMMAND_SETCOMPRESSION
|
3022 COMMAND_SETCOMPRESSIONTARGET
|
3023 COMMAND_SETCOLOURPARAMS
|
3025 COMMAND_SETYUVTHRESH
|
3026 COMMAND_SETECPTIMING
|
3027 COMMAND_SETCOMPRESSIONPARAMS
|
3028 COMMAND_SETEXPOSURE
|
3029 COMMAND_SETCOLOURBALANCE
|
3030 COMMAND_SETSENSORFPS
|
3032 COMMAND_SETFLICKERCTRL
|
3033 COMMAND_SETVLOFFSET
;
3035 do_command(cam
, CPIA_COMMAND_SetGrabMode
, CPIA_GRAB_SINGLE
,0,0,0);
3036 dispatch_commands(cam
);
3038 /* Wait 6 frames for the sensor to get all settings and
3039 AEC/ACB to settle */
3040 msleep_interruptible(6*(cam
->params
.sensorFps
.baserate
? 33 : 40) *
3041 (1 << cam
->params
.sensorFps
.divisor
) + 10);
3043 if(signal_pending(current
))
3046 save_camera_state(cam
);
3051 static void get_version_information(struct cam_data
*cam
)
3053 /* GetCPIAVersion */
3054 do_command(cam
, CPIA_COMMAND_GetCPIAVersion
, 0, 0, 0, 0);
3057 do_command(cam
, CPIA_COMMAND_GetPnPID
, 0, 0, 0, 0);
3060 /* initialize camera */
3061 static int reset_camera(struct cam_data
*cam
)
3064 /* Start the camera in low power mode */
3065 if (goto_low_power(cam
)) {
3066 if (cam
->params
.status
.systemState
!= WARM_BOOT_STATE
)
3069 /* FIXME: this is just dirty trial and error */
3070 err
= goto_high_power(cam
);
3073 do_command(cam
, CPIA_COMMAND_DiscardFrame
, 0, 0, 0, 0);
3074 if (goto_low_power(cam
))
3078 /* procedure described in developer's guide p3-28 */
3080 /* Check the firmware version. */
3081 cam
->params
.version
.firmwareVersion
= 0;
3082 get_version_information(cam
);
3083 if (cam
->params
.version
.firmwareVersion
!= 1)
3086 /* A bug in firmware 1-02 limits gainMode to 2 */
3087 if(cam
->params
.version
.firmwareRevision
<= 2 &&
3088 cam
->params
.exposure
.gainMode
> 2) {
3089 cam
->params
.exposure
.gainMode
= 2;
3092 /* set QX3 detected flag */
3093 cam
->params
.qx3
.qx3_detected
= (cam
->params
.pnpID
.vendor
== 0x0813 &&
3094 cam
->params
.pnpID
.product
== 0x0001);
3096 /* The fatal error checking should be done after
3097 * the camera powers up (developer's guide p 3-38) */
3099 /* Set streamState before transition to high power to avoid bug
3100 * in firmware 1-02 */
3101 do_command(cam
, CPIA_COMMAND_ModifyCameraStatus
, STREAMSTATE
, 0,
3102 STREAM_NOT_READY
, 0);
3105 err
= goto_high_power(cam
);
3109 /* Check the camera status */
3110 if (do_command(cam
, CPIA_COMMAND_GetCameraStatus
, 0, 0, 0, 0))
3113 if (cam
->params
.status
.fatalError
) {
3114 DBG("fatal_error: %#04x\n",
3115 cam
->params
.status
.fatalError
);
3116 DBG("vp_status: %#04x\n",
3117 cam
->params
.status
.vpStatus
);
3118 if (cam
->params
.status
.fatalError
& ~(COM_FLAG
|CPIA_FLAG
)) {
3119 /* Fatal error in camera */
3121 } else if (cam
->params
.status
.fatalError
& (COM_FLAG
|CPIA_FLAG
)) {
3122 /* Firmware 1-02 may do this for parallel port cameras,
3123 * just clear the flags (developer's guide p 3-38) */
3124 do_command(cam
, CPIA_COMMAND_ModifyCameraStatus
,
3125 FATALERROR
, ~(COM_FLAG
|CPIA_FLAG
), 0, 0);
3129 /* Check the camera status again */
3130 if (cam
->params
.status
.fatalError
) {
3131 if (cam
->params
.status
.fatalError
)
3135 /* VPVersion can't be retrieved before the camera is in HiPower,
3136 * so get it here instead of in get_version_information. */
3137 do_command(cam
, CPIA_COMMAND_GetVPVersion
, 0, 0, 0, 0);
3139 /* set camera to a known state */
3140 return set_camera_state(cam
);
3143 static void put_cam(struct cpia_camera_ops
* ops
)
3145 module_put(ops
->owner
);
3148 /* ------------------------- V4L interface --------------------- */
3149 static int cpia_open(struct file
*file
)
3151 struct video_device
*dev
= video_devdata(file
);
3152 struct cam_data
*cam
= video_get_drvdata(dev
);
3156 DBG("Internal error, cam_data not found!\n");
3160 if (cam
->open_count
> 0) {
3161 DBG("Camera already open\n");
3165 if (!try_module_get(cam
->ops
->owner
))
3168 mutex_lock(&cam
->busy_lock
);
3170 if (!cam
->raw_image
) {
3171 cam
->raw_image
= rvmalloc(CPIA_MAX_IMAGE_SIZE
);
3172 if (!cam
->raw_image
)
3176 if (!cam
->decompressed_frame
.data
) {
3177 cam
->decompressed_frame
.data
= rvmalloc(CPIA_MAX_FRAME_SIZE
);
3178 if (!cam
->decompressed_frame
.data
)
3184 if (cam
->ops
->open(cam
->lowlevel_data
))
3187 /* reset the camera */
3188 if ((err
= reset_camera(cam
)) != 0) {
3189 cam
->ops
->close(cam
->lowlevel_data
);
3194 if(signal_pending(current
))
3197 /* Set ownership of /proc/cpia/videoX to current user */
3199 cam
->proc_entry
->uid
= current_uid();
3201 /* set mark for loading first frame uncompressed */
3202 cam
->first_frame
= 1;
3204 /* init it to something */
3205 cam
->mmap_kludge
= 0;
3208 file
->private_data
= dev
;
3209 mutex_unlock(&cam
->busy_lock
);
3213 if (cam
->decompressed_frame
.data
) {
3214 rvfree(cam
->decompressed_frame
.data
, CPIA_MAX_FRAME_SIZE
);
3215 cam
->decompressed_frame
.data
= NULL
;
3217 if (cam
->raw_image
) {
3218 rvfree(cam
->raw_image
, CPIA_MAX_IMAGE_SIZE
);
3219 cam
->raw_image
= NULL
;
3221 mutex_unlock(&cam
->busy_lock
);
3226 static int cpia_close(struct file
*file
)
3228 struct video_device
*dev
= file
->private_data
;
3229 struct cam_data
*cam
= video_get_drvdata(dev
);
3232 /* Return ownership of /proc/cpia/videoX to root */
3234 cam
->proc_entry
->uid
= 0;
3236 /* save camera state for later open (developers guide ch 3.5.3) */
3237 save_camera_state(cam
);
3240 goto_low_power(cam
);
3242 /* Update the camera status */
3243 do_command(cam
, CPIA_COMMAND_GetCameraStatus
, 0, 0, 0, 0);
3245 /* cleanup internal state stuff */
3246 free_frames(cam
->frame
);
3249 cam
->ops
->close(cam
->lowlevel_data
);
3254 if (--cam
->open_count
== 0) {
3255 /* clean up capture-buffers */
3256 if (cam
->raw_image
) {
3257 rvfree(cam
->raw_image
, CPIA_MAX_IMAGE_SIZE
);
3258 cam
->raw_image
= NULL
;
3261 if (cam
->decompressed_frame
.data
) {
3262 rvfree(cam
->decompressed_frame
.data
, CPIA_MAX_FRAME_SIZE
);
3263 cam
->decompressed_frame
.data
= NULL
;
3267 free_frame_buf(cam
);
3272 file
->private_data
= NULL
;
3277 static ssize_t
cpia_read(struct file
*file
, char __user
*buf
,
3278 size_t count
, loff_t
*ppos
)
3280 struct video_device
*dev
= file
->private_data
;
3281 struct cam_data
*cam
= video_get_drvdata(dev
);
3284 /* make this _really_ smp and multithread-safe */
3285 if (mutex_lock_interruptible(&cam
->busy_lock
))
3290 mutex_unlock(&cam
->busy_lock
);
3296 mutex_unlock(&cam
->busy_lock
);
3302 mutex_unlock(&cam
->busy_lock
);
3307 cam
->decompressed_frame
.state
= FRAME_READY
;
3309 if((err
= fetch_frame(cam
)) != 0) {
3310 DBG("ERROR from fetch_frame: %d\n", err
);
3311 mutex_unlock(&cam
->busy_lock
);
3314 cam
->decompressed_frame
.state
= FRAME_UNUSED
;
3316 /* copy data to user space */
3317 if (cam
->decompressed_frame
.count
> count
) {
3318 DBG("count wrong: %d, %lu\n", cam
->decompressed_frame
.count
,
3319 (unsigned long) count
);
3320 mutex_unlock(&cam
->busy_lock
);
3323 if (copy_to_user(buf
, cam
->decompressed_frame
.data
,
3324 cam
->decompressed_frame
.count
)) {
3325 DBG("copy_to_user failed\n");
3326 mutex_unlock(&cam
->busy_lock
);
3330 mutex_unlock(&cam
->busy_lock
);
3331 return cam
->decompressed_frame
.count
;
3334 static long cpia_do_ioctl(struct file
*file
, unsigned int cmd
, void *arg
)
3336 struct video_device
*dev
= file
->private_data
;
3337 struct cam_data
*cam
= video_get_drvdata(dev
);
3340 if (!cam
|| !cam
->ops
)
3343 /* make this _really_ smp-safe */
3344 if (mutex_lock_interruptible(&cam
->busy_lock
))
3347 /* DBG("cpia_ioctl: %u\n", cmd); */
3350 /* query capabilities */
3353 struct video_capability
*b
= arg
;
3355 DBG("VIDIOCGCAP\n");
3356 strcpy(b
->name
, "CPiA Camera");
3357 b
->type
= VID_TYPE_CAPTURE
| VID_TYPE_SUBCAPTURE
;
3360 b
->maxwidth
= 352; /* VIDEOSIZE_CIF */
3362 b
->minwidth
= 48; /* VIDEOSIZE_48_48 */
3367 /* get/set video source - we are a camera and nothing else */
3370 struct video_channel
*v
= arg
;
3372 DBG("VIDIOCGCHAN\n");
3373 if (v
->channel
!= 0) {
3379 strcpy(v
->name
, "Camera");
3382 v
->type
= VIDEO_TYPE_CAMERA
;
3389 struct video_channel
*v
= arg
;
3391 DBG("VIDIOCSCHAN\n");
3392 if (v
->channel
!= 0)
3397 /* image properties */
3400 struct video_picture
*pic
= arg
;
3401 DBG("VIDIOCGPICT\n");
3408 struct video_picture
*vp
= arg
;
3410 DBG("VIDIOCSPICT\n");
3412 /* check validity */
3413 DBG("palette: %d\n", vp
->palette
);
3414 DBG("depth: %d\n", vp
->depth
);
3415 if (!valid_mode(vp
->palette
, vp
->depth
)) {
3420 mutex_lock(&cam
->param_lock
);
3421 /* brightness, colour, contrast need no check 0-65535 */
3423 /* update cam->params.colourParams */
3424 cam
->params
.colourParams
.brightness
= vp
->brightness
*100/65535;
3425 cam
->params
.colourParams
.contrast
= vp
->contrast
*100/65535;
3426 cam
->params
.colourParams
.saturation
= vp
->colour
*100/65535;
3427 /* contrast is in steps of 8, so round */
3428 cam
->params
.colourParams
.contrast
=
3429 ((cam
->params
.colourParams
.contrast
+ 3) / 8) * 8;
3430 if (cam
->params
.version
.firmwareVersion
== 1 &&
3431 cam
->params
.version
.firmwareRevision
== 2 &&
3432 cam
->params
.colourParams
.contrast
> 80) {
3433 /* 1-02 firmware limits contrast to 80 */
3434 cam
->params
.colourParams
.contrast
= 80;
3437 /* Adjust flicker control if necessary */
3438 if(cam
->params
.flickerControl
.allowableOverExposure
< 0)
3439 cam
->params
.flickerControl
.allowableOverExposure
=
3440 -find_over_exposure(cam
->params
.colourParams
.brightness
);
3441 if(cam
->params
.flickerControl
.flickerMode
!= 0)
3442 cam
->cmd_queue
|= COMMAND_SETFLICKERCTRL
;
3445 /* queue command to update camera */
3446 cam
->cmd_queue
|= COMMAND_SETCOLOURPARAMS
;
3447 mutex_unlock(&cam
->param_lock
);
3448 DBG("VIDIOCSPICT: %d / %d // %d / %d / %d / %d\n",
3449 vp
->depth
, vp
->palette
, vp
->brightness
, vp
->hue
, vp
->colour
,
3454 /* get/set capture window */
3457 struct video_window
*vw
= arg
;
3458 DBG("VIDIOCGWIN\n");
3466 /* copy_from_user, check validity, copy to internal structure */
3467 struct video_window
*vw
= arg
;
3468 DBG("VIDIOCSWIN\n");
3470 if (vw
->clipcount
!= 0) { /* clipping not supported */
3474 if (vw
->clips
!= NULL
) { /* clipping not supported */
3479 /* we set the video window to something smaller or equal to what
3480 * is requested by the user???
3482 mutex_lock(&cam
->param_lock
);
3483 if (vw
->width
!= cam
->vw
.width
|| vw
->height
!= cam
->vw
.height
) {
3484 int video_size
= match_videosize(vw
->width
, vw
->height
);
3486 if (video_size
< 0) {
3488 mutex_unlock(&cam
->param_lock
);
3491 cam
->video_size
= video_size
;
3493 /* video size is changing, reset the subcapture area */
3494 memset(&cam
->vc
, 0, sizeof(cam
->vc
));
3497 DBG("%d / %d\n", cam
->vw
.width
, cam
->vw
.height
);
3498 cam
->cmd_queue
|= COMMAND_SETFORMAT
;
3501 mutex_unlock(&cam
->param_lock
);
3503 /* setformat ignored by camera during streaming,
3504 * so stop/dispatch/start */
3505 if (cam
->cmd_queue
& COMMAND_SETFORMAT
) {
3507 dispatch_commands(cam
);
3509 DBG("%d/%d:%d\n", cam
->video_size
,
3510 cam
->vw
.width
, cam
->vw
.height
);
3514 /* mmap interface */
3517 struct video_mbuf
*vm
= arg
;
3520 DBG("VIDIOCGMBUF\n");
3521 memset(vm
, 0, sizeof(*vm
));
3522 vm
->size
= CPIA_MAX_FRAME_SIZE
*FRAME_NUM
;
3523 vm
->frames
= FRAME_NUM
;
3524 for (i
= 0; i
< FRAME_NUM
; i
++)
3525 vm
->offsets
[i
] = CPIA_MAX_FRAME_SIZE
* i
;
3529 case VIDIOCMCAPTURE
:
3531 struct video_mmap
*vm
= arg
;
3534 DBG("VIDIOCMCAPTURE: %d / %d / %dx%d\n", vm
->format
, vm
->frame
,
3535 vm
->width
, vm
->height
);
3536 if (vm
->frame
<0||vm
->frame
>=FRAME_NUM
) {
3541 /* set video format */
3542 cam
->vp
.palette
= vm
->format
;
3543 switch(vm
->format
) {
3544 case VIDEO_PALETTE_GREY
:
3547 case VIDEO_PALETTE_RGB555
:
3548 case VIDEO_PALETTE_RGB565
:
3549 case VIDEO_PALETTE_YUV422
:
3550 case VIDEO_PALETTE_YUYV
:
3551 case VIDEO_PALETTE_UYVY
:
3554 case VIDEO_PALETTE_RGB24
:
3557 case VIDEO_PALETTE_RGB32
:
3567 /* set video size */
3568 video_size
= match_videosize(vm
->width
, vm
->height
);
3569 if (video_size
< 0) {
3573 if (video_size
!= cam
->video_size
) {
3574 cam
->video_size
= video_size
;
3576 /* video size is changing, reset the subcapture area */
3577 memset(&cam
->vc
, 0, sizeof(cam
->vc
));
3580 cam
->cmd_queue
|= COMMAND_SETFORMAT
;
3581 dispatch_commands(cam
);
3583 /* according to v4l-spec we must start streaming here */
3584 cam
->mmap_kludge
= 1;
3585 retval
= capture_frame(cam
, vm
);
3594 //DBG("VIDIOCSYNC: %d\n", *frame);
3596 if (*frame
<0 || *frame
>= FRAME_NUM
) {
3601 switch (cam
->frame
[*frame
].state
) {
3604 case FRAME_GRABBING
:
3605 DBG("sync to unused frame %d\n", *frame
);
3610 cam
->frame
[*frame
].state
= FRAME_UNUSED
;
3611 //DBG("VIDIOCSYNC: %d synced\n", *frame);
3614 if (retval
== -EINTR
) {
3615 /* FIXME - xawtv does not handle this nice */
3621 case VIDIOCGCAPTURE
:
3623 struct video_capture
*vc
= arg
;
3625 DBG("VIDIOCGCAPTURE\n");
3632 case VIDIOCSCAPTURE
:
3634 struct video_capture
*vc
= arg
;
3636 DBG("VIDIOCSCAPTURE\n");
3638 if (vc
->decimation
!= 0) { /* How should this be used? */
3642 if (vc
->flags
!= 0) { /* Even/odd grab not supported */
3647 /* Clip to the resolution we can set for the ROI
3648 (every 8 columns and 4 rows) */
3649 vc
->x
= vc
->x
& ~(__u32
)7;
3650 vc
->y
= vc
->y
& ~(__u32
)3;
3651 vc
->width
= vc
->width
& ~(__u32
)7;
3652 vc
->height
= vc
->height
& ~(__u32
)3;
3654 if(vc
->width
== 0 || vc
->height
== 0 ||
3655 vc
->x
+ vc
->width
> cam
->vw
.width
||
3656 vc
->y
+ vc
->height
> cam
->vw
.height
) {
3661 DBG("%d,%d/%dx%d\n", vc
->x
,vc
->y
,vc
->width
, vc
->height
);
3663 mutex_lock(&cam
->param_lock
);
3667 cam
->vc
.width
= vc
->width
;
3668 cam
->vc
.height
= vc
->height
;
3671 cam
->cmd_queue
|= COMMAND_SETFORMAT
;
3673 mutex_unlock(&cam
->param_lock
);
3675 /* setformat ignored by camera during streaming,
3676 * so stop/dispatch/start */
3677 dispatch_commands(cam
);
3683 struct video_unit
*vu
= arg
;
3685 DBG("VIDIOCGUNIT\n");
3687 vu
->video
= cam
->vdev
.minor
;
3688 vu
->vbi
= VIDEO_NO_UNIT
;
3689 vu
->radio
= VIDEO_NO_UNIT
;
3690 vu
->audio
= VIDEO_NO_UNIT
;
3691 vu
->teletext
= VIDEO_NO_UNIT
;
3697 /* pointless to implement overlay with this camera */
3702 /* tuner interface - we have none */
3707 /* audio interface - we have none */
3713 retval
= -ENOIOCTLCMD
;
3717 mutex_unlock(&cam
->busy_lock
);
3721 static long cpia_ioctl(struct file
*file
,
3722 unsigned int cmd
, unsigned long arg
)
3724 return video_usercopy(file
, cmd
, arg
, cpia_do_ioctl
);
3729 static int cpia_mmap(struct file
*file
, struct vm_area_struct
*vma
)
3731 struct video_device
*dev
= file
->private_data
;
3732 unsigned long start
= vma
->vm_start
;
3733 unsigned long size
= vma
->vm_end
- vma
->vm_start
;
3734 unsigned long page
, pos
;
3735 struct cam_data
*cam
= video_get_drvdata(dev
);
3738 if (!cam
|| !cam
->ops
)
3741 DBG("cpia_mmap: %ld\n", size
);
3743 if (size
> FRAME_NUM
*CPIA_MAX_FRAME_SIZE
)
3746 if (!cam
|| !cam
->ops
)
3749 /* make this _really_ smp-safe */
3750 if (mutex_lock_interruptible(&cam
->busy_lock
))
3753 if (!cam
->frame_buf
) { /* we do lazy allocation */
3754 if ((retval
= allocate_frame_buf(cam
))) {
3755 mutex_unlock(&cam
->busy_lock
);
3760 pos
= (unsigned long)(cam
->frame_buf
);
3762 page
= vmalloc_to_pfn((void *)pos
);
3763 if (remap_pfn_range(vma
, start
, page
, PAGE_SIZE
, PAGE_SHARED
)) {
3764 mutex_unlock(&cam
->busy_lock
);
3769 if (size
> PAGE_SIZE
)
3775 DBG("cpia_mmap: %ld\n", size
);
3776 mutex_unlock(&cam
->busy_lock
);
3781 static const struct v4l2_file_operations cpia_fops
= {
3782 .owner
= THIS_MODULE
,
3784 .release
= cpia_close
,
3787 .ioctl
= cpia_ioctl
,
3790 static struct video_device cpia_template
= {
3791 .name
= "CPiA Camera",
3793 .release
= video_device_release_empty
,
3796 /* initialise cam_data structure */
3797 static void reset_camera_struct(struct cam_data
*cam
)
3799 /* The following parameter values are the defaults from
3800 * "Software Developer's Guide for CPiA Cameras". Any changes
3801 * to the defaults are noted in comments. */
3802 cam
->params
.colourParams
.brightness
= 50;
3803 cam
->params
.colourParams
.contrast
= 48;
3804 cam
->params
.colourParams
.saturation
= 50;
3805 cam
->params
.exposure
.gainMode
= 4;
3806 cam
->params
.exposure
.expMode
= 2; /* AEC */
3807 cam
->params
.exposure
.compMode
= 1;
3808 cam
->params
.exposure
.centreWeight
= 1;
3809 cam
->params
.exposure
.gain
= 0;
3810 cam
->params
.exposure
.fineExp
= 0;
3811 cam
->params
.exposure
.coarseExpLo
= 185;
3812 cam
->params
.exposure
.coarseExpHi
= 0;
3813 cam
->params
.exposure
.redComp
= COMP_RED
;
3814 cam
->params
.exposure
.green1Comp
= COMP_GREEN1
;
3815 cam
->params
.exposure
.green2Comp
= COMP_GREEN2
;
3816 cam
->params
.exposure
.blueComp
= COMP_BLUE
;
3817 cam
->params
.colourBalance
.balanceMode
= 2; /* ACB */
3818 cam
->params
.colourBalance
.redGain
= 32;
3819 cam
->params
.colourBalance
.greenGain
= 6;
3820 cam
->params
.colourBalance
.blueGain
= 92;
3821 cam
->params
.apcor
.gain1
= 0x18;
3822 cam
->params
.apcor
.gain2
= 0x16;
3823 cam
->params
.apcor
.gain4
= 0x24;
3824 cam
->params
.apcor
.gain8
= 0x34;
3825 cam
->params
.flickerControl
.flickerMode
= 0;
3826 cam
->params
.flickerControl
.disabled
= 1;
3828 cam
->params
.flickerControl
.coarseJump
=
3829 flicker_jumps
[cam
->mainsFreq
]
3830 [cam
->params
.sensorFps
.baserate
]
3831 [cam
->params
.sensorFps
.divisor
];
3832 cam
->params
.flickerControl
.allowableOverExposure
=
3833 -find_over_exposure(cam
->params
.colourParams
.brightness
);
3834 cam
->params
.vlOffset
.gain1
= 20;
3835 cam
->params
.vlOffset
.gain2
= 24;
3836 cam
->params
.vlOffset
.gain4
= 26;
3837 cam
->params
.vlOffset
.gain8
= 26;
3838 cam
->params
.compressionParams
.hysteresis
= 3;
3839 cam
->params
.compressionParams
.threshMax
= 11;
3840 cam
->params
.compressionParams
.smallStep
= 1;
3841 cam
->params
.compressionParams
.largeStep
= 3;
3842 cam
->params
.compressionParams
.decimationHysteresis
= 2;
3843 cam
->params
.compressionParams
.frDiffStepThresh
= 5;
3844 cam
->params
.compressionParams
.qDiffStepThresh
= 3;
3845 cam
->params
.compressionParams
.decimationThreshMod
= 2;
3846 /* End of default values from Software Developer's Guide */
3848 cam
->transfer_rate
= 0;
3849 cam
->exposure_status
= EXPOSURE_NORMAL
;
3851 /* Set Sensor FPS to 15fps. This seems better than 30fps
3852 * for indoor lighting. */
3853 cam
->params
.sensorFps
.divisor
= 1;
3854 cam
->params
.sensorFps
.baserate
= 1;
3856 cam
->params
.yuvThreshold
.yThreshold
= 6; /* From windows driver */
3857 cam
->params
.yuvThreshold
.uvThreshold
= 6; /* From windows driver */
3859 cam
->params
.format
.subSample
= SUBSAMPLE_422
;
3860 cam
->params
.format
.yuvOrder
= YUVORDER_YUYV
;
3862 cam
->params
.compression
.mode
= CPIA_COMPRESSION_AUTO
;
3863 cam
->params
.compressionTarget
.frTargeting
=
3864 CPIA_COMPRESSION_TARGET_QUALITY
;
3865 cam
->params
.compressionTarget
.targetFR
= 15; /* From windows driver */
3866 cam
->params
.compressionTarget
.targetQ
= 5; /* From windows driver */
3868 cam
->params
.qx3
.qx3_detected
= 0;
3869 cam
->params
.qx3
.toplight
= 0;
3870 cam
->params
.qx3
.bottomlight
= 0;
3871 cam
->params
.qx3
.button
= 0;
3872 cam
->params
.qx3
.cradled
= 0;
3874 cam
->video_size
= VIDEOSIZE_CIF
;
3876 cam
->vp
.colour
= 32768; /* 50% */
3877 cam
->vp
.hue
= 32768; /* 50% */
3878 cam
->vp
.brightness
= 32768; /* 50% */
3879 cam
->vp
.contrast
= 32768; /* 50% */
3880 cam
->vp
.whiteness
= 0; /* not used -> grayscale only */
3881 cam
->vp
.depth
= 24; /* to be set by user */
3882 cam
->vp
.palette
= VIDEO_PALETTE_RGB24
; /* to be set by user */
3892 cam
->vw
.chromakey
= 0;
3894 cam
->vw
.clipcount
= 0;
3895 cam
->vw
.clips
= NULL
;
3897 cam
->cmd_queue
= COMMAND_NONE
;
3898 cam
->first_frame
= 1;
3903 /* initialize cam_data structure */
3904 static void init_camera_struct(struct cam_data
*cam
,
3905 struct cpia_camera_ops
*ops
)
3909 /* Default everything to 0 */
3910 memset(cam
, 0, sizeof(struct cam_data
));
3913 mutex_init(&cam
->param_lock
);
3914 mutex_init(&cam
->busy_lock
);
3916 reset_camera_struct(cam
);
3918 cam
->proc_entry
= NULL
;
3920 memcpy(&cam
->vdev
, &cpia_template
, sizeof(cpia_template
));
3921 video_set_drvdata(&cam
->vdev
, cam
);
3924 for (i
= 0; i
< FRAME_NUM
; i
++) {
3925 cam
->frame
[i
].width
= 0;
3926 cam
->frame
[i
].height
= 0;
3927 cam
->frame
[i
].state
= FRAME_UNUSED
;
3928 cam
->frame
[i
].data
= NULL
;
3930 cam
->decompressed_frame
.width
= 0;
3931 cam
->decompressed_frame
.height
= 0;
3932 cam
->decompressed_frame
.state
= FRAME_UNUSED
;
3933 cam
->decompressed_frame
.data
= NULL
;
3936 struct cam_data
*cpia_register_camera(struct cpia_camera_ops
*ops
, void *lowlevel
)
3938 struct cam_data
*camera
;
3940 if ((camera
= kmalloc(sizeof(struct cam_data
), GFP_KERNEL
)) == NULL
)
3944 init_camera_struct( camera
, ops
);
3945 camera
->lowlevel_data
= lowlevel
;
3947 /* register v4l device */
3948 if (video_register_device(&camera
->vdev
, VFL_TYPE_GRABBER
, video_nr
) < 0) {
3950 printk(KERN_DEBUG
"video_register_device failed\n");
3954 /* get version information from camera: open/reset/close */
3957 if (camera
->ops
->open(camera
->lowlevel_data
))
3960 /* reset the camera */
3961 if (reset_camera(camera
) != 0) {
3962 camera
->ops
->close(camera
->lowlevel_data
);
3967 camera
->ops
->close(camera
->lowlevel_data
);
3969 #ifdef CONFIG_PROC_FS
3970 create_proc_cpia_cam(camera
);
3973 printk(KERN_INFO
" CPiA Version: %d.%02d (%d.%d)\n",
3974 camera
->params
.version
.firmwareVersion
,
3975 camera
->params
.version
.firmwareRevision
,
3976 camera
->params
.version
.vcVersion
,
3977 camera
->params
.version
.vcRevision
);
3978 printk(KERN_INFO
" CPiA PnP-ID: %04x:%04x:%04x\n",
3979 camera
->params
.pnpID
.vendor
,
3980 camera
->params
.pnpID
.product
,
3981 camera
->params
.pnpID
.deviceRevision
);
3982 printk(KERN_INFO
" VP-Version: %d.%d %04x\n",
3983 camera
->params
.vpVersion
.vpVersion
,
3984 camera
->params
.vpVersion
.vpRevision
,
3985 camera
->params
.vpVersion
.cameraHeadID
);
3990 void cpia_unregister_camera(struct cam_data
*cam
)
3992 DBG("unregistering video\n");
3993 video_unregister_device(&cam
->vdev
);
3994 if (cam
->open_count
) {
3996 DBG("camera open -- setting ops to NULL\n");
4000 #ifdef CONFIG_PROC_FS
4001 DBG("destroying /proc/cpia/video%d\n", cam
->vdev
.num
);
4002 destroy_proc_cpia_cam(cam
);
4004 if (!cam
->open_count
) {
4005 DBG("freeing camera\n");
4010 static int __init
cpia_init(void)
4012 printk(KERN_INFO
"%s v%d.%d.%d\n", ABOUT
,
4013 CPIA_MAJ_VER
, CPIA_MIN_VER
, CPIA_PATCH_VER
);
4015 printk(KERN_WARNING
"Since in-kernel colorspace conversion is not "
4016 "allowed, it is disabled by default now. Users should fix the "
4017 "applications in case they don't work without conversion "
4018 "reenabled by setting the 'colorspace_conv' module "
4019 "parameter to 1\n");
4021 #ifdef CONFIG_PROC_FS
4028 static void __exit
cpia_exit(void)
4030 #ifdef CONFIG_PROC_FS
4031 proc_cpia_destroy();
4035 module_init(cpia_init
);
4036 module_exit(cpia_exit
);
4038 /* Exported symbols for modules. */
4040 EXPORT_SYMBOL(cpia_register_camera
);
4041 EXPORT_SYMBOL(cpia_unregister_camera
);