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