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 */
29 #include <linux/config.h>
31 #include <linux/module.h>
32 #include <linux/moduleparam.h>
33 #include <linux/init.h>
35 #include <linux/vmalloc.h>
36 #include <linux/slab.h>
37 #include <linux/proc_fs.h>
38 #include <linux/ctype.h>
39 #include <linux/pagemap.h>
41 #include <asm/semaphore.h>
44 #include <linux/kmod.h>
49 #ifdef CONFIG_VIDEO_CPIA_PP
50 extern int cpia_pp_init(void);
52 #ifdef CONFIG_VIDEO_CPIA_USB
53 extern int cpia_usb_init(void);
56 static int video_nr
= -1;
59 MODULE_PARM(video_nr
,"i");
60 MODULE_AUTHOR("Scott J. Bertin <sbertin@securenym.net> & Peter Pregler <Peter_Pregler@email.com> & Johannes Erdfelt <johannes@erdfeld.com>");
61 MODULE_DESCRIPTION("V4L-driver for Vision CPiA based cameras");
62 MODULE_LICENSE("GPL");
63 MODULE_SUPPORTED_DEVICE("video");
66 static unsigned short colorspace_conv
= 0;
67 module_param(colorspace_conv
, ushort
, 0444);
68 MODULE_PARM_DESC(colorspace_conv
,
69 "\n<n> Colorspace conversion:"
72 "\nDefault value is 0"
75 #define ABOUT "V4L-Driver for Vision CPiA based cameras"
77 #ifndef VID_HARDWARE_CPIA
78 #define VID_HARDWARE_CPIA 24 /* FIXME -> from linux/videodev.h */
81 #define CPIA_MODULE_CPIA (0<<5)
82 #define CPIA_MODULE_SYSTEM (1<<5)
83 #define CPIA_MODULE_VP_CTRL (5<<5)
84 #define CPIA_MODULE_CAPTURE (6<<5)
85 #define CPIA_MODULE_DEBUG (7<<5)
87 #define INPUT (DATA_IN << 8)
88 #define OUTPUT (DATA_OUT << 8)
90 #define CPIA_COMMAND_GetCPIAVersion (INPUT | CPIA_MODULE_CPIA | 1)
91 #define CPIA_COMMAND_GetPnPID (INPUT | CPIA_MODULE_CPIA | 2)
92 #define CPIA_COMMAND_GetCameraStatus (INPUT | CPIA_MODULE_CPIA | 3)
93 #define CPIA_COMMAND_GotoHiPower (OUTPUT | CPIA_MODULE_CPIA | 4)
94 #define CPIA_COMMAND_GotoLoPower (OUTPUT | CPIA_MODULE_CPIA | 5)
95 #define CPIA_COMMAND_GotoSuspend (OUTPUT | CPIA_MODULE_CPIA | 7)
96 #define CPIA_COMMAND_GotoPassThrough (OUTPUT | CPIA_MODULE_CPIA | 8)
97 #define CPIA_COMMAND_ModifyCameraStatus (OUTPUT | CPIA_MODULE_CPIA | 10)
99 #define CPIA_COMMAND_ReadVCRegs (INPUT | CPIA_MODULE_SYSTEM | 1)
100 #define CPIA_COMMAND_WriteVCReg (OUTPUT | CPIA_MODULE_SYSTEM | 2)
101 #define CPIA_COMMAND_ReadMCPorts (INPUT | CPIA_MODULE_SYSTEM | 3)
102 #define CPIA_COMMAND_WriteMCPort (OUTPUT | CPIA_MODULE_SYSTEM | 4)
103 #define CPIA_COMMAND_SetBaudRate (OUTPUT | CPIA_MODULE_SYSTEM | 5)
104 #define CPIA_COMMAND_SetECPTiming (OUTPUT | CPIA_MODULE_SYSTEM | 6)
105 #define CPIA_COMMAND_ReadIDATA (INPUT | CPIA_MODULE_SYSTEM | 7)
106 #define CPIA_COMMAND_WriteIDATA (OUTPUT | CPIA_MODULE_SYSTEM | 8)
107 #define CPIA_COMMAND_GenericCall (OUTPUT | CPIA_MODULE_SYSTEM | 9)
108 #define CPIA_COMMAND_I2CStart (OUTPUT | CPIA_MODULE_SYSTEM | 10)
109 #define CPIA_COMMAND_I2CStop (OUTPUT | CPIA_MODULE_SYSTEM | 11)
110 #define CPIA_COMMAND_I2CWrite (OUTPUT | CPIA_MODULE_SYSTEM | 12)
111 #define CPIA_COMMAND_I2CRead (INPUT | CPIA_MODULE_SYSTEM | 13)
113 #define CPIA_COMMAND_GetVPVersion (INPUT | CPIA_MODULE_VP_CTRL | 1)
114 #define CPIA_COMMAND_ResetFrameCounter (INPUT | CPIA_MODULE_VP_CTRL | 2)
115 #define CPIA_COMMAND_SetColourParams (OUTPUT | CPIA_MODULE_VP_CTRL | 3)
116 #define CPIA_COMMAND_SetExposure (OUTPUT | CPIA_MODULE_VP_CTRL | 4)
117 #define CPIA_COMMAND_SetColourBalance (OUTPUT | CPIA_MODULE_VP_CTRL | 6)
118 #define CPIA_COMMAND_SetSensorFPS (OUTPUT | CPIA_MODULE_VP_CTRL | 7)
119 #define CPIA_COMMAND_SetVPDefaults (OUTPUT | CPIA_MODULE_VP_CTRL | 8)
120 #define CPIA_COMMAND_SetApcor (OUTPUT | CPIA_MODULE_VP_CTRL | 9)
121 #define CPIA_COMMAND_SetFlickerCtrl (OUTPUT | CPIA_MODULE_VP_CTRL | 10)
122 #define CPIA_COMMAND_SetVLOffset (OUTPUT | CPIA_MODULE_VP_CTRL | 11)
123 #define CPIA_COMMAND_GetColourParams (INPUT | CPIA_MODULE_VP_CTRL | 16)
124 #define CPIA_COMMAND_GetColourBalance (INPUT | CPIA_MODULE_VP_CTRL | 17)
125 #define CPIA_COMMAND_GetExposure (INPUT | CPIA_MODULE_VP_CTRL | 18)
126 #define CPIA_COMMAND_SetSensorMatrix (OUTPUT | CPIA_MODULE_VP_CTRL | 19)
127 #define CPIA_COMMAND_ColourBars (OUTPUT | CPIA_MODULE_VP_CTRL | 25)
128 #define CPIA_COMMAND_ReadVPRegs (INPUT | CPIA_MODULE_VP_CTRL | 30)
129 #define CPIA_COMMAND_WriteVPReg (OUTPUT | CPIA_MODULE_VP_CTRL | 31)
131 #define CPIA_COMMAND_GrabFrame (OUTPUT | CPIA_MODULE_CAPTURE | 1)
132 #define CPIA_COMMAND_UploadFrame (OUTPUT | CPIA_MODULE_CAPTURE | 2)
133 #define CPIA_COMMAND_SetGrabMode (OUTPUT | CPIA_MODULE_CAPTURE | 3)
134 #define CPIA_COMMAND_InitStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 4)
135 #define CPIA_COMMAND_FiniStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 5)
136 #define CPIA_COMMAND_StartStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 6)
137 #define CPIA_COMMAND_EndStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 7)
138 #define CPIA_COMMAND_SetFormat (OUTPUT | CPIA_MODULE_CAPTURE | 8)
139 #define CPIA_COMMAND_SetROI (OUTPUT | CPIA_MODULE_CAPTURE | 9)
140 #define CPIA_COMMAND_SetCompression (OUTPUT | CPIA_MODULE_CAPTURE | 10)
141 #define CPIA_COMMAND_SetCompressionTarget (OUTPUT | CPIA_MODULE_CAPTURE | 11)
142 #define CPIA_COMMAND_SetYUVThresh (OUTPUT | CPIA_MODULE_CAPTURE | 12)
143 #define CPIA_COMMAND_SetCompressionParams (OUTPUT | CPIA_MODULE_CAPTURE | 13)
144 #define CPIA_COMMAND_DiscardFrame (OUTPUT | CPIA_MODULE_CAPTURE | 14)
145 #define CPIA_COMMAND_GrabReset (OUTPUT | CPIA_MODULE_CAPTURE | 15)
147 #define CPIA_COMMAND_OutputRS232 (OUTPUT | CPIA_MODULE_DEBUG | 1)
148 #define CPIA_COMMAND_AbortProcess (OUTPUT | CPIA_MODULE_DEBUG | 4)
149 #define CPIA_COMMAND_SetDramPage (OUTPUT | CPIA_MODULE_DEBUG | 5)
150 #define CPIA_COMMAND_StartDramUpload (OUTPUT | CPIA_MODULE_DEBUG | 6)
151 #define CPIA_COMMAND_StartDummyDtream (OUTPUT | CPIA_MODULE_DEBUG | 8)
152 #define CPIA_COMMAND_AbortStream (OUTPUT | CPIA_MODULE_DEBUG | 9)
153 #define CPIA_COMMAND_DownloadDRAM (OUTPUT | CPIA_MODULE_DEBUG | 10)
154 #define CPIA_COMMAND_Null (OUTPUT | CPIA_MODULE_DEBUG | 11)
157 FRAME_READY
, /* Ready to grab into */
158 FRAME_GRABBING
, /* In the process of being grabbed into */
159 FRAME_DONE
, /* Finished grabbing, but not been synced yet */
160 FRAME_UNUSED
, /* Unused (no MCAPTURE) */
163 #define COMMAND_NONE 0x0000
164 #define COMMAND_SETCOMPRESSION 0x0001
165 #define COMMAND_SETCOMPRESSIONTARGET 0x0002
166 #define COMMAND_SETCOLOURPARAMS 0x0004
167 #define COMMAND_SETFORMAT 0x0008
168 #define COMMAND_PAUSE 0x0010
169 #define COMMAND_RESUME 0x0020
170 #define COMMAND_SETYUVTHRESH 0x0040
171 #define COMMAND_SETECPTIMING 0x0080
172 #define COMMAND_SETCOMPRESSIONPARAMS 0x0100
173 #define COMMAND_SETEXPOSURE 0x0200
174 #define COMMAND_SETCOLOURBALANCE 0x0400
175 #define COMMAND_SETSENSORFPS 0x0800
176 #define COMMAND_SETAPCOR 0x1000
177 #define COMMAND_SETFLICKERCTRL 0x2000
178 #define COMMAND_SETVLOFFSET 0x4000
179 #define COMMAND_SETLIGHTS 0x8000
181 #define ROUND_UP_EXP_FOR_FLICKER 15
183 /* Constants for automatic frame rate adjustment */
185 #define MAX_EXP_102 255
187 #define VERY_LOW_EXP 70
189 #define EXP_ACC_DARK 50
190 #define EXP_ACC_LIGHT 90
191 #define HIGH_COMP_102 160
196 /* Maximum number of 10ms loops to wait for the stream to become ready */
197 #define READY_TIMEOUT 100
199 /* Developer's Guide Table 5 p 3-34
200 * indexed by [mains][sensorFps.baserate][sensorFps.divisor]*/
201 static u8 flicker_jumps
[2][2][4] =
202 { { { 76, 38, 19, 9 }, { 92, 46, 23, 11 } },
203 { { 64, 32, 16, 8 }, { 76, 38, 19, 9} }
206 /* forward declaration of local function */
207 static void reset_camera_struct(struct cam_data
*cam
);
208 static int find_over_exposure(int brightness
);
209 static void set_flicker(struct cam_params
*params
, volatile u32
*command_flags
,
213 /**********************************************************************
217 **********************************************************************/
219 /* Here we want the physical address of the memory.
220 * This is used when initializing the contents of the area.
222 static inline unsigned long kvirt_to_pa(unsigned long adr
)
224 unsigned long kva
, ret
;
226 kva
= (unsigned long) page_address(vmalloc_to_page((void *)adr
));
227 kva
|= adr
& (PAGE_SIZE
-1); /* restore the offset */
232 static void *rvmalloc(unsigned long size
)
237 size
= PAGE_ALIGN(size
);
238 mem
= vmalloc_32(size
);
242 memset(mem
, 0, size
); /* Clear the ram out, no junk to the user */
243 adr
= (unsigned long) mem
;
245 SetPageReserved(vmalloc_to_page((void *)adr
));
253 static void rvfree(void *mem
, unsigned long size
)
260 adr
= (unsigned long) mem
;
261 while ((long) size
> 0) {
262 ClearPageReserved(vmalloc_to_page((void *)adr
));
269 /**********************************************************************
273 **********************************************************************/
274 #ifdef CONFIG_PROC_FS
275 static struct proc_dir_entry
*cpia_proc_root
=NULL
;
277 static int cpia_read_proc(char *page
, char **start
, off_t off
,
278 int count
, int *eof
, void *data
)
282 struct cam_data
*cam
= data
;
285 /* IMPORTANT: This output MUST be kept under PAGE_SIZE
286 * or we need to get more sophisticated. */
288 out
+= sprintf(out
, "read-only\n-----------------------\n");
289 out
+= sprintf(out
, "V4L Driver version: %d.%d.%d\n",
290 CPIA_MAJ_VER
, CPIA_MIN_VER
, CPIA_PATCH_VER
);
291 out
+= sprintf(out
, "CPIA Version: %d.%02d (%d.%d)\n",
292 cam
->params
.version
.firmwareVersion
,
293 cam
->params
.version
.firmwareRevision
,
294 cam
->params
.version
.vcVersion
,
295 cam
->params
.version
.vcRevision
);
296 out
+= sprintf(out
, "CPIA PnP-ID: %04x:%04x:%04x\n",
297 cam
->params
.pnpID
.vendor
, cam
->params
.pnpID
.product
,
298 cam
->params
.pnpID
.deviceRevision
);
299 out
+= sprintf(out
, "VP-Version: %d.%d %04x\n",
300 cam
->params
.vpVersion
.vpVersion
,
301 cam
->params
.vpVersion
.vpRevision
,
302 cam
->params
.vpVersion
.cameraHeadID
);
304 out
+= sprintf(out
, "system_state: %#04x\n",
305 cam
->params
.status
.systemState
);
306 out
+= sprintf(out
, "grab_state: %#04x\n",
307 cam
->params
.status
.grabState
);
308 out
+= sprintf(out
, "stream_state: %#04x\n",
309 cam
->params
.status
.streamState
);
310 out
+= sprintf(out
, "fatal_error: %#04x\n",
311 cam
->params
.status
.fatalError
);
312 out
+= sprintf(out
, "cmd_error: %#04x\n",
313 cam
->params
.status
.cmdError
);
314 out
+= sprintf(out
, "debug_flags: %#04x\n",
315 cam
->params
.status
.debugFlags
);
316 out
+= sprintf(out
, "vp_status: %#04x\n",
317 cam
->params
.status
.vpStatus
);
318 out
+= sprintf(out
, "error_code: %#04x\n",
319 cam
->params
.status
.errorCode
);
320 /* QX3 specific entries */
321 if (cam
->params
.qx3
.qx3_detected
) {
322 out
+= sprintf(out
, "button: %4d\n",
323 cam
->params
.qx3
.button
);
324 out
+= sprintf(out
, "cradled: %4d\n",
325 cam
->params
.qx3
.cradled
);
327 out
+= sprintf(out
, "video_size: %s\n",
328 cam
->params
.format
.videoSize
== VIDEOSIZE_CIF
?
330 out
+= sprintf(out
, "roi: (%3d, %3d) to (%3d, %3d)\n",
331 cam
->params
.roi
.colStart
*8,
332 cam
->params
.roi
.rowStart
*4,
333 cam
->params
.roi
.colEnd
*8,
334 cam
->params
.roi
.rowEnd
*4);
335 out
+= sprintf(out
, "actual_fps: %3d\n", cam
->fps
);
336 out
+= sprintf(out
, "transfer_rate: %4dkB/s\n",
339 out
+= sprintf(out
, "\nread-write\n");
340 out
+= sprintf(out
, "----------------------- current min"
341 " max default comment\n");
342 out
+= sprintf(out
, "brightness: %8d %8d %8d %8d\n",
343 cam
->params
.colourParams
.brightness
, 0, 100, 50);
344 if (cam
->params
.version
.firmwareVersion
== 1 &&
345 cam
->params
.version
.firmwareRevision
== 2)
346 /* 1-02 firmware limits contrast to 80 */
351 out
+= sprintf(out
, "contrast: %8d %8d %8d %8d"
353 cam
->params
.colourParams
.contrast
, 0, tmp
, 48);
354 out
+= sprintf(out
, "saturation: %8d %8d %8d %8d\n",
355 cam
->params
.colourParams
.saturation
, 0, 100, 50);
356 tmp
= (25000+5000*cam
->params
.sensorFps
.baserate
)/
357 (1<<cam
->params
.sensorFps
.divisor
);
358 out
+= sprintf(out
, "sensor_fps: %4d.%03d %8d %8d %8d\n",
359 tmp
/1000, tmp
%1000, 3, 30, 15);
360 out
+= sprintf(out
, "stream_start_line: %8d %8d %8d %8d\n",
361 2*cam
->params
.streamStartLine
, 0,
362 cam
->params
.format
.videoSize
== VIDEOSIZE_CIF
? 288:144,
363 cam
->params
.format
.videoSize
== VIDEOSIZE_CIF
? 240:120);
364 out
+= sprintf(out
, "sub_sample: %8s %8s %8s %8s\n",
365 cam
->params
.format
.subSample
== SUBSAMPLE_420
?
366 "420" : "422", "420", "422", "422");
367 out
+= sprintf(out
, "yuv_order: %8s %8s %8s %8s\n",
368 cam
->params
.format
.yuvOrder
== YUVORDER_YUYV
?
369 "YUYV" : "UYVY", "YUYV" , "UYVY", "YUYV");
370 out
+= sprintf(out
, "ecp_timing: %8s %8s %8s %8s\n",
371 cam
->params
.ecpTiming
? "slow" : "normal", "slow",
374 if (cam
->params
.colourBalance
.balanceMode
== 2) {
375 sprintf(tmpstr
, "auto");
377 sprintf(tmpstr
, "manual");
379 out
+= sprintf(out
, "color_balance_mode: %8s %8s %8s"
380 " %8s\n", tmpstr
, "manual", "auto", "auto");
381 out
+= sprintf(out
, "red_gain: %8d %8d %8d %8d\n",
382 cam
->params
.colourBalance
.redGain
, 0, 212, 32);
383 out
+= sprintf(out
, "green_gain: %8d %8d %8d %8d\n",
384 cam
->params
.colourBalance
.greenGain
, 0, 212, 6);
385 out
+= sprintf(out
, "blue_gain: %8d %8d %8d %8d\n",
386 cam
->params
.colourBalance
.blueGain
, 0, 212, 92);
388 if (cam
->params
.version
.firmwareVersion
== 1 &&
389 cam
->params
.version
.firmwareRevision
== 2)
390 /* 1-02 firmware limits gain to 2 */
391 sprintf(tmpstr
, "%8d %8d %8d", 1, 2, 2);
393 sprintf(tmpstr
, "%8d %8d %8d", 1, 8, 2);
395 if (cam
->params
.exposure
.gainMode
== 0)
396 out
+= sprintf(out
, "max_gain: unknown %28s"
397 " powers of 2\n", tmpstr
);
399 out
+= sprintf(out
, "max_gain: %8d %28s"
401 1<<(cam
->params
.exposure
.gainMode
-1), tmpstr
);
403 switch(cam
->params
.exposure
.expMode
) {
406 sprintf(tmpstr
, "manual");
409 sprintf(tmpstr
, "auto");
412 sprintf(tmpstr
, "unknown");
415 out
+= sprintf(out
, "exposure_mode: %8s %8s %8s"
416 " %8s\n", tmpstr
, "manual", "auto", "auto");
417 out
+= sprintf(out
, "centre_weight: %8s %8s %8s %8s\n",
418 (2-cam
->params
.exposure
.centreWeight
) ? "on" : "off",
420 out
+= sprintf(out
, "gain: %8d %8d max_gain %8d 1,2,4,8 possible\n",
421 1<<cam
->params
.exposure
.gain
, 1, 1);
422 if (cam
->params
.version
.firmwareVersion
== 1 &&
423 cam
->params
.version
.firmwareRevision
== 2)
424 /* 1-02 firmware limits fineExp/2 to 127 */
429 out
+= sprintf(out
, "fine_exp: %8d %8d %8d %8d\n",
430 cam
->params
.exposure
.fineExp
*2, 0, tmp
, 0);
431 if (cam
->params
.version
.firmwareVersion
== 1 &&
432 cam
->params
.version
.firmwareRevision
== 2)
433 /* 1-02 firmware limits coarseExpHi to 0 */
438 out
+= sprintf(out
, "coarse_exp: %8d %8d %8d"
439 " %8d\n", cam
->params
.exposure
.coarseExpLo
+
440 256*cam
->params
.exposure
.coarseExpHi
, 0, tmp
, 185);
441 out
+= sprintf(out
, "red_comp: %8d %8d %8d %8d\n",
442 cam
->params
.exposure
.redComp
, COMP_RED
, 255, COMP_RED
);
443 out
+= sprintf(out
, "green1_comp: %8d %8d %8d %8d\n",
444 cam
->params
.exposure
.green1Comp
, COMP_GREEN1
, 255,
446 out
+= sprintf(out
, "green2_comp: %8d %8d %8d %8d\n",
447 cam
->params
.exposure
.green2Comp
, COMP_GREEN2
, 255,
449 out
+= sprintf(out
, "blue_comp: %8d %8d %8d %8d\n",
450 cam
->params
.exposure
.blueComp
, COMP_BLUE
, 255, COMP_BLUE
);
452 out
+= sprintf(out
, "apcor_gain1: %#8x %#8x %#8x %#8x\n",
453 cam
->params
.apcor
.gain1
, 0, 0xff, 0x1c);
454 out
+= sprintf(out
, "apcor_gain2: %#8x %#8x %#8x %#8x\n",
455 cam
->params
.apcor
.gain2
, 0, 0xff, 0x1a);
456 out
+= sprintf(out
, "apcor_gain4: %#8x %#8x %#8x %#8x\n",
457 cam
->params
.apcor
.gain4
, 0, 0xff, 0x2d);
458 out
+= sprintf(out
, "apcor_gain8: %#8x %#8x %#8x %#8x\n",
459 cam
->params
.apcor
.gain8
, 0, 0xff, 0x2a);
460 out
+= sprintf(out
, "vl_offset_gain1: %8d %8d %8d %8d\n",
461 cam
->params
.vlOffset
.gain1
, 0, 255, 24);
462 out
+= sprintf(out
, "vl_offset_gain2: %8d %8d %8d %8d\n",
463 cam
->params
.vlOffset
.gain2
, 0, 255, 28);
464 out
+= sprintf(out
, "vl_offset_gain4: %8d %8d %8d %8d\n",
465 cam
->params
.vlOffset
.gain4
, 0, 255, 30);
466 out
+= sprintf(out
, "vl_offset_gain8: %8d %8d %8d %8d\n",
467 cam
->params
.vlOffset
.gain8
, 0, 255, 30);
468 out
+= sprintf(out
, "flicker_control: %8s %8s %8s %8s\n",
469 cam
->params
.flickerControl
.flickerMode
? "on" : "off",
471 out
+= sprintf(out
, "mains_frequency: %8d %8d %8d %8d"
473 cam
->mainsFreq
? 60 : 50, 50, 60, 50);
474 if(cam
->params
.flickerControl
.allowableOverExposure
< 0)
475 out
+= sprintf(out
, "allowable_overexposure: %4dauto auto %8d auto\n",
476 -cam
->params
.flickerControl
.allowableOverExposure
,
479 out
+= sprintf(out
, "allowable_overexposure: %8d auto %8d auto\n",
480 cam
->params
.flickerControl
.allowableOverExposure
,
482 out
+= sprintf(out
, "compression_mode: ");
483 switch(cam
->params
.compression
.mode
) {
484 case CPIA_COMPRESSION_NONE
:
485 out
+= sprintf(out
, "%8s", "none");
487 case CPIA_COMPRESSION_AUTO
:
488 out
+= sprintf(out
, "%8s", "auto");
490 case CPIA_COMPRESSION_MANUAL
:
491 out
+= sprintf(out
, "%8s", "manual");
494 out
+= sprintf(out
, "%8s", "unknown");
497 out
+= sprintf(out
, " none,auto,manual auto\n");
498 out
+= sprintf(out
, "decimation_enable: %8s %8s %8s %8s\n",
499 cam
->params
.compression
.decimation
==
500 DECIMATION_ENAB
? "on":"off", "off", "on",
502 out
+= sprintf(out
, "compression_target: %9s %9s %9s %9s\n",
503 cam
->params
.compressionTarget
.frTargeting
==
504 CPIA_COMPRESSION_TARGET_FRAMERATE
?
505 "framerate":"quality",
506 "framerate", "quality", "quality");
507 out
+= sprintf(out
, "target_framerate: %8d %8d %8d %8d\n",
508 cam
->params
.compressionTarget
.targetFR
, 1, 30, 15);
509 out
+= sprintf(out
, "target_quality: %8d %8d %8d %8d\n",
510 cam
->params
.compressionTarget
.targetQ
, 1, 64, 5);
511 out
+= sprintf(out
, "y_threshold: %8d %8d %8d %8d\n",
512 cam
->params
.yuvThreshold
.yThreshold
, 0, 31, 6);
513 out
+= sprintf(out
, "uv_threshold: %8d %8d %8d %8d\n",
514 cam
->params
.yuvThreshold
.uvThreshold
, 0, 31, 6);
515 out
+= sprintf(out
, "hysteresis: %8d %8d %8d %8d\n",
516 cam
->params
.compressionParams
.hysteresis
, 0, 255, 3);
517 out
+= sprintf(out
, "threshold_max: %8d %8d %8d %8d\n",
518 cam
->params
.compressionParams
.threshMax
, 0, 255, 11);
519 out
+= sprintf(out
, "small_step: %8d %8d %8d %8d\n",
520 cam
->params
.compressionParams
.smallStep
, 0, 255, 1);
521 out
+= sprintf(out
, "large_step: %8d %8d %8d %8d\n",
522 cam
->params
.compressionParams
.largeStep
, 0, 255, 3);
523 out
+= sprintf(out
, "decimation_hysteresis: %8d %8d %8d %8d\n",
524 cam
->params
.compressionParams
.decimationHysteresis
,
526 out
+= sprintf(out
, "fr_diff_step_thresh: %8d %8d %8d %8d\n",
527 cam
->params
.compressionParams
.frDiffStepThresh
,
529 out
+= sprintf(out
, "q_diff_step_thresh: %8d %8d %8d %8d\n",
530 cam
->params
.compressionParams
.qDiffStepThresh
,
532 out
+= sprintf(out
, "decimation_thresh_mod: %8d %8d %8d %8d\n",
533 cam
->params
.compressionParams
.decimationThreshMod
,
535 /* QX3 specific entries */
536 if (cam
->params
.qx3
.qx3_detected
) {
537 out
+= sprintf(out
, "toplight: %8s %8s %8s %8s\n",
538 cam
->params
.qx3
.toplight
? "on" : "off",
540 out
+= sprintf(out
, "bottomlight: %8s %8s %8s %8s\n",
541 cam
->params
.qx3
.bottomlight
? "on" : "off",
549 if (len
<= 0) return 0;
558 static int match(char *checkstr
, char **buffer
, unsigned long *count
,
559 int *find_colon
, int *err
)
561 int ret
, colon_found
= 1;
562 int len
= strlen(checkstr
);
563 ret
= (len
<= *count
&& strncmp(*buffer
, checkstr
, len
) == 0);
569 while (*count
&& (**buffer
== ' ' || **buffer
== '\t' ||
570 (!colon_found
&& **buffer
== ':'))) {
576 if (!*count
|| !colon_found
)
584 static unsigned long int value(char **buffer
, unsigned long *count
, int *err
)
587 unsigned long int ret
;
588 ret
= simple_strtoul(*buffer
, &p
, 0);
592 *count
-= p
- *buffer
;
598 static int cpia_write_proc(struct file
*file
, const char __user
*buf
,
599 unsigned long count
, void *data
)
601 struct cam_data
*cam
= data
;
602 struct cam_params new_params
;
604 int retval
, find_colon
;
606 unsigned long val
= 0;
607 u32 command_flags
= 0;
611 * This code to copy from buf to page is shamelessly copied
612 * from the comx driver
614 if (count
> PAGE_SIZE
) {
615 printk(KERN_ERR
"count is %lu > %d!!!\n", count
, (int)PAGE_SIZE
);
619 if (!(page
= (char *)__get_free_page(GFP_KERNEL
))) return -ENOMEM
;
621 if(copy_from_user(page
, buf
, count
))
627 if (page
[count
-1] == '\n')
628 page
[count
-1] = '\0';
629 else if (count
< PAGE_SIZE
)
631 else if (page
[count
]) {
638 if (down_interruptible(&cam
->param_lock
))
642 * Skip over leading whitespace
644 while (count
&& isspace(*buffer
)) {
649 memcpy(&new_params
, &cam
->params
, sizeof(struct cam_params
));
650 new_mains
= cam
->mainsFreq
;
652 #define MATCH(x) (match(x, &buffer, &count, &find_colon, &retval))
653 #define VALUE (value(&buffer,&count, &retval))
654 #define FIRMWARE_VERSION(x,y) (new_params.version.firmwareVersion == (x) && \
655 new_params.version.firmwareRevision == (y))
658 while (count
&& !retval
) {
660 if (MATCH("brightness")) {
666 new_params
.colourParams
.brightness
= val
;
670 command_flags
|= COMMAND_SETCOLOURPARAMS
;
671 if(new_params
.flickerControl
.allowableOverExposure
< 0)
672 new_params
.flickerControl
.allowableOverExposure
=
673 -find_over_exposure(new_params
.colourParams
.brightness
);
674 if(new_params
.flickerControl
.flickerMode
!= 0)
675 command_flags
|= COMMAND_SETFLICKERCTRL
;
677 } else if (MATCH("contrast")) {
683 /* contrast is in steps of 8, so round*/
684 val
= ((val
+ 3) / 8) * 8;
685 /* 1-02 firmware limits contrast to 80*/
686 if (FIRMWARE_VERSION(1,2) && val
> 80)
689 new_params
.colourParams
.contrast
= val
;
693 command_flags
|= COMMAND_SETCOLOURPARAMS
;
694 } else if (MATCH("saturation")) {
700 new_params
.colourParams
.saturation
= val
;
704 command_flags
|= COMMAND_SETCOLOURPARAMS
;
705 } else if (MATCH("sensor_fps")) {
710 /* find values so that sensorFPS is minimized,
715 new_params
.sensorFps
.divisor
= 0;
716 new_params
.sensorFps
.baserate
= 1;
717 } else if (val
> 15) {
718 new_params
.sensorFps
.divisor
= 0;
719 new_params
.sensorFps
.baserate
= 0;
720 } else if (val
> 12) {
721 new_params
.sensorFps
.divisor
= 1;
722 new_params
.sensorFps
.baserate
= 1;
723 } else if (val
> 7) {
724 new_params
.sensorFps
.divisor
= 1;
725 new_params
.sensorFps
.baserate
= 0;
726 } else if (val
> 6) {
727 new_params
.sensorFps
.divisor
= 2;
728 new_params
.sensorFps
.baserate
= 1;
729 } else if (val
> 3) {
730 new_params
.sensorFps
.divisor
= 2;
731 new_params
.sensorFps
.baserate
= 0;
733 new_params
.sensorFps
.divisor
= 3;
734 /* Either base rate would work here */
735 new_params
.sensorFps
.baserate
= 1;
737 new_params
.flickerControl
.coarseJump
=
738 flicker_jumps
[new_mains
]
739 [new_params
.sensorFps
.baserate
]
740 [new_params
.sensorFps
.divisor
];
741 if (new_params
.flickerControl
.flickerMode
)
742 command_flags
|= COMMAND_SETFLICKERCTRL
;
744 command_flags
|= COMMAND_SETSENSORFPS
;
745 cam
->exposure_status
= EXPOSURE_NORMAL
;
746 } else if (MATCH("stream_start_line")) {
753 if (new_params
.format
.videoSize
== VIDEOSIZE_QCIF
)
756 new_params
.streamStartLine
= val
/2;
760 } else if (MATCH("sub_sample")) {
761 if (!retval
&& MATCH("420"))
762 new_params
.format
.subSample
= SUBSAMPLE_420
;
763 else if (!retval
&& MATCH("422"))
764 new_params
.format
.subSample
= SUBSAMPLE_422
;
768 command_flags
|= COMMAND_SETFORMAT
;
769 } else if (MATCH("yuv_order")) {
770 if (!retval
&& MATCH("YUYV"))
771 new_params
.format
.yuvOrder
= YUVORDER_YUYV
;
772 else if (!retval
&& MATCH("UYVY"))
773 new_params
.format
.yuvOrder
= YUVORDER_UYVY
;
777 command_flags
|= COMMAND_SETFORMAT
;
778 } else if (MATCH("ecp_timing")) {
779 if (!retval
&& MATCH("normal"))
780 new_params
.ecpTiming
= 0;
781 else if (!retval
&& MATCH("slow"))
782 new_params
.ecpTiming
= 1;
786 command_flags
|= COMMAND_SETECPTIMING
;
787 } else if (MATCH("color_balance_mode")) {
788 if (!retval
&& MATCH("manual"))
789 new_params
.colourBalance
.balanceMode
= 3;
790 else if (!retval
&& MATCH("auto"))
791 new_params
.colourBalance
.balanceMode
= 2;
795 command_flags
|= COMMAND_SETCOLOURBALANCE
;
796 } else if (MATCH("red_gain")) {
802 new_params
.colourBalance
.redGain
= val
;
803 new_params
.colourBalance
.balanceMode
= 1;
807 command_flags
|= COMMAND_SETCOLOURBALANCE
;
808 } else if (MATCH("green_gain")) {
814 new_params
.colourBalance
.greenGain
= val
;
815 new_params
.colourBalance
.balanceMode
= 1;
819 command_flags
|= COMMAND_SETCOLOURBALANCE
;
820 } else if (MATCH("blue_gain")) {
826 new_params
.colourBalance
.blueGain
= val
;
827 new_params
.colourBalance
.balanceMode
= 1;
831 command_flags
|= COMMAND_SETCOLOURBALANCE
;
832 } else if (MATCH("max_gain")) {
837 /* 1-02 firmware limits gain to 2 */
838 if (FIRMWARE_VERSION(1,2) && val
> 2)
842 new_params
.exposure
.gainMode
= 1;
845 new_params
.exposure
.gainMode
= 2;
848 new_params
.exposure
.gainMode
= 3;
851 new_params
.exposure
.gainMode
= 4;
858 command_flags
|= COMMAND_SETEXPOSURE
;
859 } else if (MATCH("exposure_mode")) {
860 if (!retval
&& MATCH("auto"))
861 new_params
.exposure
.expMode
= 2;
862 else if (!retval
&& MATCH("manual")) {
863 if (new_params
.exposure
.expMode
== 2)
864 new_params
.exposure
.expMode
= 3;
865 if(new_params
.flickerControl
.flickerMode
!= 0)
866 command_flags
|= COMMAND_SETFLICKERCTRL
;
867 new_params
.flickerControl
.flickerMode
= 0;
871 command_flags
|= COMMAND_SETEXPOSURE
;
872 } else if (MATCH("centre_weight")) {
873 if (!retval
&& MATCH("on"))
874 new_params
.exposure
.centreWeight
= 1;
875 else if (!retval
&& MATCH("off"))
876 new_params
.exposure
.centreWeight
= 2;
880 command_flags
|= COMMAND_SETEXPOSURE
;
881 } else if (MATCH("gain")) {
888 new_params
.exposure
.gain
= 0;
891 new_params
.exposure
.gain
= 1;
894 new_params
.exposure
.gain
= 2;
897 new_params
.exposure
.gain
= 3;
903 new_params
.exposure
.expMode
= 1;
904 if(new_params
.flickerControl
.flickerMode
!= 0)
905 command_flags
|= COMMAND_SETFLICKERCTRL
;
906 new_params
.flickerControl
.flickerMode
= 0;
907 command_flags
|= COMMAND_SETEXPOSURE
;
908 if (new_params
.exposure
.gain
>
909 new_params
.exposure
.gainMode
-1)
912 } else if (MATCH("fine_exp")) {
918 /* 1-02 firmware limits fineExp/2 to 127*/
919 if (FIRMWARE_VERSION(1,2) && val
> 127)
921 new_params
.exposure
.fineExp
= val
;
922 new_params
.exposure
.expMode
= 1;
923 command_flags
|= COMMAND_SETEXPOSURE
;
924 if(new_params
.flickerControl
.flickerMode
!= 0)
925 command_flags
|= COMMAND_SETFLICKERCTRL
;
926 new_params
.flickerControl
.flickerMode
= 0;
927 command_flags
|= COMMAND_SETFLICKERCTRL
;
931 } else if (MATCH("coarse_exp")) {
936 if (val
<= MAX_EXP
) {
937 if (FIRMWARE_VERSION(1,2) &&
940 new_params
.exposure
.coarseExpLo
=
942 new_params
.exposure
.coarseExpHi
=
944 new_params
.exposure
.expMode
= 1;
945 command_flags
|= COMMAND_SETEXPOSURE
;
946 if(new_params
.flickerControl
.flickerMode
!= 0)
947 command_flags
|= COMMAND_SETFLICKERCTRL
;
948 new_params
.flickerControl
.flickerMode
= 0;
949 command_flags
|= COMMAND_SETFLICKERCTRL
;
953 } else if (MATCH("red_comp")) {
958 if (val
>= COMP_RED
&& val
<= 255) {
959 new_params
.exposure
.redComp
= val
;
960 new_params
.exposure
.compMode
= 1;
961 command_flags
|= COMMAND_SETEXPOSURE
;
965 } else if (MATCH("green1_comp")) {
970 if (val
>= COMP_GREEN1
&& val
<= 255) {
971 new_params
.exposure
.green1Comp
= val
;
972 new_params
.exposure
.compMode
= 1;
973 command_flags
|= COMMAND_SETEXPOSURE
;
977 } else if (MATCH("green2_comp")) {
982 if (val
>= COMP_GREEN2
&& val
<= 255) {
983 new_params
.exposure
.green2Comp
= val
;
984 new_params
.exposure
.compMode
= 1;
985 command_flags
|= COMMAND_SETEXPOSURE
;
989 } else if (MATCH("blue_comp")) {
994 if (val
>= COMP_BLUE
&& val
<= 255) {
995 new_params
.exposure
.blueComp
= val
;
996 new_params
.exposure
.compMode
= 1;
997 command_flags
|= COMMAND_SETEXPOSURE
;
1001 } else if (MATCH("apcor_gain1")) {
1006 command_flags
|= COMMAND_SETAPCOR
;
1008 new_params
.apcor
.gain1
= val
;
1012 } else if (MATCH("apcor_gain2")) {
1017 command_flags
|= COMMAND_SETAPCOR
;
1019 new_params
.apcor
.gain2
= val
;
1023 } else if (MATCH("apcor_gain4")) {
1028 command_flags
|= COMMAND_SETAPCOR
;
1030 new_params
.apcor
.gain4
= val
;
1034 } else if (MATCH("apcor_gain8")) {
1039 command_flags
|= COMMAND_SETAPCOR
;
1041 new_params
.apcor
.gain8
= val
;
1045 } else if (MATCH("vl_offset_gain1")) {
1051 new_params
.vlOffset
.gain1
= val
;
1055 command_flags
|= COMMAND_SETVLOFFSET
;
1056 } else if (MATCH("vl_offset_gain2")) {
1062 new_params
.vlOffset
.gain2
= val
;
1066 command_flags
|= COMMAND_SETVLOFFSET
;
1067 } else if (MATCH("vl_offset_gain4")) {
1073 new_params
.vlOffset
.gain4
= val
;
1077 command_flags
|= COMMAND_SETVLOFFSET
;
1078 } else if (MATCH("vl_offset_gain8")) {
1084 new_params
.vlOffset
.gain8
= val
;
1088 command_flags
|= COMMAND_SETVLOFFSET
;
1089 } else if (MATCH("flicker_control")) {
1090 if (!retval
&& MATCH("on")) {
1091 set_flicker(&new_params
, &command_flags
, 1);
1092 } else if (!retval
&& MATCH("off")) {
1093 set_flicker(&new_params
, &command_flags
, 0);
1097 command_flags
|= COMMAND_SETFLICKERCTRL
;
1098 } else if (MATCH("mains_frequency")) {
1099 if (!retval
&& MATCH("50")) {
1101 new_params
.flickerControl
.coarseJump
=
1102 flicker_jumps
[new_mains
]
1103 [new_params
.sensorFps
.baserate
]
1104 [new_params
.sensorFps
.divisor
];
1105 if (new_params
.flickerControl
.flickerMode
)
1106 command_flags
|= COMMAND_SETFLICKERCTRL
;
1107 } else if (!retval
&& MATCH("60")) {
1109 new_params
.flickerControl
.coarseJump
=
1110 flicker_jumps
[new_mains
]
1111 [new_params
.sensorFps
.baserate
]
1112 [new_params
.sensorFps
.divisor
];
1113 if (new_params
.flickerControl
.flickerMode
)
1114 command_flags
|= COMMAND_SETFLICKERCTRL
;
1117 } else if (MATCH("allowable_overexposure")) {
1118 if (!retval
&& MATCH("auto")) {
1119 new_params
.flickerControl
.allowableOverExposure
=
1120 -find_over_exposure(new_params
.colourParams
.brightness
);
1121 if(new_params
.flickerControl
.flickerMode
!= 0)
1122 command_flags
|= COMMAND_SETFLICKERCTRL
;
1129 new_params
.flickerControl
.
1130 allowableOverExposure
= val
;
1131 if(new_params
.flickerControl
.flickerMode
!= 0)
1132 command_flags
|= COMMAND_SETFLICKERCTRL
;
1137 } else if (MATCH("compression_mode")) {
1138 if (!retval
&& MATCH("none"))
1139 new_params
.compression
.mode
=
1140 CPIA_COMPRESSION_NONE
;
1141 else if (!retval
&& MATCH("auto"))
1142 new_params
.compression
.mode
=
1143 CPIA_COMPRESSION_AUTO
;
1144 else if (!retval
&& MATCH("manual"))
1145 new_params
.compression
.mode
=
1146 CPIA_COMPRESSION_MANUAL
;
1150 command_flags
|= COMMAND_SETCOMPRESSION
;
1151 } else if (MATCH("decimation_enable")) {
1152 if (!retval
&& MATCH("off"))
1153 new_params
.compression
.decimation
= 0;
1154 else if (!retval
&& MATCH("on"))
1155 new_params
.compression
.decimation
= 1;
1159 command_flags
|= COMMAND_SETCOMPRESSION
;
1160 } else if (MATCH("compression_target")) {
1161 if (!retval
&& MATCH("quality"))
1162 new_params
.compressionTarget
.frTargeting
=
1163 CPIA_COMPRESSION_TARGET_QUALITY
;
1164 else if (!retval
&& MATCH("framerate"))
1165 new_params
.compressionTarget
.frTargeting
=
1166 CPIA_COMPRESSION_TARGET_FRAMERATE
;
1170 command_flags
|= COMMAND_SETCOMPRESSIONTARGET
;
1171 } else if (MATCH("target_framerate")) {
1176 if(val
> 0 && val
<= 30)
1177 new_params
.compressionTarget
.targetFR
= val
;
1181 command_flags
|= COMMAND_SETCOMPRESSIONTARGET
;
1182 } else if (MATCH("target_quality")) {
1187 if(val
> 0 && val
<= 64)
1188 new_params
.compressionTarget
.targetQ
= val
;
1192 command_flags
|= COMMAND_SETCOMPRESSIONTARGET
;
1193 } else if (MATCH("y_threshold")) {
1199 new_params
.yuvThreshold
.yThreshold
= val
;
1203 command_flags
|= COMMAND_SETYUVTHRESH
;
1204 } else if (MATCH("uv_threshold")) {
1210 new_params
.yuvThreshold
.uvThreshold
= val
;
1214 command_flags
|= COMMAND_SETYUVTHRESH
;
1215 } else if (MATCH("hysteresis")) {
1221 new_params
.compressionParams
.hysteresis
= val
;
1225 command_flags
|= COMMAND_SETCOMPRESSIONPARAMS
;
1226 } else if (MATCH("threshold_max")) {
1232 new_params
.compressionParams
.threshMax
= val
;
1236 command_flags
|= COMMAND_SETCOMPRESSIONPARAMS
;
1237 } else if (MATCH("small_step")) {
1243 new_params
.compressionParams
.smallStep
= val
;
1247 command_flags
|= COMMAND_SETCOMPRESSIONPARAMS
;
1248 } else if (MATCH("large_step")) {
1254 new_params
.compressionParams
.largeStep
= val
;
1258 command_flags
|= COMMAND_SETCOMPRESSIONPARAMS
;
1259 } else if (MATCH("decimation_hysteresis")) {
1265 new_params
.compressionParams
.decimationHysteresis
= val
;
1269 command_flags
|= COMMAND_SETCOMPRESSIONPARAMS
;
1270 } else if (MATCH("fr_diff_step_thresh")) {
1276 new_params
.compressionParams
.frDiffStepThresh
= val
;
1280 command_flags
|= COMMAND_SETCOMPRESSIONPARAMS
;
1281 } else if (MATCH("q_diff_step_thresh")) {
1287 new_params
.compressionParams
.qDiffStepThresh
= val
;
1291 command_flags
|= COMMAND_SETCOMPRESSIONPARAMS
;
1292 } else if (MATCH("decimation_thresh_mod")) {
1298 new_params
.compressionParams
.decimationThreshMod
= val
;
1302 command_flags
|= COMMAND_SETCOMPRESSIONPARAMS
;
1303 } else if (MATCH("toplight")) {
1304 if (!retval
&& MATCH("on"))
1305 new_params
.qx3
.toplight
= 1;
1306 else if (!retval
&& MATCH("off"))
1307 new_params
.qx3
.toplight
= 0;
1310 command_flags
|= COMMAND_SETLIGHTS
;
1311 } else if (MATCH("bottomlight")) {
1312 if (!retval
&& MATCH("on"))
1313 new_params
.qx3
.bottomlight
= 1;
1314 else if (!retval
&& MATCH("off"))
1315 new_params
.qx3
.bottomlight
= 0;
1318 command_flags
|= COMMAND_SETLIGHTS
;
1320 DBG("No match found\n");
1325 while (count
&& isspace(*buffer
) && *buffer
!= '\n') {
1330 if (*buffer
== '\0' && count
!= 1)
1332 else if (*buffer
!= '\n' && *buffer
!= ';' &&
1344 #undef FIRMWARE_VERSION
1346 if (command_flags
& COMMAND_SETCOLOURPARAMS
) {
1347 /* Adjust cam->vp to reflect these changes */
1348 cam
->vp
.brightness
=
1349 new_params
.colourParams
.brightness
*65535/100;
1351 new_params
.colourParams
.contrast
*65535/100;
1353 new_params
.colourParams
.saturation
*65535/100;
1355 if((command_flags
& COMMAND_SETEXPOSURE
) &&
1356 new_params
.exposure
.expMode
== 2)
1357 cam
->exposure_status
= EXPOSURE_NORMAL
;
1359 memcpy(&cam
->params
, &new_params
, sizeof(struct cam_params
));
1360 cam
->mainsFreq
= new_mains
;
1361 cam
->cmd_queue
|= command_flags
;
1364 DBG("error: %d\n", retval
);
1366 up(&cam
->param_lock
);
1369 free_page((unsigned long)page
);
1373 static void create_proc_cpia_cam(struct cam_data
*cam
)
1376 struct proc_dir_entry
*ent
;
1378 if (!cpia_proc_root
|| !cam
)
1381 sprintf(name
, "video%d", cam
->vdev
.minor
);
1383 ent
= create_proc_entry(name
, S_IFREG
|S_IRUGO
|S_IWUSR
, cpia_proc_root
);
1388 ent
->read_proc
= cpia_read_proc
;
1389 ent
->write_proc
= cpia_write_proc
;
1391 size of the proc entry is 3736 bytes for the standard webcam;
1392 the extra features of the QX3 microscope add 189 bytes.
1393 (we have not yet probed the camera to see which type it is).
1395 ent
->size
= 3736 + 189;
1396 cam
->proc_entry
= ent
;
1399 static void destroy_proc_cpia_cam(struct cam_data
*cam
)
1403 if (!cam
|| !cam
->proc_entry
)
1406 sprintf(name
, "video%d", cam
->vdev
.minor
);
1407 remove_proc_entry(name
, cpia_proc_root
);
1408 cam
->proc_entry
= NULL
;
1411 static void proc_cpia_create(void)
1413 cpia_proc_root
= create_proc_entry("cpia", S_IFDIR
, NULL
);
1416 cpia_proc_root
->owner
= THIS_MODULE
;
1418 LOG("Unable to initialise /proc/cpia\n");
1421 static void __exit
proc_cpia_destroy(void)
1423 remove_proc_entry("cpia", NULL
);
1425 #endif /* CONFIG_PROC_FS */
1427 /* ----------------------- debug functions ---------------------- */
1429 #define printstatus(cam) \
1430 DBG("%02x %02x %02x %02x %02x %02x %02x %02x\n",\
1431 cam->params.status.systemState, cam->params.status.grabState, \
1432 cam->params.status.streamState, cam->params.status.fatalError, \
1433 cam->params.status.cmdError, cam->params.status.debugFlags, \
1434 cam->params.status.vpStatus, cam->params.status.errorCode);
1436 /* ----------------------- v4l helpers -------------------------- */
1438 /* supported frame palettes and depths */
1439 static inline int valid_mode(u16 palette
, u16 depth
)
1441 if ((palette
== VIDEO_PALETTE_YUV422
&& depth
== 16) ||
1442 (palette
== VIDEO_PALETTE_YUYV
&& depth
== 16))
1445 if (colorspace_conv
)
1446 return (palette
== VIDEO_PALETTE_GREY
&& depth
== 8) ||
1447 (palette
== VIDEO_PALETTE_RGB555
&& depth
== 16) ||
1448 (palette
== VIDEO_PALETTE_RGB565
&& depth
== 16) ||
1449 (palette
== VIDEO_PALETTE_RGB24
&& depth
== 24) ||
1450 (palette
== VIDEO_PALETTE_RGB32
&& depth
== 32) ||
1451 (palette
== VIDEO_PALETTE_UYVY
&& depth
== 16);
1456 static int match_videosize( int width
, int height
)
1458 /* return the best match, where 'best' is as always
1459 * the largest that is not bigger than what is requested. */
1460 if (width
>=352 && height
>=288)
1461 return VIDEOSIZE_352_288
; /* CIF */
1463 if (width
>=320 && height
>=240)
1464 return VIDEOSIZE_320_240
; /* SIF */
1466 if (width
>=288 && height
>=216)
1467 return VIDEOSIZE_288_216
;
1469 if (width
>=256 && height
>=192)
1470 return VIDEOSIZE_256_192
;
1472 if (width
>=224 && height
>=168)
1473 return VIDEOSIZE_224_168
;
1475 if (width
>=192 && height
>=144)
1476 return VIDEOSIZE_192_144
;
1478 if (width
>=176 && height
>=144)
1479 return VIDEOSIZE_176_144
; /* QCIF */
1481 if (width
>=160 && height
>=120)
1482 return VIDEOSIZE_160_120
; /* QSIF */
1484 if (width
>=128 && height
>=96)
1485 return VIDEOSIZE_128_96
;
1487 if (width
>=88 && height
>=72)
1488 return VIDEOSIZE_88_72
;
1490 if (width
>=64 && height
>=48)
1491 return VIDEOSIZE_64_48
;
1493 if (width
>=48 && height
>=48)
1494 return VIDEOSIZE_48_48
;
1499 /* these are the capture sizes we support */
1500 static void set_vw_size(struct cam_data
*cam
)
1502 /* the col/row/start/end values are the result of simple math */
1503 /* study the SetROI-command in cpia developers guide p 2-22 */
1504 /* streamStartLine is set to the recommended value in the cpia */
1505 /* developers guide p 3-37 */
1506 switch(cam
->video_size
) {
1508 cam
->vw
.width
= 352;
1509 cam
->vw
.height
= 288;
1510 cam
->params
.format
.videoSize
=VIDEOSIZE_CIF
;
1511 cam
->params
.roi
.colStart
=0;
1512 cam
->params
.roi
.rowStart
=0;
1513 cam
->params
.streamStartLine
= 120;
1516 cam
->vw
.width
= 320;
1517 cam
->vw
.height
= 240;
1518 cam
->params
.format
.videoSize
=VIDEOSIZE_CIF
;
1519 cam
->params
.roi
.colStart
=2;
1520 cam
->params
.roi
.rowStart
=6;
1521 cam
->params
.streamStartLine
= 120;
1523 case VIDEOSIZE_288_216
:
1524 cam
->vw
.width
= 288;
1525 cam
->vw
.height
= 216;
1526 cam
->params
.format
.videoSize
=VIDEOSIZE_CIF
;
1527 cam
->params
.roi
.colStart
=4;
1528 cam
->params
.roi
.rowStart
=9;
1529 cam
->params
.streamStartLine
= 120;
1531 case VIDEOSIZE_256_192
:
1532 cam
->vw
.width
= 256;
1533 cam
->vw
.height
= 192;
1534 cam
->params
.format
.videoSize
=VIDEOSIZE_CIF
;
1535 cam
->params
.roi
.colStart
=6;
1536 cam
->params
.roi
.rowStart
=12;
1537 cam
->params
.streamStartLine
= 120;
1539 case VIDEOSIZE_224_168
:
1540 cam
->vw
.width
= 224;
1541 cam
->vw
.height
= 168;
1542 cam
->params
.format
.videoSize
=VIDEOSIZE_CIF
;
1543 cam
->params
.roi
.colStart
=8;
1544 cam
->params
.roi
.rowStart
=15;
1545 cam
->params
.streamStartLine
= 120;
1547 case VIDEOSIZE_192_144
:
1548 cam
->vw
.width
= 192;
1549 cam
->vw
.height
= 144;
1550 cam
->params
.format
.videoSize
=VIDEOSIZE_CIF
;
1551 cam
->params
.roi
.colStart
=10;
1552 cam
->params
.roi
.rowStart
=18;
1553 cam
->params
.streamStartLine
= 120;
1555 case VIDEOSIZE_QCIF
:
1556 cam
->vw
.width
= 176;
1557 cam
->vw
.height
= 144;
1558 cam
->params
.format
.videoSize
=VIDEOSIZE_QCIF
;
1559 cam
->params
.roi
.colStart
=0;
1560 cam
->params
.roi
.rowStart
=0;
1561 cam
->params
.streamStartLine
= 60;
1563 case VIDEOSIZE_QSIF
:
1564 cam
->vw
.width
= 160;
1565 cam
->vw
.height
= 120;
1566 cam
->params
.format
.videoSize
=VIDEOSIZE_QCIF
;
1567 cam
->params
.roi
.colStart
=1;
1568 cam
->params
.roi
.rowStart
=3;
1569 cam
->params
.streamStartLine
= 60;
1571 case VIDEOSIZE_128_96
:
1572 cam
->vw
.width
= 128;
1573 cam
->vw
.height
= 96;
1574 cam
->params
.format
.videoSize
=VIDEOSIZE_QCIF
;
1575 cam
->params
.roi
.colStart
=3;
1576 cam
->params
.roi
.rowStart
=6;
1577 cam
->params
.streamStartLine
= 60;
1579 case VIDEOSIZE_88_72
:
1581 cam
->vw
.height
= 72;
1582 cam
->params
.format
.videoSize
=VIDEOSIZE_QCIF
;
1583 cam
->params
.roi
.colStart
=5;
1584 cam
->params
.roi
.rowStart
=9;
1585 cam
->params
.streamStartLine
= 60;
1587 case VIDEOSIZE_64_48
:
1589 cam
->vw
.height
= 48;
1590 cam
->params
.format
.videoSize
=VIDEOSIZE_QCIF
;
1591 cam
->params
.roi
.colStart
=7;
1592 cam
->params
.roi
.rowStart
=12;
1593 cam
->params
.streamStartLine
= 60;
1595 case VIDEOSIZE_48_48
:
1597 cam
->vw
.height
= 48;
1598 cam
->params
.format
.videoSize
=VIDEOSIZE_QCIF
;
1599 cam
->params
.roi
.colStart
=8;
1600 cam
->params
.roi
.rowStart
=6;
1601 cam
->params
.streamStartLine
= 60;
1604 LOG("bad videosize value: %d\n", cam
->video_size
);
1608 if(cam
->vc
.width
== 0)
1609 cam
->vc
.width
= cam
->vw
.width
;
1610 if(cam
->vc
.height
== 0)
1611 cam
->vc
.height
= cam
->vw
.height
;
1613 cam
->params
.roi
.colStart
+= cam
->vc
.x
>> 3;
1614 cam
->params
.roi
.colEnd
= cam
->params
.roi
.colStart
+
1615 (cam
->vc
.width
>> 3);
1616 cam
->params
.roi
.rowStart
+= cam
->vc
.y
>> 2;
1617 cam
->params
.roi
.rowEnd
= cam
->params
.roi
.rowStart
+
1618 (cam
->vc
.height
>> 2);
1623 static int allocate_frame_buf(struct cam_data
*cam
)
1627 cam
->frame_buf
= rvmalloc(FRAME_NUM
* CPIA_MAX_FRAME_SIZE
);
1628 if (!cam
->frame_buf
)
1631 for (i
= 0; i
< FRAME_NUM
; i
++)
1632 cam
->frame
[i
].data
= cam
->frame_buf
+ i
* CPIA_MAX_FRAME_SIZE
;
1637 static int free_frame_buf(struct cam_data
*cam
)
1641 rvfree(cam
->frame_buf
, FRAME_NUM
*CPIA_MAX_FRAME_SIZE
);
1642 cam
->frame_buf
= NULL
;
1643 for (i
=0; i
< FRAME_NUM
; i
++)
1644 cam
->frame
[i
].data
= NULL
;
1650 static inline void free_frames(struct cpia_frame frame
[FRAME_NUM
])
1654 for (i
=0; i
< FRAME_NUM
; i
++)
1655 frame
[i
].state
= FRAME_UNUSED
;
1659 /**********************************************************************
1663 **********************************************************************/
1664 /* send an arbitrary command to the camera */
1665 static int do_command(struct cam_data
*cam
, u16 command
, u8 a
, u8 b
, u8 c
, u8 d
)
1667 int retval
, datasize
;
1671 case CPIA_COMMAND_GetCPIAVersion
:
1672 case CPIA_COMMAND_GetPnPID
:
1673 case CPIA_COMMAND_GetCameraStatus
:
1674 case CPIA_COMMAND_GetVPVersion
:
1677 case CPIA_COMMAND_GetColourParams
:
1678 case CPIA_COMMAND_GetColourBalance
:
1679 case CPIA_COMMAND_GetExposure
:
1680 down(&cam
->param_lock
);
1683 case CPIA_COMMAND_ReadMCPorts
:
1684 case CPIA_COMMAND_ReadVCRegs
:
1692 cmd
[0] = command
>>8;
1693 cmd
[1] = command
&0xff;
1701 retval
= cam
->ops
->transferCmd(cam
->lowlevel_data
, cmd
, data
);
1703 DBG("%x - failed, retval=%d\n", command
, retval
);
1704 if (command
== CPIA_COMMAND_GetColourParams
||
1705 command
== CPIA_COMMAND_GetColourBalance
||
1706 command
== CPIA_COMMAND_GetExposure
)
1707 up(&cam
->param_lock
);
1710 case CPIA_COMMAND_GetCPIAVersion
:
1711 cam
->params
.version
.firmwareVersion
= data
[0];
1712 cam
->params
.version
.firmwareRevision
= data
[1];
1713 cam
->params
.version
.vcVersion
= data
[2];
1714 cam
->params
.version
.vcRevision
= data
[3];
1716 case CPIA_COMMAND_GetPnPID
:
1717 cam
->params
.pnpID
.vendor
= data
[0]+(((u16
)data
[1])<<8);
1718 cam
->params
.pnpID
.product
= data
[2]+(((u16
)data
[3])<<8);
1719 cam
->params
.pnpID
.deviceRevision
=
1720 data
[4]+(((u16
)data
[5])<<8);
1722 case CPIA_COMMAND_GetCameraStatus
:
1723 cam
->params
.status
.systemState
= data
[0];
1724 cam
->params
.status
.grabState
= data
[1];
1725 cam
->params
.status
.streamState
= data
[2];
1726 cam
->params
.status
.fatalError
= data
[3];
1727 cam
->params
.status
.cmdError
= data
[4];
1728 cam
->params
.status
.debugFlags
= data
[5];
1729 cam
->params
.status
.vpStatus
= data
[6];
1730 cam
->params
.status
.errorCode
= data
[7];
1732 case CPIA_COMMAND_GetVPVersion
:
1733 cam
->params
.vpVersion
.vpVersion
= data
[0];
1734 cam
->params
.vpVersion
.vpRevision
= data
[1];
1735 cam
->params
.vpVersion
.cameraHeadID
=
1736 data
[2]+(((u16
)data
[3])<<8);
1738 case CPIA_COMMAND_GetColourParams
:
1739 cam
->params
.colourParams
.brightness
= data
[0];
1740 cam
->params
.colourParams
.contrast
= data
[1];
1741 cam
->params
.colourParams
.saturation
= data
[2];
1742 up(&cam
->param_lock
);
1744 case CPIA_COMMAND_GetColourBalance
:
1745 cam
->params
.colourBalance
.redGain
= data
[0];
1746 cam
->params
.colourBalance
.greenGain
= data
[1];
1747 cam
->params
.colourBalance
.blueGain
= data
[2];
1748 up(&cam
->param_lock
);
1750 case CPIA_COMMAND_GetExposure
:
1751 cam
->params
.exposure
.gain
= data
[0];
1752 cam
->params
.exposure
.fineExp
= data
[1];
1753 cam
->params
.exposure
.coarseExpLo
= data
[2];
1754 cam
->params
.exposure
.coarseExpHi
= data
[3];
1755 cam
->params
.exposure
.redComp
= data
[4];
1756 cam
->params
.exposure
.green1Comp
= data
[5];
1757 cam
->params
.exposure
.green2Comp
= data
[6];
1758 cam
->params
.exposure
.blueComp
= data
[7];
1759 up(&cam
->param_lock
);
1762 case CPIA_COMMAND_ReadMCPorts
:
1763 if (!cam
->params
.qx3
.qx3_detected
)
1765 /* test button press */
1766 cam
->params
.qx3
.button
= ((data
[1] & 0x02) == 0);
1767 if (cam
->params
.qx3
.button
) {
1768 /* button pressed - unlock the latch */
1769 do_command(cam
,CPIA_COMMAND_WriteMCPort
,3,0xDF,0xDF,0);
1770 do_command(cam
,CPIA_COMMAND_WriteMCPort
,3,0xFF,0xFF,0);
1773 /* test whether microscope is cradled */
1774 cam
->params
.qx3
.cradled
= ((data
[2] & 0x40) == 0);
1784 /* send a command to the camera with an additional data transaction */
1785 static int do_command_extended(struct cam_data
*cam
, u16 command
,
1786 u8 a
, u8 b
, u8 c
, u8 d
,
1787 u8 e
, u8 f
, u8 g
, u8 h
,
1788 u8 i
, u8 j
, u8 k
, u8 l
)
1793 cmd
[0] = command
>>8;
1794 cmd
[1] = command
&0xff;
1810 retval
= cam
->ops
->transferCmd(cam
->lowlevel_data
, cmd
, data
);
1812 DBG("%x - failed\n", command
);
1817 /**********************************************************************
1819 * Colorspace conversion
1821 **********************************************************************/
1822 #define LIMIT(x) ((((x)>0xffffff)?0xff0000:(((x)<=0xffff)?0:(x)&0xff0000))>>16)
1824 static int convert420(unsigned char *yuv
, unsigned char *rgb
, int out_fmt
,
1825 int linesize
, int mmap_kludge
)
1827 int y
, u
, v
, r
, g
, b
, y1
;
1829 /* Odd lines use the same u and v as the previous line.
1830 * Because of compression, it is necessary to get this
1831 * information from the decoded image. */
1833 case VIDEO_PALETTE_RGB555
:
1834 y
= (*yuv
++ - 16) * 76310;
1835 y1
= (*yuv
- 16) * 76310;
1836 r
= ((*(rgb
+1-linesize
)) & 0x7c) << 1;
1837 g
= ((*(rgb
-linesize
)) & 0xe0) >> 4 |
1838 ((*(rgb
+1-linesize
)) & 0x03) << 6;
1839 b
= ((*(rgb
-linesize
)) & 0x1f) << 3;
1840 u
= (-53294 * r
- 104635 * g
+ 157929 * b
) / 5756495;
1841 v
= (157968 * r
- 132278 * g
- 25690 * b
) / 5366159;
1843 g
= -25690 * u
- 53294 * v
;
1845 *rgb
++ = ((LIMIT(g
+y
) & 0xf8) << 2) | (LIMIT(b
+y
) >> 3);
1846 *rgb
++ = ((LIMIT(r
+y
) & 0xf8) >> 1) | (LIMIT(g
+y
) >> 6);
1847 *rgb
++ = ((LIMIT(g
+y1
) & 0xf8) << 2) | (LIMIT(b
+y1
) >> 3);
1848 *rgb
= ((LIMIT(r
+y1
) & 0xf8) >> 1) | (LIMIT(g
+y1
) >> 6);
1850 case VIDEO_PALETTE_RGB565
:
1851 y
= (*yuv
++ - 16) * 76310;
1852 y1
= (*yuv
- 16) * 76310;
1853 r
= (*(rgb
+1-linesize
)) & 0xf8;
1854 g
= ((*(rgb
-linesize
)) & 0xe0) >> 3 |
1855 ((*(rgb
+1-linesize
)) & 0x07) << 5;
1856 b
= ((*(rgb
-linesize
)) & 0x1f) << 3;
1857 u
= (-53294 * r
- 104635 * g
+ 157929 * b
) / 5756495;
1858 v
= (157968 * r
- 132278 * g
- 25690 * b
) / 5366159;
1860 g
= -25690 * u
- 53294 * v
;
1862 *rgb
++ = ((LIMIT(g
+y
) & 0xfc) << 3) | (LIMIT(b
+y
) >> 3);
1863 *rgb
++ = (LIMIT(r
+y
) & 0xf8) | (LIMIT(g
+y
) >> 5);
1864 *rgb
++ = ((LIMIT(g
+y1
) & 0xfc) << 3) | (LIMIT(b
+y1
) >> 3);
1865 *rgb
= (LIMIT(r
+y1
) & 0xf8) | (LIMIT(g
+y1
) >> 5);
1868 case VIDEO_PALETTE_RGB24
:
1869 case VIDEO_PALETTE_RGB32
:
1870 y
= (*yuv
++ - 16) * 76310;
1871 y1
= (*yuv
- 16) * 76310;
1873 r
= *(rgb
+2-linesize
);
1874 g
= *(rgb
+1-linesize
);
1875 b
= *(rgb
-linesize
);
1877 r
= *(rgb
-linesize
);
1878 g
= *(rgb
+1-linesize
);
1879 b
= *(rgb
+2-linesize
);
1881 u
= (-53294 * r
- 104635 * g
+ 157929 * b
) / 5756495;
1882 v
= (157968 * r
- 132278 * g
- 25690 * b
) / 5366159;
1884 g
= -25690 * u
+ -53294 * v
;
1887 *rgb
++ = LIMIT(b
+y
);
1888 *rgb
++ = LIMIT(g
+y
);
1889 *rgb
++ = LIMIT(r
+y
);
1890 if(out_fmt
== VIDEO_PALETTE_RGB32
)
1892 *rgb
++ = LIMIT(b
+y1
);
1893 *rgb
++ = LIMIT(g
+y1
);
1896 *rgb
++ = LIMIT(r
+y
);
1897 *rgb
++ = LIMIT(g
+y
);
1898 *rgb
++ = LIMIT(b
+y
);
1899 if(out_fmt
== VIDEO_PALETTE_RGB32
)
1901 *rgb
++ = LIMIT(r
+y1
);
1902 *rgb
++ = LIMIT(g
+y1
);
1905 if(out_fmt
== VIDEO_PALETTE_RGB32
)
1908 case VIDEO_PALETTE_YUV422
:
1909 case VIDEO_PALETTE_YUYV
:
1911 u
= *(rgb
+1-linesize
);
1913 v
= *(rgb
+3-linesize
);
1919 case VIDEO_PALETTE_UYVY
:
1920 u
= *(rgb
-linesize
);
1922 v
= *(rgb
+2-linesize
);
1929 case VIDEO_PALETTE_GREY
:
1934 DBG("Empty: %d\n", out_fmt
);
1940 static int yuvconvert(unsigned char *yuv
, unsigned char *rgb
, int out_fmt
,
1941 int in_uyvy
, int mmap_kludge
)
1943 int y
, u
, v
, r
, g
, b
, y1
;
1946 case VIDEO_PALETTE_RGB555
:
1947 case VIDEO_PALETTE_RGB565
:
1948 case VIDEO_PALETTE_RGB24
:
1949 case VIDEO_PALETTE_RGB32
:
1952 y
= (*yuv
++ - 16) * 76310;
1954 y1
= (*yuv
- 16) * 76310;
1956 y
= (*yuv
++ - 16) * 76310;
1958 y1
= (*yuv
++ - 16) * 76310;
1962 g
= -25690 * u
+ -53294 * v
;
1970 /* Just to avoid compiler warnings */
1977 case VIDEO_PALETTE_RGB555
:
1978 *rgb
++ = ((LIMIT(g
+y
) & 0xf8) << 2) | (LIMIT(b
+y
) >> 3);
1979 *rgb
++ = ((LIMIT(r
+y
) & 0xf8) >> 1) | (LIMIT(g
+y
) >> 6);
1980 *rgb
++ = ((LIMIT(g
+y1
) & 0xf8) << 2) | (LIMIT(b
+y1
) >> 3);
1981 *rgb
= ((LIMIT(r
+y1
) & 0xf8) >> 1) | (LIMIT(g
+y1
) >> 6);
1983 case VIDEO_PALETTE_RGB565
:
1984 *rgb
++ = ((LIMIT(g
+y
) & 0xfc) << 3) | (LIMIT(b
+y
) >> 3);
1985 *rgb
++ = (LIMIT(r
+y
) & 0xf8) | (LIMIT(g
+y
) >> 5);
1986 *rgb
++ = ((LIMIT(g
+y1
) & 0xfc) << 3) | (LIMIT(b
+y1
) >> 3);
1987 *rgb
= (LIMIT(r
+y1
) & 0xf8) | (LIMIT(g
+y1
) >> 5);
1989 case VIDEO_PALETTE_RGB24
:
1991 *rgb
++ = LIMIT(b
+y
);
1992 *rgb
++ = LIMIT(g
+y
);
1993 *rgb
++ = LIMIT(r
+y
);
1994 *rgb
++ = LIMIT(b
+y1
);
1995 *rgb
++ = LIMIT(g
+y1
);
1998 *rgb
++ = LIMIT(r
+y
);
1999 *rgb
++ = LIMIT(g
+y
);
2000 *rgb
++ = LIMIT(b
+y
);
2001 *rgb
++ = LIMIT(r
+y1
);
2002 *rgb
++ = LIMIT(g
+y1
);
2006 case VIDEO_PALETTE_RGB32
:
2008 *rgb
++ = LIMIT(b
+y
);
2009 *rgb
++ = LIMIT(g
+y
);
2010 *rgb
++ = LIMIT(r
+y
);
2012 *rgb
++ = LIMIT(b
+y1
);
2013 *rgb
++ = LIMIT(g
+y1
);
2016 *rgb
++ = LIMIT(r
+y
);
2017 *rgb
++ = LIMIT(g
+y
);
2018 *rgb
++ = LIMIT(b
+y
);
2020 *rgb
++ = LIMIT(r
+y1
);
2021 *rgb
++ = LIMIT(g
+y1
);
2025 case VIDEO_PALETTE_GREY
:
2029 case VIDEO_PALETTE_YUV422
:
2030 case VIDEO_PALETTE_YUYV
:
2036 case VIDEO_PALETTE_UYVY
:
2043 DBG("Empty: %d\n", out_fmt
);
2048 static int skipcount(int count
, int fmt
)
2051 case VIDEO_PALETTE_GREY
:
2053 case VIDEO_PALETTE_RGB555
:
2054 case VIDEO_PALETTE_RGB565
:
2055 case VIDEO_PALETTE_YUV422
:
2056 case VIDEO_PALETTE_YUYV
:
2057 case VIDEO_PALETTE_UYVY
:
2059 case VIDEO_PALETTE_RGB24
:
2061 case VIDEO_PALETTE_RGB32
:
2068 static int parse_picture(struct cam_data
*cam
, int size
)
2070 u8
*obuf
, *ibuf
, *end_obuf
;
2071 int ll
, in_uyvy
, compressed
, decimation
, even_line
, origsize
, out_fmt
;
2072 int rows
, cols
, linesize
, subsample_422
;
2074 /* make sure params don't change while we are decoding */
2075 down(&cam
->param_lock
);
2077 obuf
= cam
->decompressed_frame
.data
;
2078 end_obuf
= obuf
+CPIA_MAX_FRAME_SIZE
;
2079 ibuf
= cam
->raw_image
;
2081 out_fmt
= cam
->vp
.palette
;
2083 if ((ibuf
[0] != MAGIC_0
) || (ibuf
[1] != MAGIC_1
)) {
2084 LOG("header not found\n");
2085 up(&cam
->param_lock
);
2089 if ((ibuf
[16] != VIDEOSIZE_QCIF
) && (ibuf
[16] != VIDEOSIZE_CIF
)) {
2090 LOG("wrong video size\n");
2091 up(&cam
->param_lock
);
2095 if (ibuf
[17] != SUBSAMPLE_420
&& ibuf
[17] != SUBSAMPLE_422
) {
2096 LOG("illegal subtype %d\n",ibuf
[17]);
2097 up(&cam
->param_lock
);
2100 subsample_422
= ibuf
[17] == SUBSAMPLE_422
;
2102 if (ibuf
[18] != YUVORDER_YUYV
&& ibuf
[18] != YUVORDER_UYVY
) {
2103 LOG("illegal yuvorder %d\n",ibuf
[18]);
2104 up(&cam
->param_lock
);
2107 in_uyvy
= ibuf
[18] == YUVORDER_UYVY
;
2109 if ((ibuf
[24] != cam
->params
.roi
.colStart
) ||
2110 (ibuf
[25] != cam
->params
.roi
.colEnd
) ||
2111 (ibuf
[26] != cam
->params
.roi
.rowStart
) ||
2112 (ibuf
[27] != cam
->params
.roi
.rowEnd
)) {
2113 LOG("ROI mismatch\n");
2114 up(&cam
->param_lock
);
2117 cols
= 8*(ibuf
[25] - ibuf
[24]);
2118 rows
= 4*(ibuf
[27] - ibuf
[26]);
2121 if ((ibuf
[28] != NOT_COMPRESSED
) && (ibuf
[28] != COMPRESSED
)) {
2122 LOG("illegal compression %d\n",ibuf
[28]);
2123 up(&cam
->param_lock
);
2126 compressed
= (ibuf
[28] == COMPRESSED
);
2128 if (ibuf
[29] != NO_DECIMATION
&& ibuf
[29] != DECIMATION_ENAB
) {
2129 LOG("illegal decimation %d\n",ibuf
[29]);
2130 up(&cam
->param_lock
);
2133 decimation
= (ibuf
[29] == DECIMATION_ENAB
);
2135 cam
->params
.yuvThreshold
.yThreshold
= ibuf
[30];
2136 cam
->params
.yuvThreshold
.uvThreshold
= ibuf
[31];
2137 cam
->params
.status
.systemState
= ibuf
[32];
2138 cam
->params
.status
.grabState
= ibuf
[33];
2139 cam
->params
.status
.streamState
= ibuf
[34];
2140 cam
->params
.status
.fatalError
= ibuf
[35];
2141 cam
->params
.status
.cmdError
= ibuf
[36];
2142 cam
->params
.status
.debugFlags
= ibuf
[37];
2143 cam
->params
.status
.vpStatus
= ibuf
[38];
2144 cam
->params
.status
.errorCode
= ibuf
[39];
2145 cam
->fps
= ibuf
[41];
2146 up(&cam
->param_lock
);
2148 linesize
= skipcount(cols
, out_fmt
);
2149 ibuf
+= FRAME_HEADER_SIZE
;
2150 size
-= FRAME_HEADER_SIZE
;
2151 ll
= ibuf
[0] | (ibuf
[1] << 8);
2158 LOG("Insufficient data in buffer\n");
2163 if (!compressed
|| (compressed
&& !(*ibuf
& 1))) {
2164 if(subsample_422
|| even_line
) {
2165 obuf
+= yuvconvert(ibuf
, obuf
, out_fmt
,
2166 in_uyvy
, cam
->mmap_kludge
);
2170 /* SUBSAMPLE_420 on an odd line */
2171 obuf
+= convert420(ibuf
, obuf
,
2178 /*skip compressed interval from previous frame*/
2179 obuf
+= skipcount(*ibuf
>> 1, out_fmt
);
2180 if (obuf
> end_obuf
) {
2181 LOG("Insufficient buffer size\n");
2190 DBG("EOL not found giving up after %d/%d"
2191 " bytes\n", origsize
-size
, origsize
);
2195 ++ibuf
; /* skip over EOL */
2197 if ((size
> 3) && (ibuf
[0] == EOI
) && (ibuf
[1] == EOI
) &&
2198 (ibuf
[2] == EOI
) && (ibuf
[3] == EOI
)) {
2204 /* skip the odd lines for now */
2209 ll
= ibuf
[0] | (ibuf
[1] << 8);
2210 ibuf
+= 2; /* skip over line length */
2213 even_line
= !even_line
;
2215 LOG("line length was not 1 but %d after %d/%d bytes\n",
2216 ll
, origsize
-size
, origsize
);
2222 /* interpolate odd rows */
2225 prev
= cam
->decompressed_frame
.data
;
2226 obuf
= prev
+linesize
;
2227 next
= obuf
+linesize
;
2228 for(i
=1; i
<rows
-1; i
+=2) {
2229 for(j
=0; j
<linesize
; ++j
) {
2230 *obuf
++ = ((int)*prev
++ + *next
++) / 2;
2236 /* last row is odd, just copy previous row */
2237 memcpy(obuf
, prev
, linesize
);
2240 cam
->decompressed_frame
.count
= obuf
-cam
->decompressed_frame
.data
;
2242 return cam
->decompressed_frame
.count
;
2245 /* InitStreamCap wrapper to select correct start line */
2246 static inline int init_stream_cap(struct cam_data
*cam
)
2248 return do_command(cam
, CPIA_COMMAND_InitStreamCap
,
2249 0, cam
->params
.streamStartLine
, 0, 0);
2253 /* find_over_exposure
2254 * Finds a suitable value of OverExposure for use with SetFlickerCtrl
2255 * Some calculation is required because this value changes with the brightness
2256 * set with SetColourParameters
2258 * Parameters: Brightness - last brightness value set with SetColourParameters
2260 * Returns: OverExposure value to use with SetFlickerCtrl
2262 #define FLICKER_MAX_EXPOSURE 250
2263 #define FLICKER_ALLOWABLE_OVER_EXPOSURE 146
2264 #define FLICKER_BRIGHTNESS_CONSTANT 59
2265 static int find_over_exposure(int brightness
)
2267 int MaxAllowableOverExposure
, OverExposure
;
2269 MaxAllowableOverExposure
= FLICKER_MAX_EXPOSURE
- brightness
-
2270 FLICKER_BRIGHTNESS_CONSTANT
;
2272 if (MaxAllowableOverExposure
< FLICKER_ALLOWABLE_OVER_EXPOSURE
) {
2273 OverExposure
= MaxAllowableOverExposure
;
2275 OverExposure
= FLICKER_ALLOWABLE_OVER_EXPOSURE
;
2278 return OverExposure
;
2280 #undef FLICKER_MAX_EXPOSURE
2281 #undef FLICKER_ALLOWABLE_OVER_EXPOSURE
2282 #undef FLICKER_BRIGHTNESS_CONSTANT
2284 /* update various camera modes and settings */
2285 static void dispatch_commands(struct cam_data
*cam
)
2287 down(&cam
->param_lock
);
2288 if (cam
->cmd_queue
==COMMAND_NONE
) {
2289 up(&cam
->param_lock
);
2292 DEB_BYTE(cam
->cmd_queue
);
2293 DEB_BYTE(cam
->cmd_queue
>>8);
2294 if (cam
->cmd_queue
& COMMAND_SETFORMAT
) {
2295 do_command(cam
, CPIA_COMMAND_SetFormat
,
2296 cam
->params
.format
.videoSize
,
2297 cam
->params
.format
.subSample
,
2298 cam
->params
.format
.yuvOrder
, 0);
2299 do_command(cam
, CPIA_COMMAND_SetROI
,
2300 cam
->params
.roi
.colStart
, cam
->params
.roi
.colEnd
,
2301 cam
->params
.roi
.rowStart
, cam
->params
.roi
.rowEnd
);
2302 cam
->first_frame
= 1;
2305 if (cam
->cmd_queue
& COMMAND_SETCOLOURPARAMS
)
2306 do_command(cam
, CPIA_COMMAND_SetColourParams
,
2307 cam
->params
.colourParams
.brightness
,
2308 cam
->params
.colourParams
.contrast
,
2309 cam
->params
.colourParams
.saturation
, 0);
2311 if (cam
->cmd_queue
& COMMAND_SETAPCOR
)
2312 do_command(cam
, CPIA_COMMAND_SetApcor
,
2313 cam
->params
.apcor
.gain1
,
2314 cam
->params
.apcor
.gain2
,
2315 cam
->params
.apcor
.gain4
,
2316 cam
->params
.apcor
.gain8
);
2318 if (cam
->cmd_queue
& COMMAND_SETVLOFFSET
)
2319 do_command(cam
, CPIA_COMMAND_SetVLOffset
,
2320 cam
->params
.vlOffset
.gain1
,
2321 cam
->params
.vlOffset
.gain2
,
2322 cam
->params
.vlOffset
.gain4
,
2323 cam
->params
.vlOffset
.gain8
);
2325 if (cam
->cmd_queue
& COMMAND_SETEXPOSURE
) {
2326 do_command_extended(cam
, CPIA_COMMAND_SetExposure
,
2327 cam
->params
.exposure
.gainMode
,
2329 cam
->params
.exposure
.compMode
,
2330 cam
->params
.exposure
.centreWeight
,
2331 cam
->params
.exposure
.gain
,
2332 cam
->params
.exposure
.fineExp
,
2333 cam
->params
.exposure
.coarseExpLo
,
2334 cam
->params
.exposure
.coarseExpHi
,
2335 cam
->params
.exposure
.redComp
,
2336 cam
->params
.exposure
.green1Comp
,
2337 cam
->params
.exposure
.green2Comp
,
2338 cam
->params
.exposure
.blueComp
);
2339 if(cam
->params
.exposure
.expMode
!= 1) {
2340 do_command_extended(cam
, CPIA_COMMAND_SetExposure
,
2342 cam
->params
.exposure
.expMode
,
2344 cam
->params
.exposure
.gain
,
2345 cam
->params
.exposure
.fineExp
,
2346 cam
->params
.exposure
.coarseExpLo
,
2347 cam
->params
.exposure
.coarseExpHi
,
2352 if (cam
->cmd_queue
& COMMAND_SETCOLOURBALANCE
) {
2353 if (cam
->params
.colourBalance
.balanceMode
== 1) {
2354 do_command(cam
, CPIA_COMMAND_SetColourBalance
,
2356 cam
->params
.colourBalance
.redGain
,
2357 cam
->params
.colourBalance
.greenGain
,
2358 cam
->params
.colourBalance
.blueGain
);
2359 do_command(cam
, CPIA_COMMAND_SetColourBalance
,
2362 if (cam
->params
.colourBalance
.balanceMode
== 2) {
2363 do_command(cam
, CPIA_COMMAND_SetColourBalance
,
2366 if (cam
->params
.colourBalance
.balanceMode
== 3) {
2367 do_command(cam
, CPIA_COMMAND_SetColourBalance
,
2372 if (cam
->cmd_queue
& COMMAND_SETCOMPRESSIONTARGET
)
2373 do_command(cam
, CPIA_COMMAND_SetCompressionTarget
,
2374 cam
->params
.compressionTarget
.frTargeting
,
2375 cam
->params
.compressionTarget
.targetFR
,
2376 cam
->params
.compressionTarget
.targetQ
, 0);
2378 if (cam
->cmd_queue
& COMMAND_SETYUVTHRESH
)
2379 do_command(cam
, CPIA_COMMAND_SetYUVThresh
,
2380 cam
->params
.yuvThreshold
.yThreshold
,
2381 cam
->params
.yuvThreshold
.uvThreshold
, 0, 0);
2383 if (cam
->cmd_queue
& COMMAND_SETCOMPRESSIONPARAMS
)
2384 do_command_extended(cam
, CPIA_COMMAND_SetCompressionParams
,
2386 cam
->params
.compressionParams
.hysteresis
,
2387 cam
->params
.compressionParams
.threshMax
,
2388 cam
->params
.compressionParams
.smallStep
,
2389 cam
->params
.compressionParams
.largeStep
,
2390 cam
->params
.compressionParams
.decimationHysteresis
,
2391 cam
->params
.compressionParams
.frDiffStepThresh
,
2392 cam
->params
.compressionParams
.qDiffStepThresh
,
2393 cam
->params
.compressionParams
.decimationThreshMod
);
2395 if (cam
->cmd_queue
& COMMAND_SETCOMPRESSION
)
2396 do_command(cam
, CPIA_COMMAND_SetCompression
,
2397 cam
->params
.compression
.mode
,
2398 cam
->params
.compression
.decimation
, 0, 0);
2400 if (cam
->cmd_queue
& COMMAND_SETSENSORFPS
)
2401 do_command(cam
, CPIA_COMMAND_SetSensorFPS
,
2402 cam
->params
.sensorFps
.divisor
,
2403 cam
->params
.sensorFps
.baserate
, 0, 0);
2405 if (cam
->cmd_queue
& COMMAND_SETFLICKERCTRL
)
2406 do_command(cam
, CPIA_COMMAND_SetFlickerCtrl
,
2407 cam
->params
.flickerControl
.flickerMode
,
2408 cam
->params
.flickerControl
.coarseJump
,
2409 abs(cam
->params
.flickerControl
.allowableOverExposure
),
2412 if (cam
->cmd_queue
& COMMAND_SETECPTIMING
)
2413 do_command(cam
, CPIA_COMMAND_SetECPTiming
,
2414 cam
->params
.ecpTiming
, 0, 0, 0);
2416 if (cam
->cmd_queue
& COMMAND_PAUSE
)
2417 do_command(cam
, CPIA_COMMAND_EndStreamCap
, 0, 0, 0, 0);
2419 if (cam
->cmd_queue
& COMMAND_RESUME
)
2420 init_stream_cap(cam
);
2422 if (cam
->cmd_queue
& COMMAND_SETLIGHTS
&& cam
->params
.qx3
.qx3_detected
)
2424 int p1
= (cam
->params
.qx3
.bottomlight
== 0) << 1;
2425 int p2
= (cam
->params
.qx3
.toplight
== 0) << 3;
2426 do_command(cam
, CPIA_COMMAND_WriteVCReg
, 0x90, 0x8F, 0x50, 0);
2427 do_command(cam
, CPIA_COMMAND_WriteMCPort
, 2, 0, (p1
|p2
|0xE0), 0);
2430 cam
->cmd_queue
= COMMAND_NONE
;
2431 up(&cam
->param_lock
);
2437 static void set_flicker(struct cam_params
*params
, volatile u32
*command_flags
,
2440 /* Everything in here is from the Windows driver */
2441 #define FIRMWARE_VERSION(x,y) (params->version.firmwareVersion == (x) && \
2442 params->version.firmwareRevision == (y))
2443 /* define for compgain calculation */
2445 #define COMPGAIN(base, curexp, newexp) \
2446 (u8) ((((float) base - 128.0) * ((float) curexp / (float) newexp)) + 128.5)
2447 #define EXP_FROM_COMP(basecomp, curcomp, curexp) \
2448 (u16)((float)curexp * (float)(u8)(curcomp + 128) / (float)(u8)(basecomp - 128))
2450 /* equivalent functions without floating point math */
2451 #define COMPGAIN(base, curexp, newexp) \
2452 (u8)(128 + (((u32)(2*(base-128)*curexp + newexp)) / (2* newexp)) )
2453 #define EXP_FROM_COMP(basecomp, curcomp, curexp) \
2454 (u16)(((u32)(curexp * (u8)(curcomp + 128)) / (u8)(basecomp - 128)))
2458 int currentexp
= params
->exposure
.coarseExpLo
+
2459 params
->exposure
.coarseExpHi
*256;
2462 int cj
= params
->flickerControl
.coarseJump
;
2463 params
->flickerControl
.flickerMode
= 1;
2464 params
->flickerControl
.disabled
= 0;
2465 if(params
->exposure
.expMode
!= 2)
2466 *command_flags
|= COMMAND_SETEXPOSURE
;
2467 params
->exposure
.expMode
= 2;
2468 currentexp
= currentexp
<< params
->exposure
.gain
;
2469 params
->exposure
.gain
= 0;
2470 /* round down current exposure to nearest value */
2471 startexp
= (currentexp
+ ROUND_UP_EXP_FOR_FLICKER
) / cj
;
2474 startexp
= (startexp
* cj
) - 1;
2475 if(FIRMWARE_VERSION(1,2))
2476 while(startexp
> MAX_EXP_102
)
2479 while(startexp
> MAX_EXP
)
2481 params
->exposure
.coarseExpLo
= startexp
& 0xff;
2482 params
->exposure
.coarseExpHi
= startexp
>> 8;
2483 if (currentexp
> startexp
) {
2484 if (currentexp
> (2 * startexp
))
2485 currentexp
= 2 * startexp
;
2486 params
->exposure
.redComp
= COMPGAIN (COMP_RED
, currentexp
, startexp
);
2487 params
->exposure
.green1Comp
= COMPGAIN (COMP_GREEN1
, currentexp
, startexp
);
2488 params
->exposure
.green2Comp
= COMPGAIN (COMP_GREEN2
, currentexp
, startexp
);
2489 params
->exposure
.blueComp
= COMPGAIN (COMP_BLUE
, currentexp
, startexp
);
2491 params
->exposure
.redComp
= COMP_RED
;
2492 params
->exposure
.green1Comp
= COMP_GREEN1
;
2493 params
->exposure
.green2Comp
= COMP_GREEN2
;
2494 params
->exposure
.blueComp
= COMP_BLUE
;
2496 if(FIRMWARE_VERSION(1,2))
2497 params
->exposure
.compMode
= 0;
2499 params
->exposure
.compMode
= 1;
2501 params
->apcor
.gain1
= 0x18;
2502 params
->apcor
.gain2
= 0x18;
2503 params
->apcor
.gain4
= 0x16;
2504 params
->apcor
.gain8
= 0x14;
2505 *command_flags
|= COMMAND_SETAPCOR
;
2507 params
->flickerControl
.flickerMode
= 0;
2508 params
->flickerControl
.disabled
= 1;
2509 /* Coarse = average of equivalent coarse for each comp channel */
2510 startexp
= EXP_FROM_COMP(COMP_RED
, params
->exposure
.redComp
, currentexp
);
2511 startexp
+= EXP_FROM_COMP(COMP_GREEN1
, params
->exposure
.green1Comp
, currentexp
);
2512 startexp
+= EXP_FROM_COMP(COMP_GREEN2
, params
->exposure
.green2Comp
, currentexp
);
2513 startexp
+= EXP_FROM_COMP(COMP_BLUE
, params
->exposure
.blueComp
, currentexp
);
2514 startexp
= startexp
>> 2;
2515 while(startexp
> MAX_EXP
&&
2516 params
->exposure
.gain
< params
->exposure
.gainMode
-1) {
2517 startexp
= startexp
>> 1;
2518 ++params
->exposure
.gain
;
2520 if(FIRMWARE_VERSION(1,2) && startexp
> MAX_EXP_102
)
2521 startexp
= MAX_EXP_102
;
2522 if(startexp
> MAX_EXP
)
2524 params
->exposure
.coarseExpLo
= startexp
&0xff;
2525 params
->exposure
.coarseExpHi
= startexp
>> 8;
2526 params
->exposure
.redComp
= COMP_RED
;
2527 params
->exposure
.green1Comp
= COMP_GREEN1
;
2528 params
->exposure
.green2Comp
= COMP_GREEN2
;
2529 params
->exposure
.blueComp
= COMP_BLUE
;
2530 params
->exposure
.compMode
= 1;
2531 *command_flags
|= COMMAND_SETEXPOSURE
;
2532 params
->apcor
.gain1
= 0x18;
2533 params
->apcor
.gain2
= 0x16;
2534 params
->apcor
.gain4
= 0x24;
2535 params
->apcor
.gain8
= 0x34;
2536 *command_flags
|= COMMAND_SETAPCOR
;
2538 params
->vlOffset
.gain1
= 20;
2539 params
->vlOffset
.gain2
= 24;
2540 params
->vlOffset
.gain4
= 26;
2541 params
->vlOffset
.gain8
= 26;
2542 *command_flags
|= COMMAND_SETVLOFFSET
;
2543 #undef FIRMWARE_VERSION
2544 #undef EXP_FROM_COMP
2548 #define FIRMWARE_VERSION(x,y) (cam->params.version.firmwareVersion == (x) && \
2549 cam->params.version.firmwareRevision == (y))
2550 /* monitor the exposure and adjust the sensor frame rate if needed */
2551 static void monitor_exposure(struct cam_data
*cam
)
2553 u8 exp_acc
, bcomp
, gain
, coarseL
, cmd
[8], data
[8];
2554 int retval
, light_exp
, dark_exp
, very_dark_exp
;
2555 int old_exposure
, new_exposure
, framerate
;
2557 /* get necessary stats and register settings from camera */
2558 /* do_command can't handle this, so do it ourselves */
2559 cmd
[0] = CPIA_COMMAND_ReadVPRegs
>>8;
2560 cmd
[1] = CPIA_COMMAND_ReadVPRegs
&0xff;
2567 retval
= cam
->ops
->transferCmd(cam
->lowlevel_data
, cmd
, data
);
2569 LOG("ReadVPRegs(30,4,9,8) - failed, retval=%d\n",
2578 down(&cam
->param_lock
);
2579 light_exp
= cam
->params
.colourParams
.brightness
+
2580 TC
- 50 + EXP_ACC_LIGHT
;
2583 dark_exp
= cam
->params
.colourParams
.brightness
+
2584 TC
- 50 - EXP_ACC_DARK
;
2587 very_dark_exp
= dark_exp
/2;
2589 old_exposure
= cam
->params
.exposure
.coarseExpHi
* 256 +
2590 cam
->params
.exposure
.coarseExpLo
;
2592 if(!cam
->params
.flickerControl
.disabled
) {
2593 /* Flicker control on */
2594 int max_comp
= FIRMWARE_VERSION(1,2) ? MAX_COMP
: HIGH_COMP_102
;
2595 bcomp
+= 128; /* decode */
2596 if(bcomp
>= max_comp
&& exp_acc
< dark_exp
) {
2598 if(exp_acc
< very_dark_exp
) {
2600 if(cam
->exposure_status
== EXPOSURE_VERY_DARK
)
2601 ++cam
->exposure_count
;
2603 cam
->exposure_status
= EXPOSURE_VERY_DARK
;
2604 cam
->exposure_count
= 1;
2608 if(cam
->exposure_status
== EXPOSURE_DARK
)
2609 ++cam
->exposure_count
;
2611 cam
->exposure_status
= EXPOSURE_DARK
;
2612 cam
->exposure_count
= 1;
2615 } else if(old_exposure
<= LOW_EXP
|| exp_acc
> light_exp
) {
2617 if(old_exposure
<= VERY_LOW_EXP
) {
2619 if(cam
->exposure_status
== EXPOSURE_VERY_LIGHT
)
2620 ++cam
->exposure_count
;
2622 cam
->exposure_status
= EXPOSURE_VERY_LIGHT
;
2623 cam
->exposure_count
= 1;
2627 if(cam
->exposure_status
== EXPOSURE_LIGHT
)
2628 ++cam
->exposure_count
;
2630 cam
->exposure_status
= EXPOSURE_LIGHT
;
2631 cam
->exposure_count
= 1;
2635 /* not dark or light */
2636 cam
->exposure_status
= EXPOSURE_NORMAL
;
2639 /* Flicker control off */
2640 if(old_exposure
>= MAX_EXP
&& exp_acc
< dark_exp
) {
2642 if(exp_acc
< very_dark_exp
) {
2644 if(cam
->exposure_status
== EXPOSURE_VERY_DARK
)
2645 ++cam
->exposure_count
;
2647 cam
->exposure_status
= EXPOSURE_VERY_DARK
;
2648 cam
->exposure_count
= 1;
2652 if(cam
->exposure_status
== EXPOSURE_DARK
)
2653 ++cam
->exposure_count
;
2655 cam
->exposure_status
= EXPOSURE_DARK
;
2656 cam
->exposure_count
= 1;
2659 } else if(old_exposure
<= LOW_EXP
|| exp_acc
> light_exp
) {
2661 if(old_exposure
<= VERY_LOW_EXP
) {
2663 if(cam
->exposure_status
== EXPOSURE_VERY_LIGHT
)
2664 ++cam
->exposure_count
;
2666 cam
->exposure_status
= EXPOSURE_VERY_LIGHT
;
2667 cam
->exposure_count
= 1;
2671 if(cam
->exposure_status
== EXPOSURE_LIGHT
)
2672 ++cam
->exposure_count
;
2674 cam
->exposure_status
= EXPOSURE_LIGHT
;
2675 cam
->exposure_count
= 1;
2679 /* not dark or light */
2680 cam
->exposure_status
= EXPOSURE_NORMAL
;
2684 framerate
= cam
->fps
;
2685 if(framerate
> 30 || framerate
< 1)
2688 if(!cam
->params
.flickerControl
.disabled
) {
2689 /* Flicker control on */
2690 if((cam
->exposure_status
== EXPOSURE_VERY_DARK
||
2691 cam
->exposure_status
== EXPOSURE_DARK
) &&
2692 cam
->exposure_count
>= DARK_TIME
*framerate
&&
2693 cam
->params
.sensorFps
.divisor
< 3) {
2695 /* dark for too long */
2696 ++cam
->params
.sensorFps
.divisor
;
2697 cam
->cmd_queue
|= COMMAND_SETSENSORFPS
;
2699 cam
->params
.flickerControl
.coarseJump
=
2700 flicker_jumps
[cam
->mainsFreq
]
2701 [cam
->params
.sensorFps
.baserate
]
2702 [cam
->params
.sensorFps
.divisor
];
2703 cam
->cmd_queue
|= COMMAND_SETFLICKERCTRL
;
2705 new_exposure
= cam
->params
.flickerControl
.coarseJump
-1;
2706 while(new_exposure
< old_exposure
/2)
2707 new_exposure
+= cam
->params
.flickerControl
.coarseJump
;
2708 cam
->params
.exposure
.coarseExpLo
= new_exposure
& 0xff;
2709 cam
->params
.exposure
.coarseExpHi
= new_exposure
>> 8;
2710 cam
->cmd_queue
|= COMMAND_SETEXPOSURE
;
2711 cam
->exposure_status
= EXPOSURE_NORMAL
;
2712 LOG("Automatically decreasing sensor_fps\n");
2714 } else if((cam
->exposure_status
== EXPOSURE_VERY_LIGHT
||
2715 cam
->exposure_status
== EXPOSURE_LIGHT
) &&
2716 cam
->exposure_count
>= LIGHT_TIME
*framerate
&&
2717 cam
->params
.sensorFps
.divisor
> 0) {
2719 /* light for too long */
2720 int max_exp
= FIRMWARE_VERSION(1,2) ? MAX_EXP_102
: MAX_EXP
;
2722 --cam
->params
.sensorFps
.divisor
;
2723 cam
->cmd_queue
|= COMMAND_SETSENSORFPS
;
2725 cam
->params
.flickerControl
.coarseJump
=
2726 flicker_jumps
[cam
->mainsFreq
]
2727 [cam
->params
.sensorFps
.baserate
]
2728 [cam
->params
.sensorFps
.divisor
];
2729 cam
->cmd_queue
|= COMMAND_SETFLICKERCTRL
;
2731 new_exposure
= cam
->params
.flickerControl
.coarseJump
-1;
2732 while(new_exposure
< 2*old_exposure
&&
2734 cam
->params
.flickerControl
.coarseJump
< max_exp
)
2735 new_exposure
+= cam
->params
.flickerControl
.coarseJump
;
2736 cam
->params
.exposure
.coarseExpLo
= new_exposure
& 0xff;
2737 cam
->params
.exposure
.coarseExpHi
= new_exposure
>> 8;
2738 cam
->cmd_queue
|= COMMAND_SETEXPOSURE
;
2739 cam
->exposure_status
= EXPOSURE_NORMAL
;
2740 LOG("Automatically increasing sensor_fps\n");
2743 /* Flicker control off */
2744 if((cam
->exposure_status
== EXPOSURE_VERY_DARK
||
2745 cam
->exposure_status
== EXPOSURE_DARK
) &&
2746 cam
->exposure_count
>= DARK_TIME
*framerate
&&
2747 cam
->params
.sensorFps
.divisor
< 3) {
2749 /* dark for too long */
2750 ++cam
->params
.sensorFps
.divisor
;
2751 cam
->cmd_queue
|= COMMAND_SETSENSORFPS
;
2753 if(cam
->params
.exposure
.gain
> 0) {
2754 --cam
->params
.exposure
.gain
;
2755 cam
->cmd_queue
|= COMMAND_SETEXPOSURE
;
2757 cam
->exposure_status
= EXPOSURE_NORMAL
;
2758 LOG("Automatically decreasing sensor_fps\n");
2760 } else if((cam
->exposure_status
== EXPOSURE_VERY_LIGHT
||
2761 cam
->exposure_status
== EXPOSURE_LIGHT
) &&
2762 cam
->exposure_count
>= LIGHT_TIME
*framerate
&&
2763 cam
->params
.sensorFps
.divisor
> 0) {
2765 /* light for too long */
2766 --cam
->params
.sensorFps
.divisor
;
2767 cam
->cmd_queue
|= COMMAND_SETSENSORFPS
;
2769 if(cam
->params
.exposure
.gain
<
2770 cam
->params
.exposure
.gainMode
-1) {
2771 ++cam
->params
.exposure
.gain
;
2772 cam
->cmd_queue
|= COMMAND_SETEXPOSURE
;
2774 cam
->exposure_status
= EXPOSURE_NORMAL
;
2775 LOG("Automatically increasing sensor_fps\n");
2778 up(&cam
->param_lock
);
2781 /*-----------------------------------------------------------------*/
2782 /* if flicker is switched off, this function switches it back on.It checks,
2783 however, that conditions are suitable before restarting it.
2784 This should only be called for firmware version 1.2.
2786 It also adjust the colour balance when an exposure step is detected - as
2787 long as flicker is running
2789 static void restart_flicker(struct cam_data
*cam
)
2791 int cam_exposure
, old_exp
;
2792 if(!FIRMWARE_VERSION(1,2))
2794 down(&cam
->param_lock
);
2795 if(cam
->params
.flickerControl
.flickerMode
== 0 ||
2796 cam
->raw_image
[39] == 0) {
2797 up(&cam
->param_lock
);
2800 cam_exposure
= cam
->raw_image
[39]*2;
2801 old_exp
= cam
->params
.exposure
.coarseExpLo
+
2802 cam
->params
.exposure
.coarseExpHi
*256;
2804 see how far away camera exposure is from a valid
2805 flicker exposure value
2807 cam_exposure
%= cam
->params
.flickerControl
.coarseJump
;
2808 if(!cam
->params
.flickerControl
.disabled
&&
2809 cam_exposure
<= cam
->params
.flickerControl
.coarseJump
- 3) {
2810 /* Flicker control auto-disabled */
2811 cam
->params
.flickerControl
.disabled
= 1;
2814 if(cam
->params
.flickerControl
.disabled
&&
2815 cam
->params
.flickerControl
.flickerMode
&&
2816 old_exp
> cam
->params
.flickerControl
.coarseJump
+
2817 ROUND_UP_EXP_FOR_FLICKER
) {
2818 /* exposure is now high enough to switch
2819 flicker control back on */
2820 set_flicker(&cam
->params
, &cam
->cmd_queue
, 1);
2821 if((cam
->cmd_queue
& COMMAND_SETEXPOSURE
) &&
2822 cam
->params
.exposure
.expMode
== 2)
2823 cam
->exposure_status
= EXPOSURE_NORMAL
;
2826 up(&cam
->param_lock
);
2828 #undef FIRMWARE_VERSION
2830 static int clear_stall(struct cam_data
*cam
)
2832 /* FIXME: Does this actually work? */
2833 LOG("Clearing stall\n");
2835 cam
->ops
->streamRead(cam
->lowlevel_data
, cam
->raw_image
, 0);
2836 do_command(cam
, CPIA_COMMAND_GetCameraStatus
,0,0,0,0);
2837 return cam
->params
.status
.streamState
!= STREAM_PAUSED
;
2840 /* kernel thread function to read image from camera */
2841 static int fetch_frame(void *data
)
2843 int image_size
, retry
;
2844 struct cam_data
*cam
= (struct cam_data
*)data
;
2845 unsigned long oldjif
, rate
, diff
;
2847 /* Allow up to two bad images in a row to be read and
2848 * ignored before an error is reported */
2849 for (retry
= 0; retry
< 3; ++retry
) {
2851 DBG("retry=%d\n", retry
);
2856 /* load first frame always uncompressed */
2857 if (cam
->first_frame
&&
2858 cam
->params
.compression
.mode
!= CPIA_COMPRESSION_NONE
) {
2859 do_command(cam
, CPIA_COMMAND_SetCompression
,
2860 CPIA_COMPRESSION_NONE
,
2861 NO_DECIMATION
, 0, 0);
2862 /* Trial & error - Discarding a frame prevents the
2863 first frame from having an error in the data. */
2864 do_command(cam
, CPIA_COMMAND_DiscardFrame
, 0, 0, 0, 0);
2867 /* init camera upload */
2868 if (do_command(cam
, CPIA_COMMAND_GrabFrame
, 0,
2869 cam
->params
.streamStartLine
, 0, 0))
2872 if (cam
->ops
->wait_for_stream_ready
) {
2873 /* loop until image ready */
2875 do_command(cam
, CPIA_COMMAND_GetCameraStatus
,0,0,0,0);
2876 while (cam
->params
.status
.streamState
!= STREAM_READY
) {
2877 if(++count
> READY_TIMEOUT
)
2879 if(cam
->params
.status
.streamState
==
2882 if(!clear_stall(cam
))
2888 /* sleep for 10 ms, hopefully ;) */
2889 current
->state
= TASK_INTERRUPTIBLE
;
2891 schedule_timeout(10*HZ
/1000);
2892 if (signal_pending(current
))
2895 do_command(cam
, CPIA_COMMAND_GetCameraStatus
,
2898 if(cam
->params
.status
.streamState
!= STREAM_READY
) {
2905 /* grab image from camera */
2907 image_size
= cam
->ops
->streamRead(cam
->lowlevel_data
,
2909 if (image_size
<= 0) {
2910 DBG("streamRead failed: %d\n", image_size
);
2914 rate
= image_size
* HZ
/ 1024;
2915 diff
= jiffies
-oldjif
;
2916 cam
->transfer_rate
= diff
==0 ? rate
: rate
/diff
;
2917 /* diff==0 ? unlikely but possible */
2919 /* Switch flicker control back on if it got turned off */
2920 restart_flicker(cam
);
2922 /* If AEC is enabled, monitor the exposure and
2923 adjust the sensor frame rate if needed */
2924 if(cam
->params
.exposure
.expMode
== 2)
2925 monitor_exposure(cam
);
2927 /* camera idle now so dispatch queued commands */
2928 dispatch_commands(cam
);
2930 /* Update our knowledge of the camera state */
2931 do_command(cam
, CPIA_COMMAND_GetColourBalance
, 0, 0, 0, 0);
2932 do_command(cam
, CPIA_COMMAND_GetExposure
, 0, 0, 0, 0);
2933 do_command(cam
, CPIA_COMMAND_ReadMCPorts
, 0, 0, 0, 0);
2935 /* decompress and convert image to by copying it from
2936 * raw_image to decompressed_frame
2941 cam
->image_size
= parse_picture(cam
, image_size
);
2942 if (cam
->image_size
<= 0) {
2943 DBG("parse_picture failed %d\n", cam
->image_size
);
2944 if(cam
->params
.compression
.mode
!=
2945 CPIA_COMPRESSION_NONE
) {
2946 /* Compression may not work right if we
2947 had a bad frame, get the next one
2949 cam
->first_frame
= 1;
2950 do_command(cam
, CPIA_COMMAND_SetGrabMode
,
2951 CPIA_GRAB_SINGLE
, 0, 0, 0);
2952 /* FIXME: Trial & error - need up to 70ms for
2953 the grab mode change to complete ? */
2954 current
->state
= TASK_INTERRUPTIBLE
;
2955 schedule_timeout(70*HZ
/ 1000);
2956 if (signal_pending(current
))
2964 /* FIXME: this only works for double buffering */
2965 if (cam
->frame
[cam
->curframe
].state
== FRAME_READY
) {
2966 memcpy(cam
->frame
[cam
->curframe
].data
,
2967 cam
->decompressed_frame
.data
,
2968 cam
->decompressed_frame
.count
);
2969 cam
->frame
[cam
->curframe
].state
= FRAME_DONE
;
2971 cam
->decompressed_frame
.state
= FRAME_DONE
;
2973 if (cam
->first_frame
) {
2974 cam
->first_frame
= 0;
2975 do_command(cam
, CPIA_COMMAND_SetCompression
,
2976 cam
->params
.compression
.mode
,
2977 cam
->params
.compression
.decimation
, 0, 0);
2979 /* Switch from single-grab to continuous grab */
2980 do_command(cam
, CPIA_COMMAND_SetGrabMode
,
2981 CPIA_GRAB_CONTINUOUS
, 0, 0, 0);
2988 static int capture_frame(struct cam_data
*cam
, struct video_mmap
*vm
)
2990 if (!cam
->frame_buf
) {
2991 /* we do lazy allocation */
2993 if ((err
= allocate_frame_buf(cam
)))
2997 cam
->curframe
= vm
->frame
;
2998 cam
->frame
[cam
->curframe
].state
= FRAME_READY
;
2999 return fetch_frame(cam
);
3002 static int goto_high_power(struct cam_data
*cam
)
3004 if (do_command(cam
, CPIA_COMMAND_GotoHiPower
, 0, 0, 0, 0))
3006 current
->state
= TASK_INTERRUPTIBLE
;
3007 schedule_timeout(40*HZ
/1000); /* windows driver does it too */
3008 if(signal_pending(current
))
3010 if (do_command(cam
, CPIA_COMMAND_GetCameraStatus
, 0, 0, 0, 0))
3012 if (cam
->params
.status
.systemState
== HI_POWER_STATE
) {
3013 DBG("camera now in HIGH power state\n");
3020 static int goto_low_power(struct cam_data
*cam
)
3022 if (do_command(cam
, CPIA_COMMAND_GotoLoPower
, 0, 0, 0, 0))
3024 if (do_command(cam
, CPIA_COMMAND_GetCameraStatus
, 0, 0, 0, 0))
3026 if (cam
->params
.status
.systemState
== LO_POWER_STATE
) {
3027 DBG("camera now in LOW power state\n");
3034 static void save_camera_state(struct cam_data
*cam
)
3036 if(!(cam
->cmd_queue
& COMMAND_SETCOLOURBALANCE
))
3037 do_command(cam
, CPIA_COMMAND_GetColourBalance
, 0, 0, 0, 0);
3038 if(!(cam
->cmd_queue
& COMMAND_SETEXPOSURE
))
3039 do_command(cam
, CPIA_COMMAND_GetExposure
, 0, 0, 0, 0);
3041 DBG("%d/%d/%d/%d/%d/%d/%d/%d\n",
3042 cam
->params
.exposure
.gain
,
3043 cam
->params
.exposure
.fineExp
,
3044 cam
->params
.exposure
.coarseExpLo
,
3045 cam
->params
.exposure
.coarseExpHi
,
3046 cam
->params
.exposure
.redComp
,
3047 cam
->params
.exposure
.green1Comp
,
3048 cam
->params
.exposure
.green2Comp
,
3049 cam
->params
.exposure
.blueComp
);
3051 cam
->params
.colourBalance
.redGain
,
3052 cam
->params
.colourBalance
.greenGain
,
3053 cam
->params
.colourBalance
.blueGain
);
3056 static int set_camera_state(struct cam_data
*cam
)
3058 cam
->cmd_queue
= COMMAND_SETCOMPRESSION
|
3059 COMMAND_SETCOMPRESSIONTARGET
|
3060 COMMAND_SETCOLOURPARAMS
|
3062 COMMAND_SETYUVTHRESH
|
3063 COMMAND_SETECPTIMING
|
3064 COMMAND_SETCOMPRESSIONPARAMS
|
3065 COMMAND_SETEXPOSURE
|
3066 COMMAND_SETCOLOURBALANCE
|
3067 COMMAND_SETSENSORFPS
|
3069 COMMAND_SETFLICKERCTRL
|
3070 COMMAND_SETVLOFFSET
;
3072 do_command(cam
, CPIA_COMMAND_SetGrabMode
, CPIA_GRAB_SINGLE
,0,0,0);
3073 dispatch_commands(cam
);
3075 /* Wait 6 frames for the sensor to get all settings and
3076 AEC/ACB to settle */
3077 current
->state
= TASK_INTERRUPTIBLE
;
3078 schedule_timeout((6*(cam
->params
.sensorFps
.baserate
? 33 : 40) *
3079 (1 << cam
->params
.sensorFps
.divisor
) + 10) *
3082 if(signal_pending(current
))
3085 save_camera_state(cam
);
3090 static void get_version_information(struct cam_data
*cam
)
3092 /* GetCPIAVersion */
3093 do_command(cam
, CPIA_COMMAND_GetCPIAVersion
, 0, 0, 0, 0);
3096 do_command(cam
, CPIA_COMMAND_GetPnPID
, 0, 0, 0, 0);
3099 /* initialize camera */
3100 static int reset_camera(struct cam_data
*cam
)
3103 /* Start the camera in low power mode */
3104 if (goto_low_power(cam
)) {
3105 if (cam
->params
.status
.systemState
!= WARM_BOOT_STATE
)
3108 /* FIXME: this is just dirty trial and error */
3109 err
= goto_high_power(cam
);
3112 do_command(cam
, CPIA_COMMAND_DiscardFrame
, 0, 0, 0, 0);
3113 if (goto_low_power(cam
))
3117 /* procedure described in developer's guide p3-28 */
3119 /* Check the firmware version. */
3120 cam
->params
.version
.firmwareVersion
= 0;
3121 get_version_information(cam
);
3122 if (cam
->params
.version
.firmwareVersion
!= 1)
3125 /* A bug in firmware 1-02 limits gainMode to 2 */
3126 if(cam
->params
.version
.firmwareRevision
<= 2 &&
3127 cam
->params
.exposure
.gainMode
> 2) {
3128 cam
->params
.exposure
.gainMode
= 2;
3131 /* set QX3 detected flag */
3132 cam
->params
.qx3
.qx3_detected
= (cam
->params
.pnpID
.vendor
== 0x0813 &&
3133 cam
->params
.pnpID
.product
== 0x0001);
3135 /* The fatal error checking should be done after
3136 * the camera powers up (developer's guide p 3-38) */
3138 /* Set streamState before transition to high power to avoid bug
3139 * in firmware 1-02 */
3140 do_command(cam
, CPIA_COMMAND_ModifyCameraStatus
, STREAMSTATE
, 0,
3141 STREAM_NOT_READY
, 0);
3144 err
= goto_high_power(cam
);
3148 /* Check the camera status */
3149 if (do_command(cam
, CPIA_COMMAND_GetCameraStatus
, 0, 0, 0, 0))
3152 if (cam
->params
.status
.fatalError
) {
3153 DBG("fatal_error: %#04x\n",
3154 cam
->params
.status
.fatalError
);
3155 DBG("vp_status: %#04x\n",
3156 cam
->params
.status
.vpStatus
);
3157 if (cam
->params
.status
.fatalError
& ~(COM_FLAG
|CPIA_FLAG
)) {
3158 /* Fatal error in camera */
3160 } else if (cam
->params
.status
.fatalError
& (COM_FLAG
|CPIA_FLAG
)) {
3161 /* Firmware 1-02 may do this for parallel port cameras,
3162 * just clear the flags (developer's guide p 3-38) */
3163 do_command(cam
, CPIA_COMMAND_ModifyCameraStatus
,
3164 FATALERROR
, ~(COM_FLAG
|CPIA_FLAG
), 0, 0);
3168 /* Check the camera status again */
3169 if (cam
->params
.status
.fatalError
) {
3170 if (cam
->params
.status
.fatalError
)
3174 /* VPVersion can't be retrieved before the camera is in HiPower,
3175 * so get it here instead of in get_version_information. */
3176 do_command(cam
, CPIA_COMMAND_GetVPVersion
, 0, 0, 0, 0);
3178 /* set camera to a known state */
3179 return set_camera_state(cam
);
3182 static void put_cam(struct cpia_camera_ops
* ops
)
3185 module_put(ops
->owner
);
3188 /* ------------------------- V4L interface --------------------- */
3189 static int cpia_open(struct inode
*inode
, struct file
*file
)
3191 struct video_device
*dev
= video_devdata(file
);
3192 struct cam_data
*cam
= dev
->priv
;
3196 DBG("Internal error, cam_data not found!\n");
3200 if (cam
->open_count
> 0) {
3201 DBG("Camera already open\n");
3205 if (!try_module_get(cam
->ops
->owner
))
3208 down(&cam
->busy_lock
);
3210 if (!cam
->raw_image
) {
3211 cam
->raw_image
= rvmalloc(CPIA_MAX_IMAGE_SIZE
);
3212 if (!cam
->raw_image
)
3216 if (!cam
->decompressed_frame
.data
) {
3217 cam
->decompressed_frame
.data
= rvmalloc(CPIA_MAX_FRAME_SIZE
);
3218 if (!cam
->decompressed_frame
.data
)
3224 if (cam
->ops
->open(cam
->lowlevel_data
))
3227 /* reset the camera */
3228 if ((err
= reset_camera(cam
)) != 0) {
3229 cam
->ops
->close(cam
->lowlevel_data
);
3234 if(signal_pending(current
))
3237 /* Set ownership of /proc/cpia/videoX to current user */
3239 cam
->proc_entry
->uid
= current
->uid
;
3241 /* set mark for loading first frame uncompressed */
3242 cam
->first_frame
= 1;
3244 /* init it to something */
3245 cam
->mmap_kludge
= 0;
3248 file
->private_data
= dev
;
3249 up(&cam
->busy_lock
);
3253 if (cam
->decompressed_frame
.data
) {
3254 rvfree(cam
->decompressed_frame
.data
, CPIA_MAX_FRAME_SIZE
);
3255 cam
->decompressed_frame
.data
= NULL
;
3257 if (cam
->raw_image
) {
3258 rvfree(cam
->raw_image
, CPIA_MAX_IMAGE_SIZE
);
3259 cam
->raw_image
= NULL
;
3261 up(&cam
->busy_lock
);
3266 static int cpia_close(struct inode
*inode
, struct file
*file
)
3268 struct video_device
*dev
= file
->private_data
;
3269 struct cam_data
*cam
= dev
->priv
;
3272 /* Return ownership of /proc/cpia/videoX to root */
3274 cam
->proc_entry
->uid
= 0;
3276 /* save camera state for later open (developers guide ch 3.5.3) */
3277 save_camera_state(cam
);
3280 goto_low_power(cam
);
3282 /* Update the camera status */
3283 do_command(cam
, CPIA_COMMAND_GetCameraStatus
, 0, 0, 0, 0);
3285 /* cleanup internal state stuff */
3286 free_frames(cam
->frame
);
3289 cam
->ops
->close(cam
->lowlevel_data
);
3294 if (--cam
->open_count
== 0) {
3295 /* clean up capture-buffers */
3296 if (cam
->raw_image
) {
3297 rvfree(cam
->raw_image
, CPIA_MAX_IMAGE_SIZE
);
3298 cam
->raw_image
= NULL
;
3301 if (cam
->decompressed_frame
.data
) {
3302 rvfree(cam
->decompressed_frame
.data
, CPIA_MAX_FRAME_SIZE
);
3303 cam
->decompressed_frame
.data
= NULL
;
3307 free_frame_buf(cam
);
3312 file
->private_data
= NULL
;
3317 static ssize_t
cpia_read(struct file
*file
, char __user
*buf
,
3318 size_t count
, loff_t
*ppos
)
3320 struct video_device
*dev
= file
->private_data
;
3321 struct cam_data
*cam
= dev
->priv
;
3324 /* make this _really_ smp and multithread-safe */
3325 if (down_interruptible(&cam
->busy_lock
))
3330 up(&cam
->busy_lock
);
3336 up(&cam
->busy_lock
);
3342 up(&cam
->busy_lock
);
3347 cam
->decompressed_frame
.state
= FRAME_READY
;
3349 if((err
= fetch_frame(cam
)) != 0) {
3350 DBG("ERROR from fetch_frame: %d\n", err
);
3351 up(&cam
->busy_lock
);
3354 cam
->decompressed_frame
.state
= FRAME_UNUSED
;
3356 /* copy data to user space */
3357 if (cam
->decompressed_frame
.count
> count
) {
3358 DBG("count wrong: %d, %lu\n", cam
->decompressed_frame
.count
,
3359 (unsigned long) count
);
3360 up(&cam
->busy_lock
);
3363 if (copy_to_user(buf
, cam
->decompressed_frame
.data
,
3364 cam
->decompressed_frame
.count
)) {
3365 DBG("copy_to_user failed\n");
3366 up(&cam
->busy_lock
);
3370 up(&cam
->busy_lock
);
3371 return cam
->decompressed_frame
.count
;
3374 static int cpia_do_ioctl(struct inode
*inode
, struct file
*file
,
3375 unsigned int ioctlnr
, void *arg
)
3377 struct video_device
*dev
= file
->private_data
;
3378 struct cam_data
*cam
= dev
->priv
;
3381 if (!cam
|| !cam
->ops
)
3384 /* make this _really_ smp-safe */
3385 if (down_interruptible(&cam
->busy_lock
))
3388 //DBG("cpia_ioctl: %u\n", ioctlnr);
3391 /* query capabilites */
3394 struct video_capability
*b
= arg
;
3396 DBG("VIDIOCGCAP\n");
3397 strcpy(b
->name
, "CPiA Camera");
3398 b
->type
= VID_TYPE_CAPTURE
| VID_TYPE_SUBCAPTURE
;
3401 b
->maxwidth
= 352; /* VIDEOSIZE_CIF */
3403 b
->minwidth
= 48; /* VIDEOSIZE_48_48 */
3408 /* get/set video source - we are a camera and nothing else */
3411 struct video_channel
*v
= arg
;
3413 DBG("VIDIOCGCHAN\n");
3414 if (v
->channel
!= 0) {
3420 strcpy(v
->name
, "Camera");
3423 v
->type
= VIDEO_TYPE_CAMERA
;
3430 struct video_channel
*v
= arg
;
3432 DBG("VIDIOCSCHAN\n");
3433 if (v
->channel
!= 0)
3438 /* image properties */
3441 struct video_picture
*pic
= arg
;
3442 DBG("VIDIOCGPICT\n");
3449 struct video_picture
*vp
= arg
;
3451 DBG("VIDIOCSPICT\n");
3453 /* check validity */
3454 DBG("palette: %d\n", vp
->palette
);
3455 DBG("depth: %d\n", vp
->depth
);
3456 if (!valid_mode(vp
->palette
, vp
->depth
)) {
3461 down(&cam
->param_lock
);
3462 /* brightness, colour, contrast need no check 0-65535 */
3464 /* update cam->params.colourParams */
3465 cam
->params
.colourParams
.brightness
= vp
->brightness
*100/65535;
3466 cam
->params
.colourParams
.contrast
= vp
->contrast
*100/65535;
3467 cam
->params
.colourParams
.saturation
= vp
->colour
*100/65535;
3468 /* contrast is in steps of 8, so round */
3469 cam
->params
.colourParams
.contrast
=
3470 ((cam
->params
.colourParams
.contrast
+ 3) / 8) * 8;
3471 if (cam
->params
.version
.firmwareVersion
== 1 &&
3472 cam
->params
.version
.firmwareRevision
== 2 &&
3473 cam
->params
.colourParams
.contrast
> 80) {
3474 /* 1-02 firmware limits contrast to 80 */
3475 cam
->params
.colourParams
.contrast
= 80;
3478 /* Adjust flicker control if necessary */
3479 if(cam
->params
.flickerControl
.allowableOverExposure
< 0)
3480 cam
->params
.flickerControl
.allowableOverExposure
=
3481 -find_over_exposure(cam
->params
.colourParams
.brightness
);
3482 if(cam
->params
.flickerControl
.flickerMode
!= 0)
3483 cam
->cmd_queue
|= COMMAND_SETFLICKERCTRL
;
3486 /* queue command to update camera */
3487 cam
->cmd_queue
|= COMMAND_SETCOLOURPARAMS
;
3488 up(&cam
->param_lock
);
3489 DBG("VIDIOCSPICT: %d / %d // %d / %d / %d / %d\n",
3490 vp
->depth
, vp
->palette
, vp
->brightness
, vp
->hue
, vp
->colour
,
3495 /* get/set capture window */
3498 struct video_window
*vw
= arg
;
3499 DBG("VIDIOCGWIN\n");
3507 /* copy_from_user, check validity, copy to internal structure */
3508 struct video_window
*vw
= arg
;
3509 DBG("VIDIOCSWIN\n");
3511 if (vw
->clipcount
!= 0) { /* clipping not supported */
3515 if (vw
->clips
!= NULL
) { /* clipping not supported */
3520 /* we set the video window to something smaller or equal to what
3521 * is requested by the user???
3523 down(&cam
->param_lock
);
3524 if (vw
->width
!= cam
->vw
.width
|| vw
->height
!= cam
->vw
.height
) {
3525 int video_size
= match_videosize(vw
->width
, vw
->height
);
3527 if (video_size
< 0) {
3529 up(&cam
->param_lock
);
3532 cam
->video_size
= video_size
;
3534 /* video size is changing, reset the subcapture area */
3535 memset(&cam
->vc
, 0, sizeof(cam
->vc
));
3538 DBG("%d / %d\n", cam
->vw
.width
, cam
->vw
.height
);
3539 cam
->cmd_queue
|= COMMAND_SETFORMAT
;
3542 up(&cam
->param_lock
);
3544 /* setformat ignored by camera during streaming,
3545 * so stop/dispatch/start */
3546 if (cam
->cmd_queue
& COMMAND_SETFORMAT
) {
3548 dispatch_commands(cam
);
3550 DBG("%d/%d:%d\n", cam
->video_size
,
3551 cam
->vw
.width
, cam
->vw
.height
);
3555 /* mmap interface */
3558 struct video_mbuf
*vm
= arg
;
3561 DBG("VIDIOCGMBUF\n");
3562 memset(vm
, 0, sizeof(*vm
));
3563 vm
->size
= CPIA_MAX_FRAME_SIZE
*FRAME_NUM
;
3564 vm
->frames
= FRAME_NUM
;
3565 for (i
= 0; i
< FRAME_NUM
; i
++)
3566 vm
->offsets
[i
] = CPIA_MAX_FRAME_SIZE
* i
;
3570 case VIDIOCMCAPTURE
:
3572 struct video_mmap
*vm
= arg
;
3575 DBG("VIDIOCMCAPTURE: %d / %d / %dx%d\n", vm
->format
, vm
->frame
,
3576 vm
->width
, vm
->height
);
3577 if (vm
->frame
<0||vm
->frame
>=FRAME_NUM
) {
3582 /* set video format */
3583 cam
->vp
.palette
= vm
->format
;
3584 switch(vm
->format
) {
3585 case VIDEO_PALETTE_GREY
:
3588 case VIDEO_PALETTE_RGB555
:
3589 case VIDEO_PALETTE_RGB565
:
3590 case VIDEO_PALETTE_YUV422
:
3591 case VIDEO_PALETTE_YUYV
:
3592 case VIDEO_PALETTE_UYVY
:
3595 case VIDEO_PALETTE_RGB24
:
3598 case VIDEO_PALETTE_RGB32
:
3608 /* set video size */
3609 video_size
= match_videosize(vm
->width
, vm
->height
);
3610 if (video_size
< 0) {
3614 if (video_size
!= cam
->video_size
) {
3615 cam
->video_size
= video_size
;
3617 /* video size is changing, reset the subcapture area */
3618 memset(&cam
->vc
, 0, sizeof(cam
->vc
));
3621 cam
->cmd_queue
|= COMMAND_SETFORMAT
;
3622 dispatch_commands(cam
);
3624 /* according to v4l-spec we must start streaming here */
3625 cam
->mmap_kludge
= 1;
3626 retval
= capture_frame(cam
, vm
);
3635 //DBG("VIDIOCSYNC: %d\n", *frame);
3637 if (*frame
<0 || *frame
>= FRAME_NUM
) {
3642 switch (cam
->frame
[*frame
].state
) {
3645 case FRAME_GRABBING
:
3646 DBG("sync to unused frame %d\n", *frame
);
3651 cam
->frame
[*frame
].state
= FRAME_UNUSED
;
3652 //DBG("VIDIOCSYNC: %d synced\n", *frame);
3655 if (retval
== -EINTR
) {
3656 /* FIXME - xawtv does not handle this nice */
3662 case VIDIOCGCAPTURE
:
3664 struct video_capture
*vc
= arg
;
3666 DBG("VIDIOCGCAPTURE\n");
3673 case VIDIOCSCAPTURE
:
3675 struct video_capture
*vc
= arg
;
3677 DBG("VIDIOCSCAPTURE\n");
3679 if (vc
->decimation
!= 0) { /* How should this be used? */
3683 if (vc
->flags
!= 0) { /* Even/odd grab not supported */
3688 /* Clip to the resolution we can set for the ROI
3689 (every 8 columns and 4 rows) */
3690 vc
->x
= vc
->x
& ~(__u32
)7;
3691 vc
->y
= vc
->y
& ~(__u32
)3;
3692 vc
->width
= vc
->width
& ~(__u32
)7;
3693 vc
->height
= vc
->height
& ~(__u32
)3;
3695 if(vc
->width
== 0 || vc
->height
== 0 ||
3696 vc
->x
+ vc
->width
> cam
->vw
.width
||
3697 vc
->y
+ vc
->height
> cam
->vw
.height
) {
3702 DBG("%d,%d/%dx%d\n", vc
->x
,vc
->y
,vc
->width
, vc
->height
);
3704 down(&cam
->param_lock
);
3708 cam
->vc
.width
= vc
->width
;
3709 cam
->vc
.height
= vc
->height
;
3712 cam
->cmd_queue
|= COMMAND_SETFORMAT
;
3714 up(&cam
->param_lock
);
3716 /* setformat ignored by camera during streaming,
3717 * so stop/dispatch/start */
3718 dispatch_commands(cam
);
3724 struct video_unit
*vu
= arg
;
3726 DBG("VIDIOCGUNIT\n");
3728 vu
->video
= cam
->vdev
.minor
;
3729 vu
->vbi
= VIDEO_NO_UNIT
;
3730 vu
->radio
= VIDEO_NO_UNIT
;
3731 vu
->audio
= VIDEO_NO_UNIT
;
3732 vu
->teletext
= VIDEO_NO_UNIT
;
3738 /* pointless to implement overlay with this camera */
3743 /* tuner interface - we have none */
3748 /* audio interface - we have none */
3754 retval
= -ENOIOCTLCMD
;
3758 up(&cam
->busy_lock
);
3762 static int cpia_ioctl(struct inode
*inode
, struct file
*file
,
3763 unsigned int cmd
, unsigned long arg
)
3765 return video_usercopy(inode
, file
, cmd
, arg
, cpia_do_ioctl
);
3770 static int cpia_mmap(struct file
*file
, struct vm_area_struct
*vma
)
3772 struct video_device
*dev
= file
->private_data
;
3773 unsigned long start
= vma
->vm_start
;
3774 unsigned long size
= vma
->vm_end
- vma
->vm_start
;
3775 unsigned long page
, pos
;
3776 struct cam_data
*cam
= dev
->priv
;
3779 if (!cam
|| !cam
->ops
)
3782 DBG("cpia_mmap: %ld\n", size
);
3784 if (size
> FRAME_NUM
*CPIA_MAX_FRAME_SIZE
)
3787 if (!cam
|| !cam
->ops
)
3790 /* make this _really_ smp-safe */
3791 if (down_interruptible(&cam
->busy_lock
))
3794 if (!cam
->frame_buf
) { /* we do lazy allocation */
3795 if ((retval
= allocate_frame_buf(cam
))) {
3796 up(&cam
->busy_lock
);
3801 pos
= (unsigned long)(cam
->frame_buf
);
3803 page
= kvirt_to_pa(pos
);
3804 if (remap_page_range(vma
, start
, page
, PAGE_SIZE
, PAGE_SHARED
)) {
3805 up(&cam
->busy_lock
);
3810 if (size
> PAGE_SIZE
)
3816 DBG("cpia_mmap: %ld\n", size
);
3817 up(&cam
->busy_lock
);
3822 static struct file_operations cpia_fops
= {
3823 .owner
= THIS_MODULE
,
3825 .release
= cpia_close
,
3828 .ioctl
= cpia_ioctl
,
3829 .llseek
= no_llseek
,
3832 static struct video_device cpia_template
= {
3833 .owner
= THIS_MODULE
,
3834 .name
= "CPiA Camera",
3835 .type
= VID_TYPE_CAPTURE
,
3836 .hardware
= VID_HARDWARE_CPIA
,
3840 /* initialise cam_data structure */
3841 static void reset_camera_struct(struct cam_data
*cam
)
3843 /* The following parameter values are the defaults from
3844 * "Software Developer's Guide for CPiA Cameras". Any changes
3845 * to the defaults are noted in comments. */
3846 cam
->params
.colourParams
.brightness
= 50;
3847 cam
->params
.colourParams
.contrast
= 48;
3848 cam
->params
.colourParams
.saturation
= 50;
3849 cam
->params
.exposure
.gainMode
= 4;
3850 cam
->params
.exposure
.expMode
= 2; /* AEC */
3851 cam
->params
.exposure
.compMode
= 1;
3852 cam
->params
.exposure
.centreWeight
= 1;
3853 cam
->params
.exposure
.gain
= 0;
3854 cam
->params
.exposure
.fineExp
= 0;
3855 cam
->params
.exposure
.coarseExpLo
= 185;
3856 cam
->params
.exposure
.coarseExpHi
= 0;
3857 cam
->params
.exposure
.redComp
= COMP_RED
;
3858 cam
->params
.exposure
.green1Comp
= COMP_GREEN1
;
3859 cam
->params
.exposure
.green2Comp
= COMP_GREEN2
;
3860 cam
->params
.exposure
.blueComp
= COMP_BLUE
;
3861 cam
->params
.colourBalance
.balanceMode
= 2; /* ACB */
3862 cam
->params
.colourBalance
.redGain
= 32;
3863 cam
->params
.colourBalance
.greenGain
= 6;
3864 cam
->params
.colourBalance
.blueGain
= 92;
3865 cam
->params
.apcor
.gain1
= 0x18;
3866 cam
->params
.apcor
.gain2
= 0x16;
3867 cam
->params
.apcor
.gain4
= 0x24;
3868 cam
->params
.apcor
.gain8
= 0x34;
3869 cam
->params
.flickerControl
.flickerMode
= 0;
3870 cam
->params
.flickerControl
.disabled
= 1;
3872 cam
->params
.flickerControl
.coarseJump
=
3873 flicker_jumps
[cam
->mainsFreq
]
3874 [cam
->params
.sensorFps
.baserate
]
3875 [cam
->params
.sensorFps
.divisor
];
3876 cam
->params
.flickerControl
.allowableOverExposure
=
3877 -find_over_exposure(cam
->params
.colourParams
.brightness
);
3878 cam
->params
.vlOffset
.gain1
= 20;
3879 cam
->params
.vlOffset
.gain2
= 24;
3880 cam
->params
.vlOffset
.gain4
= 26;
3881 cam
->params
.vlOffset
.gain8
= 26;
3882 cam
->params
.compressionParams
.hysteresis
= 3;
3883 cam
->params
.compressionParams
.threshMax
= 11;
3884 cam
->params
.compressionParams
.smallStep
= 1;
3885 cam
->params
.compressionParams
.largeStep
= 3;
3886 cam
->params
.compressionParams
.decimationHysteresis
= 2;
3887 cam
->params
.compressionParams
.frDiffStepThresh
= 5;
3888 cam
->params
.compressionParams
.qDiffStepThresh
= 3;
3889 cam
->params
.compressionParams
.decimationThreshMod
= 2;
3890 /* End of default values from Software Developer's Guide */
3892 cam
->transfer_rate
= 0;
3893 cam
->exposure_status
= EXPOSURE_NORMAL
;
3895 /* Set Sensor FPS to 15fps. This seems better than 30fps
3896 * for indoor lighting. */
3897 cam
->params
.sensorFps
.divisor
= 1;
3898 cam
->params
.sensorFps
.baserate
= 1;
3900 cam
->params
.yuvThreshold
.yThreshold
= 6; /* From windows driver */
3901 cam
->params
.yuvThreshold
.uvThreshold
= 6; /* From windows driver */
3903 cam
->params
.format
.subSample
= SUBSAMPLE_422
;
3904 cam
->params
.format
.yuvOrder
= YUVORDER_YUYV
;
3906 cam
->params
.compression
.mode
= CPIA_COMPRESSION_AUTO
;
3907 cam
->params
.compressionTarget
.frTargeting
=
3908 CPIA_COMPRESSION_TARGET_QUALITY
;
3909 cam
->params
.compressionTarget
.targetFR
= 15; /* From windows driver */
3910 cam
->params
.compressionTarget
.targetQ
= 5; /* From windows driver */
3912 cam
->params
.qx3
.qx3_detected
= 0;
3913 cam
->params
.qx3
.toplight
= 0;
3914 cam
->params
.qx3
.bottomlight
= 0;
3915 cam
->params
.qx3
.button
= 0;
3916 cam
->params
.qx3
.cradled
= 0;
3918 cam
->video_size
= VIDEOSIZE_CIF
;
3920 cam
->vp
.colour
= 32768; /* 50% */
3921 cam
->vp
.hue
= 32768; /* 50% */
3922 cam
->vp
.brightness
= 32768; /* 50% */
3923 cam
->vp
.contrast
= 32768; /* 50% */
3924 cam
->vp
.whiteness
= 0; /* not used -> grayscale only */
3925 cam
->vp
.depth
= 24; /* to be set by user */
3926 cam
->vp
.palette
= VIDEO_PALETTE_RGB24
; /* to be set by user */
3936 cam
->vw
.chromakey
= 0;
3938 cam
->vw
.clipcount
= 0;
3939 cam
->vw
.clips
= NULL
;
3941 cam
->cmd_queue
= COMMAND_NONE
;
3942 cam
->first_frame
= 1;
3947 /* initialize cam_data structure */
3948 static void init_camera_struct(struct cam_data
*cam
,
3949 struct cpia_camera_ops
*ops
)
3953 /* Default everything to 0 */
3954 memset(cam
, 0, sizeof(struct cam_data
));
3957 init_MUTEX(&cam
->param_lock
);
3958 init_MUTEX(&cam
->busy_lock
);
3960 reset_camera_struct(cam
);
3962 cam
->proc_entry
= NULL
;
3964 memcpy(&cam
->vdev
, &cpia_template
, sizeof(cpia_template
));
3965 cam
->vdev
.priv
= cam
;
3968 for (i
= 0; i
< FRAME_NUM
; i
++) {
3969 cam
->frame
[i
].width
= 0;
3970 cam
->frame
[i
].height
= 0;
3971 cam
->frame
[i
].state
= FRAME_UNUSED
;
3972 cam
->frame
[i
].data
= NULL
;
3974 cam
->decompressed_frame
.width
= 0;
3975 cam
->decompressed_frame
.height
= 0;
3976 cam
->decompressed_frame
.state
= FRAME_UNUSED
;
3977 cam
->decompressed_frame
.data
= NULL
;
3980 struct cam_data
*cpia_register_camera(struct cpia_camera_ops
*ops
, void *lowlevel
)
3982 struct cam_data
*camera
;
3984 if ((camera
= kmalloc(sizeof(struct cam_data
), GFP_KERNEL
)) == NULL
)
3988 init_camera_struct( camera
, ops
);
3989 camera
->lowlevel_data
= lowlevel
;
3991 /* register v4l device */
3992 if (video_register_device(&camera
->vdev
, VFL_TYPE_GRABBER
, video_nr
) == -1) {
3994 printk(KERN_DEBUG
"video_register_device failed\n");
3998 /* get version information from camera: open/reset/close */
4001 if (camera
->ops
->open(camera
->lowlevel_data
))
4004 /* reset the camera */
4005 if (reset_camera(camera
) != 0) {
4006 camera
->ops
->close(camera
->lowlevel_data
);
4011 camera
->ops
->close(camera
->lowlevel_data
);
4013 #ifdef CONFIG_PROC_FS
4014 create_proc_cpia_cam(camera
);
4017 printk(KERN_INFO
" CPiA Version: %d.%02d (%d.%d)\n",
4018 camera
->params
.version
.firmwareVersion
,
4019 camera
->params
.version
.firmwareRevision
,
4020 camera
->params
.version
.vcVersion
,
4021 camera
->params
.version
.vcRevision
);
4022 printk(KERN_INFO
" CPiA PnP-ID: %04x:%04x:%04x\n",
4023 camera
->params
.pnpID
.vendor
,
4024 camera
->params
.pnpID
.product
,
4025 camera
->params
.pnpID
.deviceRevision
);
4026 printk(KERN_INFO
" VP-Version: %d.%d %04x\n",
4027 camera
->params
.vpVersion
.vpVersion
,
4028 camera
->params
.vpVersion
.vpRevision
,
4029 camera
->params
.vpVersion
.cameraHeadID
);
4034 void cpia_unregister_camera(struct cam_data
*cam
)
4036 DBG("unregistering video\n");
4037 video_unregister_device(&cam
->vdev
);
4038 if (cam
->open_count
) {
4040 DBG("camera open -- setting ops to NULL\n");
4044 #ifdef CONFIG_PROC_FS
4045 DBG("destroying /proc/cpia/video%d\n", cam
->vdev
.minor
);
4046 destroy_proc_cpia_cam(cam
);
4048 if (!cam
->open_count
) {
4049 DBG("freeing camera\n");
4054 static int __init
cpia_init(void)
4056 printk(KERN_INFO
"%s v%d.%d.%d\n", ABOUT
,
4057 CPIA_MAJ_VER
, CPIA_MIN_VER
, CPIA_PATCH_VER
);
4059 printk(KERN_WARNING
"Since in-kernel colorspace conversion is not "
4060 "allowed, it is disabled by default now. Users should fix the "
4061 "applications in case they don't work without conversion "
4062 "reenabled by setting the 'colorspace_conv' module "
4065 #ifdef CONFIG_PROC_FS
4070 #ifdef CONFIG_VIDEO_CPIA_PP_MODULE
4071 request_module("cpia_pp");
4074 #ifdef CONFIG_VIDEO_CPIA_USB_MODULE
4075 request_module("cpia_usb");
4077 #endif /* CONFIG_KMOD */
4079 #ifdef CONFIG_VIDEO_CPIA_PP
4082 #ifdef CONFIG_VIDEO_CPIA_USB
4088 static void __exit
cpia_exit(void)
4090 #ifdef CONFIG_PROC_FS
4091 proc_cpia_destroy();
4095 module_init(cpia_init
);
4096 module_exit(cpia_exit
);
4098 /* Exported symbols for modules. */
4100 EXPORT_SYMBOL(cpia_register_camera
);
4101 EXPORT_SYMBOL(cpia_unregister_camera
);