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) */
27 /* #define _CPIA_DEBUG_  1 */
28 
29 #include <linux/config.h>
30 
31 #include <linux/module.h>
32 #include <linux/version.h>
33 #include <linux/init.h>
34 #include <linux/fs.h>
35 #include <linux/vmalloc.h>
36 #include <linux/delay.h>
37 #include <linux/slab.h>
38 #include <linux/proc_fs.h>
39 #include <linux/ctype.h>
40 #include <linux/pagemap.h>
41 #include <asm/io.h>
42 #include <asm/semaphore.h>
43 #include <linux/wrapper.h>
44 
45 #ifdef CONFIG_KMOD
46 #include <linux/kmod.h>
47 #endif
48 
49 #include "cpia.h"
50 
51 #ifdef CONFIG_VIDEO_CPIA_PP
52 extern int cpia_pp_init(void);
53 #endif
54 #ifdef CONFIG_VIDEO_CPIA_USB
55 extern int cpia_usb_init(void);
56 #endif
57 
58 static int video_nr = -1;
59 
60 #ifdef MODULE
61 MODULE_PARM(video_nr,"i");
62 MODULE_AUTHOR("Scott J. Bertin <sbertin@securenym.net> & Peter Pregler <Peter_Pregler@email.com> & Johannes Erdfelt <johannes@erdfeld.com>");
63 MODULE_DESCRIPTION("V4L-driver for Vision CPiA based cameras");
64 MODULE_LICENSE("GPL");
65 MODULE_SUPPORTED_DEVICE("video");
66 #endif
67 
68 #define ABOUT "V4L-Driver for Vision CPiA based cameras"
69 
70 #ifndef VID_HARDWARE_CPIA
71 #define VID_HARDWARE_CPIA 24    /* FIXME -> from linux/videodev.h */
72 #endif
73 
74 #define CPIA_MODULE_CPIA			(0<<5)
75 #define CPIA_MODULE_SYSTEM			(1<<5)
76 #define CPIA_MODULE_VP_CTRL			(5<<5)
77 #define CPIA_MODULE_CAPTURE			(6<<5)
78 #define CPIA_MODULE_DEBUG			(7<<5)
79 
80 #define INPUT (DATA_IN << 8)
81 #define OUTPUT (DATA_OUT << 8)
82 
83 #define CPIA_COMMAND_GetCPIAVersion	(INPUT | CPIA_MODULE_CPIA | 1)
84 #define CPIA_COMMAND_GetPnPID		(INPUT | CPIA_MODULE_CPIA | 2)
85 #define CPIA_COMMAND_GetCameraStatus	(INPUT | CPIA_MODULE_CPIA | 3)
86 #define CPIA_COMMAND_GotoHiPower	(OUTPUT | CPIA_MODULE_CPIA | 4)
87 #define CPIA_COMMAND_GotoLoPower	(OUTPUT | CPIA_MODULE_CPIA | 5)
88 #define CPIA_COMMAND_GotoSuspend	(OUTPUT | CPIA_MODULE_CPIA | 7)
89 #define CPIA_COMMAND_GotoPassThrough	(OUTPUT | CPIA_MODULE_CPIA | 8)
90 #define CPIA_COMMAND_ModifyCameraStatus	(OUTPUT | CPIA_MODULE_CPIA | 10)
91 
92 #define CPIA_COMMAND_ReadVCRegs		(INPUT | CPIA_MODULE_SYSTEM | 1)
93 #define CPIA_COMMAND_WriteVCReg		(OUTPUT | CPIA_MODULE_SYSTEM | 2)
94 #define CPIA_COMMAND_ReadMCPorts	(INPUT | CPIA_MODULE_SYSTEM | 3)
95 #define CPIA_COMMAND_WriteMCPort	(OUTPUT | CPIA_MODULE_SYSTEM | 4)
96 #define CPIA_COMMAND_SetBaudRate	(OUTPUT | CPIA_MODULE_SYSTEM | 5)
97 #define CPIA_COMMAND_SetECPTiming	(OUTPUT | CPIA_MODULE_SYSTEM | 6)
98 #define CPIA_COMMAND_ReadIDATA		(INPUT | CPIA_MODULE_SYSTEM | 7)
99 #define CPIA_COMMAND_WriteIDATA		(OUTPUT | CPIA_MODULE_SYSTEM | 8)
100 #define CPIA_COMMAND_GenericCall	(OUTPUT | CPIA_MODULE_SYSTEM | 9)
101 #define CPIA_COMMAND_I2CStart		(OUTPUT | CPIA_MODULE_SYSTEM | 10)
102 #define CPIA_COMMAND_I2CStop		(OUTPUT | CPIA_MODULE_SYSTEM | 11)
103 #define CPIA_COMMAND_I2CWrite		(OUTPUT | CPIA_MODULE_SYSTEM | 12)
104 #define CPIA_COMMAND_I2CRead		(INPUT | CPIA_MODULE_SYSTEM | 13)
105 
106 #define CPIA_COMMAND_GetVPVersion	(INPUT | CPIA_MODULE_VP_CTRL | 1)
107 #define CPIA_COMMAND_SetColourParams	(OUTPUT | CPIA_MODULE_VP_CTRL | 3)
108 #define CPIA_COMMAND_SetExposure	(OUTPUT | CPIA_MODULE_VP_CTRL | 4)
109 #define CPIA_COMMAND_SetColourBalance	(OUTPUT | CPIA_MODULE_VP_CTRL | 6)
110 #define CPIA_COMMAND_SetSensorFPS	(OUTPUT | CPIA_MODULE_VP_CTRL | 7)
111 #define CPIA_COMMAND_SetVPDefaults	(OUTPUT | CPIA_MODULE_VP_CTRL | 8)
112 #define CPIA_COMMAND_SetApcor		(OUTPUT | CPIA_MODULE_VP_CTRL | 9)
113 #define CPIA_COMMAND_SetFlickerCtrl	(OUTPUT | CPIA_MODULE_VP_CTRL | 10)
114 #define CPIA_COMMAND_SetVLOffset	(OUTPUT | CPIA_MODULE_VP_CTRL | 11)
115 #define CPIA_COMMAND_GetColourParams	(INPUT | CPIA_MODULE_VP_CTRL | 16)
116 #define CPIA_COMMAND_GetColourBalance	(INPUT | CPIA_MODULE_VP_CTRL | 17)
117 #define CPIA_COMMAND_GetExposure	(INPUT | CPIA_MODULE_VP_CTRL | 18)
118 #define CPIA_COMMAND_SetSensorMatrix	(OUTPUT | CPIA_MODULE_VP_CTRL | 19)
119 #define CPIA_COMMAND_ColourBars		(OUTPUT | CPIA_MODULE_VP_CTRL | 25)
120 #define CPIA_COMMAND_ReadVPRegs		(INPUT | CPIA_MODULE_VP_CTRL | 30)
121 #define CPIA_COMMAND_WriteVPReg		(OUTPUT | CPIA_MODULE_VP_CTRL | 31)
122 
123 #define CPIA_COMMAND_GrabFrame		(OUTPUT | CPIA_MODULE_CAPTURE | 1)
124 #define CPIA_COMMAND_UploadFrame	(OUTPUT | CPIA_MODULE_CAPTURE | 2)
125 #define CPIA_COMMAND_SetGrabMode	(OUTPUT | CPIA_MODULE_CAPTURE | 3)
126 #define CPIA_COMMAND_InitStreamCap	(OUTPUT | CPIA_MODULE_CAPTURE | 4)
127 #define CPIA_COMMAND_FiniStreamCap	(OUTPUT | CPIA_MODULE_CAPTURE | 5)
128 #define CPIA_COMMAND_StartStreamCap	(OUTPUT | CPIA_MODULE_CAPTURE | 6)
129 #define CPIA_COMMAND_EndStreamCap	(OUTPUT | CPIA_MODULE_CAPTURE | 7)
130 #define CPIA_COMMAND_SetFormat		(OUTPUT | CPIA_MODULE_CAPTURE | 8)
131 #define CPIA_COMMAND_SetROI		(OUTPUT | CPIA_MODULE_CAPTURE | 9)
132 #define CPIA_COMMAND_SetCompression	(OUTPUT | CPIA_MODULE_CAPTURE | 10)
133 #define CPIA_COMMAND_SetCompressionTarget (OUTPUT | CPIA_MODULE_CAPTURE | 11)
134 #define CPIA_COMMAND_SetYUVThresh	(OUTPUT | CPIA_MODULE_CAPTURE | 12)
135 #define CPIA_COMMAND_SetCompressionParams (OUTPUT | CPIA_MODULE_CAPTURE | 13)
136 #define CPIA_COMMAND_DiscardFrame	(OUTPUT | CPIA_MODULE_CAPTURE | 14)
137 
138 #define CPIA_COMMAND_OutputRS232	(OUTPUT | CPIA_MODULE_DEBUG | 1)
139 #define CPIA_COMMAND_AbortProcess	(OUTPUT | CPIA_MODULE_DEBUG | 4)
140 #define CPIA_COMMAND_SetDramPage	(OUTPUT | CPIA_MODULE_DEBUG | 5)
141 #define CPIA_COMMAND_StartDramUpload	(OUTPUT | CPIA_MODULE_DEBUG | 6)
142 #define CPIA_COMMAND_StartDummyDtream	(OUTPUT | CPIA_MODULE_DEBUG | 8)
143 #define CPIA_COMMAND_AbortStream	(OUTPUT | CPIA_MODULE_DEBUG | 9)
144 #define CPIA_COMMAND_DownloadDRAM	(OUTPUT | CPIA_MODULE_DEBUG | 10)
145 
146 enum {
147 	FRAME_READY,		/* Ready to grab into */
148 	FRAME_GRABBING,		/* In the process of being grabbed into */
149 	FRAME_DONE,		/* Finished grabbing, but not been synced yet */
150 	FRAME_UNUSED,		/* Unused (no MCAPTURE) */
151 };
152 
153 #define COMMAND_NONE			0x0000
154 #define COMMAND_SETCOMPRESSION		0x0001
155 #define COMMAND_SETCOMPRESSIONTARGET	0x0002
156 #define COMMAND_SETCOLOURPARAMS		0x0004
157 #define COMMAND_SETFORMAT		0x0008
158 #define COMMAND_PAUSE			0x0010
159 #define COMMAND_RESUME			0x0020
160 #define COMMAND_SETYUVTHRESH		0x0040
161 #define COMMAND_SETECPTIMING		0x0080
162 #define COMMAND_SETCOMPRESSIONPARAMS	0x0100
163 #define COMMAND_SETEXPOSURE		0x0200
164 #define COMMAND_SETCOLOURBALANCE	0x0400
165 #define COMMAND_SETSENSORFPS		0x0800
166 #define COMMAND_SETAPCOR		0x1000
167 #define COMMAND_SETFLICKERCTRL		0x2000
168 #define COMMAND_SETVLOFFSET		0x4000
169 #define COMMAND_SETLIGHTS		0x8000
170 
171 /* Developer's Guide Table 5 p 3-34
172  * indexed by [mains][sensorFps.baserate][sensorFps.divisor]*/
173 static u8 flicker_jumps[2][2][4] =
174 { { { 76, 38, 19, 9 }, { 92, 46, 23, 11 } },
175   { { 64, 32, 16, 8 }, { 76, 38, 19, 9} }
176 };
177 
178 /* forward declaration of local function */
179 static void reset_camera_struct(struct cam_data *cam);
180 
181 /**********************************************************************
182  *
183  * Memory management
184  *
185  **********************************************************************/
186 
187 /* Here we want the physical address of the memory.
188  * This is used when initializing the contents of the area.
189  */
kvirt_to_pa(unsigned long adr)190 static inline unsigned long kvirt_to_pa(unsigned long adr)
191 {
192 	unsigned long kva, ret;
193 
194 	kva = (unsigned long) page_address(vmalloc_to_page((void *)adr));
195 	kva |= adr & (PAGE_SIZE-1); /* restore the offset */
196 	ret = __pa(kva);
197 	return ret;
198 }
199 
rvmalloc(unsigned long size)200 static void *rvmalloc(unsigned long size)
201 {
202 	void *mem;
203 	unsigned long adr;
204 
205 	size = PAGE_ALIGN(size);
206 	mem = vmalloc_32(size);
207 	if (!mem)
208 		return NULL;
209 
210 	memset(mem, 0, size); /* Clear the ram out, no junk to the user */
211 	adr = (unsigned long) mem;
212 	while (size > 0) {
213 		mem_map_reserve(vmalloc_to_page((void *)adr));
214 		adr += PAGE_SIZE;
215 		size -= PAGE_SIZE;
216 	}
217 
218 	return mem;
219 }
220 
rvfree(void * mem,unsigned long size)221 static void rvfree(void *mem, unsigned long size)
222 {
223 	unsigned long adr;
224 
225 	if (!mem)
226 		return;
227 
228 	adr = (unsigned long) mem;
229 	while ((long) size > 0) {
230 		mem_map_unreserve(vmalloc_to_page((void *)adr));
231 		adr += PAGE_SIZE;
232 		size -= PAGE_SIZE;
233 	}
234 	vfree(mem);
235 }
236 
237 /**********************************************************************
238  *
239  * /proc interface
240  *
241  **********************************************************************/
242 #ifdef CONFIG_PROC_FS
243 static struct proc_dir_entry *cpia_proc_root=NULL;
244 
cpia_read_proc(char * page,char ** start,off_t off,int count,int * eof,void * data)245 static int cpia_read_proc(char *page, char **start, off_t off,
246                           int count, int *eof, void *data)
247 {
248 	char *out = page;
249 	int len, tmp;
250 	struct cam_data *cam = data;
251 	char tmpstr[29];
252 
253 	/* IMPORTANT: This output MUST be kept under PAGE_SIZE
254 	 *            or we need to get more sophisticated. */
255 
256 	out += sprintf(out, "read-only\n-----------------------\n");
257 	out += sprintf(out, "V4L Driver version:       %d.%d.%d\n",
258 		       CPIA_MAJ_VER, CPIA_MIN_VER, CPIA_PATCH_VER);
259 	out += sprintf(out, "CPIA Version:             %d.%02d (%d.%d)\n",
260 	               cam->params.version.firmwareVersion,
261 	               cam->params.version.firmwareRevision,
262 	               cam->params.version.vcVersion,
263 	               cam->params.version.vcRevision);
264 	out += sprintf(out, "CPIA PnP-ID:              %04x:%04x:%04x\n",
265 	               cam->params.pnpID.vendor, cam->params.pnpID.product,
266 	               cam->params.pnpID.deviceRevision);
267 	out += sprintf(out, "VP-Version:               %d.%d %04x\n",
268 	               cam->params.vpVersion.vpVersion,
269 	               cam->params.vpVersion.vpRevision,
270 	               cam->params.vpVersion.cameraHeadID);
271 
272 	out += sprintf(out, "system_state:             %#04x\n",
273 	               cam->params.status.systemState);
274 	out += sprintf(out, "grab_state:               %#04x\n",
275 	               cam->params.status.grabState);
276 	out += sprintf(out, "stream_state:             %#04x\n",
277 	               cam->params.status.streamState);
278 	out += sprintf(out, "fatal_error:              %#04x\n",
279 	               cam->params.status.fatalError);
280 	out += sprintf(out, "cmd_error:                %#04x\n",
281 	               cam->params.status.cmdError);
282 	out += sprintf(out, "debug_flags:              %#04x\n",
283 	               cam->params.status.debugFlags);
284 	out += sprintf(out, "vp_status:                %#04x\n",
285 	               cam->params.status.vpStatus);
286 	out += sprintf(out, "error_code:               %#04x\n",
287 	               cam->params.status.errorCode);
288 	/* QX3 specific entries */
289 	if (cam->params.qx3.qx3_detected) {
290 		out += sprintf(out, "button:                   %4d\n",
291 		               cam->params.qx3.button);
292 		out += sprintf(out, "cradled:                  %4d\n",
293 		               cam->params.qx3.cradled);
294 	}
295 	out += sprintf(out, "video_size:               %s\n",
296 	               cam->params.format.videoSize == VIDEOSIZE_CIF ?
297 		       "CIF " : "QCIF");
298 	out += sprintf(out, "sub_sample:               %s\n",
299 	               cam->params.format.subSample == SUBSAMPLE_420 ?
300 		       "420" : "422");
301 	out += sprintf(out, "yuv_order:                %s\n",
302 	               cam->params.format.yuvOrder == YUVORDER_YUYV ?
303 		       "YUYV" : "UYVY");
304 	out += sprintf(out, "roi:                      (%3d, %3d) to (%3d, %3d)\n",
305 	               cam->params.roi.colStart*8,
306 	               cam->params.roi.rowStart*4,
307 	               cam->params.roi.colEnd*8,
308 	               cam->params.roi.rowEnd*4);
309 	out += sprintf(out, "actual_fps:               %3d\n", cam->fps);
310 	out += sprintf(out, "transfer_rate:            %4dkB/s\n",
311 	               cam->transfer_rate);
312 
313 	out += sprintf(out, "\nread-write\n");
314 	out += sprintf(out, "-----------------------  current       min"
315 	               "       max   default  comment\n");
316 	out += sprintf(out, "brightness:             %8d  %8d  %8d  %8d\n",
317 	               cam->params.colourParams.brightness, 0, 100, 50);
318 	if (cam->params.version.firmwareVersion == 1 &&
319 	   cam->params.version.firmwareRevision == 2)
320 		/* 1-02 firmware limits contrast to 80 */
321 		tmp = 80;
322 	else
323 		tmp = 96;
324 
325 	out += sprintf(out, "contrast:               %8d  %8d  %8d  %8d"
326 	               "  steps of 8\n",
327 	               cam->params.colourParams.contrast, 0, tmp, 48);
328 	out += sprintf(out, "saturation:             %8d  %8d  %8d  %8d\n",
329 	               cam->params.colourParams.saturation, 0, 100, 50);
330 	tmp = (25000+5000*cam->params.sensorFps.baserate)/
331 	      (1<<cam->params.sensorFps.divisor);
332 	out += sprintf(out, "sensor_fps:             %4d.%03d  %8d  %8d  %8d\n",
333 	               tmp/1000, tmp%1000, 3, 30, 15);
334 	out += sprintf(out, "stream_start_line:      %8d  %8d  %8d  %8d\n",
335 	               2*cam->params.streamStartLine, 0,
336 		       cam->params.format.videoSize == VIDEOSIZE_CIF ? 288:144,
337 		       cam->params.format.videoSize == VIDEOSIZE_CIF ? 240:120);
338 	out += sprintf(out, "ecp_timing:             %8s  %8s  %8s  %8s\n",
339 	               cam->params.ecpTiming ? "slow" : "normal", "slow",
340 		       "normal", "normal");
341 
342 	if (cam->params.colourBalance.balanceModeIsAuto) {
343 		sprintf(tmpstr, "auto");
344 	} else {
345 		sprintf(tmpstr, "manual");
346 	}
347 	out += sprintf(out, "color_balance_mode:     %8s  %8s  %8s"
348 		       "  %8s\n",  tmpstr, "manual", "auto", "auto");
349 	out += sprintf(out, "red_gain:               %8d  %8d  %8d  %8d\n",
350 	               cam->params.colourBalance.redGain, 0, 212, 32);
351 	out += sprintf(out, "green_gain:             %8d  %8d  %8d  %8d\n",
352 	               cam->params.colourBalance.greenGain, 0, 212, 6);
353 	out += sprintf(out, "blue_gain:              %8d  %8d  %8d  %8d\n",
354 	               cam->params.colourBalance.blueGain, 0, 212, 92);
355 
356 	if (cam->params.version.firmwareVersion == 1 &&
357 	   cam->params.version.firmwareRevision == 2)
358 		/* 1-02 firmware limits gain to 2 */
359 		sprintf(tmpstr, "%8d  %8d  %8d", 1, 2, 2);
360 	else
361 		sprintf(tmpstr, "%8d  %8d  %8d", 1, 8, 2);
362 
363 	if (cam->params.exposure.gainMode == 0)
364 		out += sprintf(out, "max_gain:                unknown  %28s"
365 		               "  powers of 2\n", tmpstr);
366 	else
367 		out += sprintf(out, "max_gain:               %8d  %28s"
368 			       "  1,2,4 or 8 \n",
369 		               1<<(cam->params.exposure.gainMode-1), tmpstr);
370 
371 	switch(cam->params.exposure.expMode) {
372 	case 1:
373 	case 3:
374 		sprintf(tmpstr, "manual");
375 		break;
376 	case 2:
377 		sprintf(tmpstr, "auto");
378 		break;
379 	default:
380 		sprintf(tmpstr, "unknown");
381 		break;
382 	}
383 	out += sprintf(out, "exposure_mode:          %8s  %8s  %8s"
384 		       "  %8s\n",  tmpstr, "manual", "auto", "auto");
385 	out += sprintf(out, "centre_weight:          %8s  %8s  %8s  %8s\n",
386 	               (2-cam->params.exposure.centreWeight) ? "on" : "off",
387 	               "off", "on", "on");
388 	out += sprintf(out, "gain:                   %8d  %8d  max_gain  %8d  1,2,4,8 possible\n",
389 	               1<<cam->params.exposure.gain, 1, 1);
390 	if (cam->params.version.firmwareVersion == 1 &&
391 	   cam->params.version.firmwareRevision == 2)
392 		/* 1-02 firmware limits fineExp to 127 */
393 		tmp = 255;
394 	else
395 		tmp = 511;
396 
397 	out += sprintf(out, "fine_exp:               %8d  %8d  %8d  %8d\n",
398 	               cam->params.exposure.fineExp*2, 0, tmp, 0);
399 	if (cam->params.version.firmwareVersion == 1 &&
400 	   cam->params.version.firmwareRevision == 2)
401 		/* 1-02 firmware limits coarseExpHi to 0 */
402 		tmp = 255;
403 	else
404 		tmp = 65535;
405 
406 	out += sprintf(out, "coarse_exp:             %8d  %8d  %8d"
407 		       "  %8d\n", cam->params.exposure.coarseExpLo+
408 		       256*cam->params.exposure.coarseExpHi, 0, tmp, 185);
409 	out += sprintf(out, "red_comp:               %8d  %8d  %8d  %8d\n",
410 	               cam->params.exposure.redComp, 220, 255, 220);
411 	out += sprintf(out, "green1_comp:            %8d  %8d  %8d  %8d\n",
412 	               cam->params.exposure.green1Comp, 214, 255, 214);
413 	out += sprintf(out, "green2_comp:            %8d  %8d  %8d  %8d\n",
414 	               cam->params.exposure.green2Comp, 214, 255, 214);
415 	out += sprintf(out, "blue_comp:              %8d  %8d  %8d  %8d\n",
416 	               cam->params.exposure.blueComp, 230, 255, 230);
417 
418 	out += sprintf(out, "apcor_gain1:            %#8x  %#8x  %#8x  %#8x\n",
419 	               cam->params.apcor.gain1, 0, 0xff, 0x1c);
420 	out += sprintf(out, "apcor_gain2:            %#8x  %#8x  %#8x  %#8x\n",
421 	               cam->params.apcor.gain2, 0, 0xff, 0x1a);
422 	out += sprintf(out, "apcor_gain4:            %#8x  %#8x  %#8x  %#8x\n",
423 	               cam->params.apcor.gain4, 0, 0xff, 0x2d);
424 	out += sprintf(out, "apcor_gain8:            %#8x  %#8x  %#8x  %#8x\n",
425 	               cam->params.apcor.gain8, 0, 0xff, 0x2a);
426 	out += sprintf(out, "vl_offset_gain1:        %8d  %8d  %8d  %8d\n",
427 	               cam->params.vlOffset.gain1, 0, 255, 24);
428 	out += sprintf(out, "vl_offset_gain2:        %8d  %8d  %8d  %8d\n",
429 	               cam->params.vlOffset.gain2, 0, 255, 28);
430 	out += sprintf(out, "vl_offset_gain4:        %8d  %8d  %8d  %8d\n",
431 	               cam->params.vlOffset.gain4, 0, 255, 30);
432 	out += sprintf(out, "vl_offset_gain8:        %8d  %8d  %8d  %8d\n",
433 	               cam->params.vlOffset.gain8, 0, 255, 30);
434 	out += sprintf(out, "flicker_control:        %8s  %8s  %8s  %8s\n",
435 	               cam->params.flickerControl.flickerMode ? "on" : "off",
436 		       "off", "on", "off");
437 	out += sprintf(out, "mains_frequency:        %8d  %8d  %8d  %8d"
438 	               " only 50/60\n",
439 	               cam->mainsFreq ? 60 : 50, 50, 60, 50);
440 	out += sprintf(out, "allowable_overexposure: %8d  %8d  %8d  %8d\n",
441 	               cam->params.flickerControl.allowableOverExposure, 0,
442 		       255, 0);
443 	out += sprintf(out, "compression_mode:       ");
444 	switch(cam->params.compression.mode) {
445 	case CPIA_COMPRESSION_NONE:
446 		out += sprintf(out, "%8s", "none");
447 		break;
448 	case CPIA_COMPRESSION_AUTO:
449 		out += sprintf(out, "%8s", "auto");
450 		break;
451 	case CPIA_COMPRESSION_MANUAL:
452 		out += sprintf(out, "%8s", "manual");
453 		break;
454 	default:
455 		out += sprintf(out, "%8s", "unknown");
456 		break;
457 	}
458 	out += sprintf(out, "    none,auto,manual      auto\n");
459 	out += sprintf(out, "decimation_enable:      %8s  %8s  %8s  %8s\n",
460         	       cam->params.compression.decimation ==
461 		       DECIMATION_ENAB ? "on":"off", "off", "off",
462 		       "off");
463 	out += sprintf(out, "compression_target:    %9s %9s %9s %9s\n",
464 	               cam->params.compressionTarget.frTargeting  ==
465 		       CPIA_COMPRESSION_TARGET_FRAMERATE ?
466 		       "framerate":"quality",
467 		       "framerate", "quality", "quality");
468 	out += sprintf(out, "target_framerate:       %8d  %8d  %8d  %8d\n",
469 	               cam->params.compressionTarget.targetFR, 0, 30, 7);
470 	out += sprintf(out, "target_quality:         %8d  %8d  %8d  %8d\n",
471 	               cam->params.compressionTarget.targetQ, 0, 255, 10);
472 	out += sprintf(out, "y_threshold:            %8d  %8d  %8d  %8d\n",
473 	               cam->params.yuvThreshold.yThreshold, 0, 31, 15);
474 	out += sprintf(out, "uv_threshold:           %8d  %8d  %8d  %8d\n",
475 	               cam->params.yuvThreshold.uvThreshold, 0, 31, 15);
476 	out += sprintf(out, "hysteresis:             %8d  %8d  %8d  %8d\n",
477 	               cam->params.compressionParams.hysteresis, 0, 255, 3);
478 	out += sprintf(out, "threshold_max:          %8d  %8d  %8d  %8d\n",
479 	               cam->params.compressionParams.threshMax, 0, 255, 11);
480 	out += sprintf(out, "small_step:             %8d  %8d  %8d  %8d\n",
481 	               cam->params.compressionParams.smallStep, 0, 255, 1);
482 	out += sprintf(out, "large_step:             %8d  %8d  %8d  %8d\n",
483 	               cam->params.compressionParams.largeStep, 0, 255, 3);
484 	out += sprintf(out, "decimation_hysteresis:  %8d  %8d  %8d  %8d\n",
485 	               cam->params.compressionParams.decimationHysteresis,
486 		       0, 255, 2);
487 	out += sprintf(out, "fr_diff_step_thresh:    %8d  %8d  %8d  %8d\n",
488 	               cam->params.compressionParams.frDiffStepThresh,
489 		       0, 255, 5);
490 	out += sprintf(out, "q_diff_step_thresh:     %8d  %8d  %8d  %8d\n",
491 	               cam->params.compressionParams.qDiffStepThresh,
492 		       0, 255, 3);
493 	out += sprintf(out, "decimation_thresh_mod:  %8d  %8d  %8d  %8d\n",
494 	               cam->params.compressionParams.decimationThreshMod,
495 		       0, 255, 2);
496 	/* QX3 specific entries */
497 	if (cam->params.qx3.qx3_detected) {
498 		out += sprintf(out, "toplight:               %8s  %8s  %8s  %8s\n",
499 		               cam->params.qx3.toplight ? "on" : "off",
500 			       "off", "on", "off");
501 		out += sprintf(out, "bottomlight:            %8s  %8s  %8s  %8s\n",
502 		               cam->params.qx3.bottomlight ? "on" : "off",
503 			       "off", "on", "off");
504 	}
505 
506 	len = out - page;
507 	len -= off;
508 	if (len < count) {
509 		*eof = 1;
510 		if (len <= 0) return 0;
511 	} else
512 		len = count;
513 
514 	*start = page + off;
515 	return len;
516 }
517 
match(char * checkstr,char ** buffer,unsigned long * count,int * find_colon,int * err)518 static int match(char *checkstr, char **buffer, unsigned long *count,
519                  int *find_colon, int *err)
520 {
521 	int ret, colon_found = 1;
522 	int len = strlen(checkstr);
523 	ret = (len <= *count && strncmp(*buffer, checkstr, len) == 0);
524 	if (ret) {
525 		*buffer += len;
526 		*count -= len;
527 		if (*find_colon) {
528 			colon_found = 0;
529 			while (*count && (**buffer == ' ' || **buffer == '\t' ||
530 			       (!colon_found && **buffer == ':'))) {
531 				if (**buffer == ':')
532 					colon_found = 1;
533 				--*count;
534 				++*buffer;
535 			}
536 			if (!*count || !colon_found)
537 				*err = -EINVAL;
538 			*find_colon = 0;
539 		}
540 	}
541 	return ret;
542 }
543 
value(char ** buffer,unsigned long * count,int * err)544 static unsigned long int value(char **buffer, unsigned long *count, int *err)
545 {
546 	char *p;
547 	unsigned long int ret;
548 	ret = simple_strtoul(*buffer, &p, 0);
549 	if (p == *buffer)
550 		*err = -EINVAL;
551 	else {
552 		*count -= p - *buffer;
553 		*buffer = p;
554 	}
555 	return ret;
556 }
557 
cpia_write_proc(struct file * file,const char * buf,unsigned long count,void * data)558 static int cpia_write_proc(struct file *file, const char *buf,
559                            unsigned long count, void *data)
560 {
561 	struct cam_data *cam = data;
562 	struct cam_params new_params;
563 	char *page, *buffer;
564 	int retval, find_colon;
565 	int size = count;
566 	unsigned long val = 0;
567 	u32 command_flags = 0;
568 	u8 new_mains;
569 
570 	/*
571 	 * This code to copy from buf to page is shamelessly copied
572 	 * from the comx driver
573 	 */
574 	if (count > PAGE_SIZE) {
575 		printk(KERN_ERR "count is %lu > %d!!!\n", count, (int)PAGE_SIZE);
576 		return -ENOSPC;
577 	}
578 
579 	if (!(page = (char *)__get_free_page(GFP_KERNEL))) return -ENOMEM;
580 
581 	if(copy_from_user(page, buf, count))
582 	{
583 		retval = -EFAULT;
584 		goto out;
585 	}
586 
587 	if (page[count-1] == '\n')
588 		page[count-1] = '\0';
589 	else if (count < PAGE_SIZE)
590 		page[count] = '\0';
591 	else if (page[count]) {
592 		retval = -EINVAL;
593 		goto out;
594 	}
595 
596 	buffer = page;
597 
598 	if (down_interruptible(&cam->param_lock))
599 		return -ERESTARTSYS;
600 
601 	/*
602 	 * Skip over leading whitespace
603 	 */
604 	while (count && isspace(*buffer)) {
605 		--count;
606 		++buffer;
607 	}
608 
609 	memcpy(&new_params, &cam->params, sizeof(struct cam_params));
610 	new_mains = cam->mainsFreq;
611 
612 #define MATCH(x) (match(x, &buffer, &count, &find_colon, &retval))
613 #define VALUE (value(&buffer,&count, &retval))
614 #define FIRMWARE_VERSION(x,y) (new_params.version.firmwareVersion == (x) && \
615                                new_params.version.firmwareRevision == (y))
616 
617 
618 	retval = 0;
619 	while (count && !retval) {
620 		find_colon = 1;
621 		if (MATCH("brightness")) {
622 			if (!retval)
623 				val = VALUE;
624 
625 			if (!retval) {
626 				if (val <= 100)
627 					new_params.colourParams.brightness = val;
628 				else
629 					retval = -EINVAL;
630 			}
631 			command_flags |= COMMAND_SETCOLOURPARAMS;
632 		} else if (MATCH("contrast")) {
633 			if (!retval)
634 				val = VALUE;
635 
636 			if (!retval) {
637 				if (val <= 100) {
638 					/* contrast is in steps of 8, so round*/
639 					val = ((val + 3) / 8) * 8;
640 					/* 1-02 firmware limits contrast to 80*/
641 					if (FIRMWARE_VERSION(1,2) && val > 80)
642 						val = 80;
643 
644 					new_params.colourParams.contrast = val;
645 				} else
646 					retval = -EINVAL;
647 			}
648 			command_flags |= COMMAND_SETCOLOURPARAMS;
649 		} else if (MATCH("saturation")) {
650 			if (!retval)
651 				val = VALUE;
652 
653 			if (!retval) {
654 				if (val <= 100)
655 					new_params.colourParams.saturation = val;
656 				else
657 					retval = -EINVAL;
658 			}
659 			command_flags |= COMMAND_SETCOLOURPARAMS;
660 		} else if (MATCH("sensor_fps")) {
661 			if (!retval)
662 				val = VALUE;
663 
664 			if (!retval) {
665 				/* find values so that sensorFPS is minimized,
666 				 * but >= val */
667 				if (val > 30)
668 					retval = -EINVAL;
669 				else if (val > 25) {
670 					new_params.sensorFps.divisor = 0;
671 					new_params.sensorFps.baserate = 1;
672 				} else if (val > 15) {
673 					new_params.sensorFps.divisor = 0;
674 					new_params.sensorFps.baserate = 0;
675 				} else if (val > 12) {
676 					new_params.sensorFps.divisor = 1;
677 					new_params.sensorFps.baserate = 1;
678 				} else if (val > 7) {
679 					new_params.sensorFps.divisor = 1;
680 					new_params.sensorFps.baserate = 0;
681 				} else if (val > 6) {
682 					new_params.sensorFps.divisor = 2;
683 					new_params.sensorFps.baserate = 1;
684 				} else if (val > 3) {
685 					new_params.sensorFps.divisor = 2;
686 					new_params.sensorFps.baserate = 0;
687 				} else {
688 					new_params.sensorFps.divisor = 3;
689 					/* Either base rate would work here */
690 					new_params.sensorFps.baserate = 1;
691 				}
692 				new_params.flickerControl.coarseJump =
693 					flicker_jumps[new_mains]
694 					[new_params.sensorFps.baserate]
695 					[new_params.sensorFps.divisor];
696 				if (new_params.flickerControl.flickerMode)
697 					command_flags |= COMMAND_SETFLICKERCTRL;
698 			}
699 			command_flags |= COMMAND_SETSENSORFPS;
700 		} else if (MATCH("stream_start_line")) {
701 			if (!retval)
702 				val = VALUE;
703 
704 			if (!retval) {
705 				int max_line = 288;
706 
707 				if (new_params.format.videoSize == VIDEOSIZE_QCIF)
708 					max_line = 144;
709 				if (val <= max_line)
710 					new_params.streamStartLine = val/2;
711 				else
712 					retval = -EINVAL;
713 			}
714 		} else if (MATCH("ecp_timing")) {
715 			if (!retval && MATCH("normal"))
716 				new_params.ecpTiming = 0;
717 			else if (!retval && MATCH("slow"))
718 				new_params.ecpTiming = 1;
719 			else
720 				retval = -EINVAL;
721 
722 			command_flags |= COMMAND_SETECPTIMING;
723 		} else if (MATCH("color_balance_mode")) {
724 			if (!retval && MATCH("manual"))
725 				new_params.colourBalance.balanceModeIsAuto = 0;
726 			else if (!retval && MATCH("auto"))
727 				new_params.colourBalance.balanceModeIsAuto = 1;
728 			else
729 				retval = -EINVAL;
730 
731 			command_flags |= COMMAND_SETCOLOURBALANCE;
732 		} else if (MATCH("red_gain")) {
733 			if (!retval)
734 				val = VALUE;
735 
736 			if (!retval) {
737 				if (val <= 212)
738 					new_params.colourBalance.redGain = val;
739 				else
740 					retval = -EINVAL;
741 			}
742 			command_flags |= COMMAND_SETCOLOURBALANCE;
743 		} else if (MATCH("green_gain")) {
744 			if (!retval)
745 				val = VALUE;
746 
747 			if (!retval) {
748 				if (val <= 212)
749 					new_params.colourBalance.greenGain = val;
750 				else
751 					retval = -EINVAL;
752 			}
753 			command_flags |= COMMAND_SETCOLOURBALANCE;
754 		} else if (MATCH("blue_gain")) {
755 			if (!retval)
756 				val = VALUE;
757 
758 			if (!retval) {
759 				if (val <= 212)
760 					new_params.colourBalance.blueGain = val;
761 				else
762 					retval = -EINVAL;
763 			}
764 			command_flags |= COMMAND_SETCOLOURBALANCE;
765 		} else if (MATCH("max_gain")) {
766 			if (!retval)
767 				val = VALUE;
768 
769 			if (!retval) {
770 				/* 1-02 firmware limits gain to 2 */
771 				if (FIRMWARE_VERSION(1,2) && val > 2)
772 					val = 2;
773 				switch(val) {
774 				case 1:
775 					new_params.exposure.gainMode = 1;
776 					break;
777 				case 2:
778 					new_params.exposure.gainMode = 2;
779 					break;
780 				case 4:
781 					new_params.exposure.gainMode = 3;
782 					break;
783 				case 8:
784 					new_params.exposure.gainMode = 4;
785 					break;
786 				default:
787 					retval = -EINVAL;
788 					break;
789 				}
790 			}
791 			command_flags |= COMMAND_SETEXPOSURE;
792 		} else if (MATCH("exposure_mode")) {
793 			if (!retval && MATCH("auto"))
794 				new_params.exposure.expMode = 2;
795 			else if (!retval && MATCH("manual")) {
796 				if (new_params.exposure.expMode == 2)
797 					new_params.exposure.expMode = 3;
798 				new_params.flickerControl.flickerMode = 0;
799 				command_flags |= COMMAND_SETFLICKERCTRL;
800 			} else
801 				retval = -EINVAL;
802 
803 			command_flags |= COMMAND_SETEXPOSURE;
804 		} else if (MATCH("centre_weight")) {
805 			if (!retval && MATCH("on"))
806 				new_params.exposure.centreWeight = 1;
807 			else if (!retval && MATCH("off"))
808 				new_params.exposure.centreWeight = 2;
809 			else
810 				retval = -EINVAL;
811 
812 			command_flags |= COMMAND_SETEXPOSURE;
813 		} else if (MATCH("gain")) {
814 			if (!retval)
815 				val = VALUE;
816 
817 			if (!retval) {
818 				switch(val) {
819 				case 1:
820 					new_params.exposure.gain = 0;
821 					new_params.exposure.expMode = 1;
822 					new_params.flickerControl.flickerMode = 0;
823 					command_flags |= COMMAND_SETFLICKERCTRL;
824 					break;
825 				case 2:
826 					new_params.exposure.gain = 1;
827 					new_params.exposure.expMode = 1;
828 					new_params.flickerControl.flickerMode = 0;
829 					command_flags |= COMMAND_SETFLICKERCTRL;
830 					break;
831 				case 4:
832 					new_params.exposure.gain = 2;
833 					new_params.exposure.expMode = 1;
834 					new_params.flickerControl.flickerMode = 0;
835 					command_flags |= COMMAND_SETFLICKERCTRL;
836 					break;
837 				case 8:
838 					new_params.exposure.gain = 3;
839 					new_params.exposure.expMode = 1;
840 					new_params.flickerControl.flickerMode = 0;
841 					command_flags |= COMMAND_SETFLICKERCTRL;
842 					break;
843 				default:
844 					retval = -EINVAL;
845 					break;
846 				}
847 				command_flags |= COMMAND_SETEXPOSURE;
848 				if (new_params.exposure.gain >
849 				    new_params.exposure.gainMode-1)
850 					retval = -EINVAL;
851 			}
852 		} else if (MATCH("fine_exp")) {
853 			if (!retval)
854 				val = VALUE;
855 
856 			if (!retval) {
857 				if (val < 256) {
858 					/* 1-02 firmware limits fineExp to 127*/
859 					if (FIRMWARE_VERSION(1,2) && val > 127)
860 						val = 127;
861 					new_params.exposure.fineExp = val;
862 					new_params.exposure.expMode = 1;
863 					command_flags |= COMMAND_SETEXPOSURE;
864 					new_params.flickerControl.flickerMode = 0;
865 					command_flags |= COMMAND_SETFLICKERCTRL;
866 				} else
867 					retval = -EINVAL;
868 			}
869 		} else if (MATCH("coarse_exp")) {
870 			if (!retval)
871 				val = VALUE;
872 
873 			if (!retval) {
874 				if (val < 65536) {
875 					/* 1-02 firmware limits
876 					 * coarseExp to 255 */
877 					if (FIRMWARE_VERSION(1,2) && val > 255)
878 						val = 255;
879 					new_params.exposure.coarseExpLo =
880 						val & 0xff;
881 					new_params.exposure.coarseExpHi =
882 						val >> 8;
883 					new_params.exposure.expMode = 1;
884 					command_flags |= COMMAND_SETEXPOSURE;
885 					new_params.flickerControl.flickerMode = 0;
886 					command_flags |= COMMAND_SETFLICKERCTRL;
887 				} else
888 					retval = -EINVAL;
889 			}
890 		} else if (MATCH("red_comp")) {
891 			if (!retval)
892 				val = VALUE;
893 
894 			if (!retval) {
895 				if (val >= 220 && val <= 255) {
896 					new_params.exposure.redComp = val;
897 					command_flags |= COMMAND_SETEXPOSURE;
898 				} else
899 					retval = -EINVAL;
900 			}
901 		} else if (MATCH("green1_comp")) {
902 			if (!retval)
903 				val = VALUE;
904 
905 			if (!retval) {
906 				if (val >= 214 && val <= 255) {
907 					new_params.exposure.green1Comp = val;
908 					command_flags |= COMMAND_SETEXPOSURE;
909 				} else
910 					retval = -EINVAL;
911 			}
912 		} else if (MATCH("green2_comp")) {
913 			if (!retval)
914 				val = VALUE;
915 
916 			if (!retval) {
917 				if (val >= 214 && val <= 255) {
918 					new_params.exposure.green2Comp = val;
919 					command_flags |= COMMAND_SETEXPOSURE;
920 				} else
921 					retval = -EINVAL;
922 			}
923 		} else if (MATCH("blue_comp")) {
924 			if (!retval)
925 				val = VALUE;
926 
927 			if (!retval) {
928 				if (val >= 230 && val <= 255) {
929 					new_params.exposure.blueComp = val;
930 					command_flags |= COMMAND_SETEXPOSURE;
931 				} else
932 					retval = -EINVAL;
933 			}
934 		} else if (MATCH("apcor_gain1")) {
935 			if (!retval)
936 				val = VALUE;
937 
938 			if (!retval) {
939 				command_flags |= COMMAND_SETAPCOR;
940 				if (val <= 0xff)
941 					new_params.apcor.gain1 = val;
942 				else
943 					retval = -EINVAL;
944 			}
945 		} else if (MATCH("apcor_gain2")) {
946 			if (!retval)
947 				val = VALUE;
948 
949 			if (!retval) {
950 				command_flags |= COMMAND_SETAPCOR;
951 				if (val <= 0xff)
952 					new_params.apcor.gain2 = val;
953 				else
954 					retval = -EINVAL;
955 			}
956 		} else if (MATCH("apcor_gain4")) {
957 			if (!retval)
958 				val = VALUE;
959 
960 			if (!retval) {
961 				command_flags |= COMMAND_SETAPCOR;
962 				if (val <= 0xff)
963 					new_params.apcor.gain4 = val;
964 				else
965 					retval = -EINVAL;
966 			}
967 		} else if (MATCH("apcor_gain8")) {
968 			if (!retval)
969 				val = VALUE;
970 
971 			if (!retval) {
972 				command_flags |= COMMAND_SETAPCOR;
973 				if (val <= 0xff)
974 					new_params.apcor.gain8 = val;
975 				else
976 					retval = -EINVAL;
977 			}
978 		} else if (MATCH("vl_offset_gain1")) {
979 			if (!retval)
980 				val = VALUE;
981 
982 			if (!retval) {
983 				if (val <= 0xff)
984 					new_params.vlOffset.gain1 = val;
985 				else
986 					retval = -EINVAL;
987 			}
988 			command_flags |= COMMAND_SETVLOFFSET;
989 		} else if (MATCH("vl_offset_gain2")) {
990 			if (!retval)
991 				val = VALUE;
992 
993 			if (!retval) {
994 				if (val <= 0xff)
995 					new_params.vlOffset.gain2 = val;
996 				else
997 					retval = -EINVAL;
998 			}
999 			command_flags |= COMMAND_SETVLOFFSET;
1000 		} else if (MATCH("vl_offset_gain4")) {
1001 			if (!retval)
1002 				val = VALUE;
1003 
1004 			if (!retval) {
1005 				if (val <= 0xff)
1006 					new_params.vlOffset.gain4 = val;
1007 				else
1008 					retval = -EINVAL;
1009 			}
1010 			command_flags |= COMMAND_SETVLOFFSET;
1011 		} else if (MATCH("vl_offset_gain8")) {
1012 			if (!retval)
1013 				val = VALUE;
1014 
1015 			if (!retval) {
1016 				if (val <= 0xff)
1017 					new_params.vlOffset.gain8 = val;
1018 				else
1019 					retval = -EINVAL;
1020 			}
1021 			command_flags |= COMMAND_SETVLOFFSET;
1022 		} else if (MATCH("flicker_control")) {
1023 			if (!retval && MATCH("on")) {
1024 				new_params.flickerControl.flickerMode = 1;
1025 				new_params.exposure.expMode = 2;
1026 				command_flags |= COMMAND_SETEXPOSURE;
1027 			} else if (!retval && MATCH("off"))
1028 				new_params.flickerControl.flickerMode = 0;
1029 			else
1030 				retval = -EINVAL;
1031 
1032 			command_flags |= COMMAND_SETFLICKERCTRL;
1033 		} else if (MATCH("mains_frequency")) {
1034 			if (!retval && MATCH("50")) {
1035 				new_mains = 0;
1036 				new_params.flickerControl.coarseJump =
1037 					flicker_jumps[new_mains]
1038 					[new_params.sensorFps.baserate]
1039 					[new_params.sensorFps.divisor];
1040 				if (new_params.flickerControl.flickerMode)
1041 					command_flags |= COMMAND_SETFLICKERCTRL;
1042 			} else if (!retval && MATCH("60")) {
1043 				new_mains = 1;
1044 				new_params.flickerControl.coarseJump =
1045 					flicker_jumps[new_mains]
1046 					[new_params.sensorFps.baserate]
1047 					[new_params.sensorFps.divisor];
1048 				if (new_params.flickerControl.flickerMode)
1049 					command_flags |= COMMAND_SETFLICKERCTRL;
1050 			} else
1051 				retval = -EINVAL;
1052 		} else if (MATCH("allowable_overexposure")) {
1053 			if (!retval)
1054 				val = VALUE;
1055 
1056 			if (!retval) {
1057 				if (val <= 0xff) {
1058 					new_params.flickerControl.
1059 						allowableOverExposure = val;
1060 					command_flags |= COMMAND_SETFLICKERCTRL;
1061 				} else
1062 					retval = -EINVAL;
1063 			}
1064 		} else if (MATCH("compression_mode")) {
1065 			if (!retval && MATCH("none"))
1066 				new_params.compression.mode =
1067 					CPIA_COMPRESSION_NONE;
1068 			else if (!retval && MATCH("auto"))
1069 				new_params.compression.mode =
1070 					CPIA_COMPRESSION_AUTO;
1071 			else if (!retval && MATCH("manual"))
1072 				new_params.compression.mode =
1073 					CPIA_COMPRESSION_MANUAL;
1074 			else
1075 				retval = -EINVAL;
1076 
1077 			command_flags |= COMMAND_SETCOMPRESSION;
1078 		} else if (MATCH("decimation_enable")) {
1079 			if (!retval && MATCH("off"))
1080 				new_params.compression.decimation = 0;
1081 			else
1082 				retval = -EINVAL;
1083 
1084 			command_flags |= COMMAND_SETCOMPRESSION;
1085 		} else if (MATCH("compression_target")) {
1086 			if (!retval && MATCH("quality"))
1087 				new_params.compressionTarget.frTargeting =
1088 					CPIA_COMPRESSION_TARGET_QUALITY;
1089 			else if (!retval && MATCH("framerate"))
1090 				new_params.compressionTarget.frTargeting =
1091 					CPIA_COMPRESSION_TARGET_FRAMERATE;
1092 			else
1093 				retval = -EINVAL;
1094 
1095 			command_flags |= COMMAND_SETCOMPRESSIONTARGET;
1096 		} else if (MATCH("target_framerate")) {
1097 			if (!retval)
1098 				val = VALUE;
1099 
1100 			if (!retval)
1101 				new_params.compressionTarget.targetFR = val;
1102 			command_flags |= COMMAND_SETCOMPRESSIONTARGET;
1103 		} else if (MATCH("target_quality")) {
1104 			if (!retval)
1105 				val = VALUE;
1106 
1107 			if (!retval)
1108 				new_params.compressionTarget.targetQ = val;
1109 
1110 			command_flags |= COMMAND_SETCOMPRESSIONTARGET;
1111 		} else if (MATCH("y_threshold")) {
1112 			if (!retval)
1113 				val = VALUE;
1114 
1115 			if (!retval) {
1116 				if (val < 32)
1117 					new_params.yuvThreshold.yThreshold = val;
1118 				else
1119 					retval = -EINVAL;
1120 			}
1121 			command_flags |= COMMAND_SETYUVTHRESH;
1122 		} else if (MATCH("uv_threshold")) {
1123 			if (!retval)
1124 				val = VALUE;
1125 
1126 			if (!retval) {
1127 				if (val < 32)
1128 					new_params.yuvThreshold.uvThreshold = val;
1129 				else
1130 					retval = -EINVAL;
1131 			}
1132 			command_flags |= COMMAND_SETYUVTHRESH;
1133 		} else if (MATCH("hysteresis")) {
1134 			if (!retval)
1135 				val = VALUE;
1136 
1137 			if (!retval) {
1138 				if (val <= 0xff)
1139 					new_params.compressionParams.hysteresis = val;
1140 				else
1141 					retval = -EINVAL;
1142 			}
1143 			command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1144 		} else if (MATCH("threshold_max")) {
1145 			if (!retval)
1146 				val = VALUE;
1147 
1148 			if (!retval) {
1149 				if (val <= 0xff)
1150 					new_params.compressionParams.threshMax = val;
1151 				else
1152 					retval = -EINVAL;
1153 			}
1154 			command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1155 		} else if (MATCH("small_step")) {
1156 			if (!retval)
1157 				val = VALUE;
1158 
1159 			if (!retval) {
1160 				if (val <= 0xff)
1161 					new_params.compressionParams.smallStep = val;
1162 				else
1163 					retval = -EINVAL;
1164 			}
1165 			command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1166 		} else if (MATCH("large_step")) {
1167 			if (!retval)
1168 				val = VALUE;
1169 
1170 			if (!retval) {
1171 				if (val <= 0xff)
1172 					new_params.compressionParams.largeStep = val;
1173 				else
1174 					retval = -EINVAL;
1175 			}
1176 			command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1177 		} else if (MATCH("decimation_hysteresis")) {
1178 			if (!retval)
1179 				val = VALUE;
1180 
1181 			if (!retval) {
1182 				if (val <= 0xff)
1183 					new_params.compressionParams.decimationHysteresis = val;
1184 				else
1185 					retval = -EINVAL;
1186 			}
1187 			command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1188 		} else if (MATCH("fr_diff_step_thresh")) {
1189 			if (!retval)
1190 				val = VALUE;
1191 
1192 			if (!retval) {
1193 				if (val <= 0xff)
1194 					new_params.compressionParams.frDiffStepThresh = val;
1195 				else
1196 					retval = -EINVAL;
1197 			}
1198 			command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1199 		} else if (MATCH("q_diff_step_thresh")) {
1200 			if (!retval)
1201 				val = VALUE;
1202 
1203 			if (!retval) {
1204 				if (val <= 0xff)
1205 					new_params.compressionParams.qDiffStepThresh = val;
1206 				else
1207 					retval = -EINVAL;
1208 			}
1209 			command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1210 		} else if (MATCH("decimation_thresh_mod")) {
1211 			if (!retval)
1212 				val = VALUE;
1213 
1214 			if (!retval) {
1215 				if (val <= 0xff)
1216 					new_params.compressionParams.decimationThreshMod = val;
1217 				else
1218 					retval = -EINVAL;
1219 			}
1220 			command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
1221 		} else if (MATCH("toplight")) {
1222 		        if (!retval && MATCH("on"))
1223 				new_params.qx3.toplight = 1;
1224 			else if (!retval && MATCH("off"))
1225 				new_params.qx3.toplight = 0;
1226 			else
1227 				retval = -EINVAL;
1228 			command_flags |= COMMAND_SETLIGHTS;
1229 		} else if (MATCH("bottomlight")) {
1230 		        if (!retval && MATCH("on"))
1231 				new_params.qx3.bottomlight = 1;
1232 			else if (!retval && MATCH("off"))
1233 				new_params.qx3.bottomlight = 0;
1234 			else
1235 				retval = -EINVAL;
1236 			command_flags |= COMMAND_SETLIGHTS;
1237 		} else {
1238 			DBG("No match found\n");
1239 			retval = -EINVAL;
1240 		}
1241 
1242 		if (!retval) {
1243 			while (count && isspace(*buffer) && *buffer != '\n') {
1244 				--count;
1245 				++buffer;
1246 			}
1247 			if (count) {
1248 				if (*buffer == '\0' && count != 1)
1249 					retval = -EINVAL;
1250 				else if (*buffer != '\n' && *buffer != ';' &&
1251 					 *buffer != '\0')
1252 					retval = -EINVAL;
1253 				else {
1254 					--count;
1255 					++buffer;
1256 				}
1257 			}
1258 		}
1259 	}
1260 #undef MATCH
1261 #undef VALUE
1262 #undef FIRMWARE_VERSION
1263 
1264 	if (!retval) {
1265 		if (command_flags & COMMAND_SETCOLOURPARAMS) {
1266 			/* Adjust cam->vp to reflect these changes */
1267 			cam->vp.brightness =
1268 				new_params.colourParams.brightness*65535/100;
1269 			cam->vp.contrast =
1270 				new_params.colourParams.contrast*65535/100;
1271 			cam->vp.colour =
1272 				new_params.colourParams.saturation*65535/100;
1273 		}
1274 
1275 		memcpy(&cam->params, &new_params, sizeof(struct cam_params));
1276 		cam->mainsFreq = new_mains;
1277 		cam->cmd_queue |= command_flags;
1278 		retval = size;
1279 	} else
1280 		DBG("error: %d\n", retval);
1281 
1282 	up(&cam->param_lock);
1283 
1284 out:
1285 	free_page((unsigned long)page);
1286 	return retval;
1287 }
1288 
create_proc_cpia_cam(struct cam_data * cam)1289 static void create_proc_cpia_cam(struct cam_data *cam)
1290 {
1291 	char name[7];
1292 	struct proc_dir_entry *ent;
1293 
1294 	if (!cpia_proc_root || !cam)
1295 		return;
1296 
1297 	sprintf(name, "video%d", cam->vdev.minor);
1298 
1299 	ent = create_proc_entry(name, S_IFREG|S_IRUGO|S_IWUSR, cpia_proc_root);
1300 	if (!ent)
1301 		return;
1302 
1303 	ent->data = cam;
1304 	ent->read_proc = cpia_read_proc;
1305 	ent->write_proc = cpia_write_proc;
1306 	/*
1307 	   size of the proc entry is 3672 bytes for the standard webcam;
1308  	   the extra features of the QX3 microscope add 188 bytes.
1309 	   (we have not yet probed the camera to see which type it is).
1310 	*/
1311 	ent->size = 3672 + 188;
1312 	cam->proc_entry = ent;
1313 }
1314 
destroy_proc_cpia_cam(struct cam_data * cam)1315 static void destroy_proc_cpia_cam(struct cam_data *cam)
1316 {
1317 	char name[7];
1318 
1319 	if (!cam || !cam->proc_entry)
1320 		return;
1321 
1322 	sprintf(name, "video%d", cam->vdev.minor);
1323 	remove_proc_entry(name, cpia_proc_root);
1324 	cam->proc_entry = NULL;
1325 }
1326 
proc_cpia_create(void)1327 static void proc_cpia_create(void)
1328 {
1329 	cpia_proc_root = create_proc_entry("cpia", S_IFDIR, 0);
1330 
1331 	if (cpia_proc_root)
1332 		cpia_proc_root->owner = THIS_MODULE;
1333 	else
1334 		LOG("Unable to initialise /proc/cpia\n");
1335 }
1336 
proc_cpia_destroy(void)1337 static void proc_cpia_destroy(void)
1338 {
1339 	remove_proc_entry("cpia", 0);
1340 }
1341 #endif /* CONFIG_PROC_FS */
1342 
1343 /* ----------------------- debug functions ---------------------- */
1344 
1345 #define printstatus(cam) \
1346   DBG("%02x %02x %02x %02x %02x %02x %02x %02x\n",\
1347 	cam->params.status.systemState, cam->params.status.grabState, \
1348 	cam->params.status.streamState, cam->params.status.fatalError, \
1349 	cam->params.status.cmdError, cam->params.status.debugFlags, \
1350 	cam->params.status.vpStatus, cam->params.status.errorCode);
1351 
1352 /* ----------------------- v4l helpers -------------------------- */
1353 
1354 /* supported frame palettes and depths */
valid_mode(u16 palette,u16 depth)1355 static inline int valid_mode(u16 palette, u16 depth)
1356 {
1357 	return (palette == VIDEO_PALETTE_GREY && depth == 8) ||
1358 	       (palette == VIDEO_PALETTE_RGB555 && depth == 16) ||
1359 	       (palette == VIDEO_PALETTE_RGB565 && depth == 16) ||
1360 	       (palette == VIDEO_PALETTE_RGB24 && depth == 24) ||
1361 	       (palette == VIDEO_PALETTE_RGB32 && depth == 32) ||
1362 	       (palette == VIDEO_PALETTE_YUV422 && depth == 16) ||
1363 	       (palette == VIDEO_PALETTE_YUYV && depth == 16) ||
1364 	       (palette == VIDEO_PALETTE_UYVY && depth == 16);
1365 }
1366 
match_videosize(int width,int height)1367 static int match_videosize( int width, int height )
1368 {
1369 	/* return the best match, where 'best' is as always
1370 	 * the largest that is not bigger than what is requested. */
1371 	if (width>=352 && height>=288)
1372 		return VIDEOSIZE_352_288; /* CIF */
1373 
1374 	if (width>=320 && height>=240)
1375 		return VIDEOSIZE_320_240; /* SIF */
1376 
1377 	if (width>=288 && height>=216)
1378 		return VIDEOSIZE_288_216;
1379 
1380 	if (width>=256 && height>=192)
1381 		return VIDEOSIZE_256_192;
1382 
1383 	if (width>=224 && height>=168)
1384 		return VIDEOSIZE_224_168;
1385 
1386 	if (width>=192 && height>=144)
1387 		return VIDEOSIZE_192_144;
1388 
1389 	if (width>=176 && height>=144)
1390 		return VIDEOSIZE_176_144; /* QCIF */
1391 
1392 	if (width>=160 && height>=120)
1393 		return VIDEOSIZE_160_120; /* QSIF */
1394 
1395 	if (width>=128 && height>=96)
1396 		return VIDEOSIZE_128_96;
1397 
1398 	if (width>=88 && height>=72)
1399 		return VIDEOSIZE_88_72;
1400 
1401 	if (width>=64 && height>=48)
1402 		return VIDEOSIZE_64_48;
1403 
1404 	if (width>=48 && height>=48)
1405 		return VIDEOSIZE_48_48;
1406 
1407 	return -1;
1408 }
1409 
1410 /* these are the capture sizes we support */
set_vw_size(struct cam_data * cam)1411 static void set_vw_size(struct cam_data *cam)
1412 {
1413 	/* the col/row/start/end values are the result of simple math    */
1414 	/* study the SetROI-command in cpia developers guide p 2-22      */
1415 	/* streamStartLine is set to the recommended value in the cpia   */
1416 	/*  developers guide p 3-37                                      */
1417 	switch(cam->video_size) {
1418 	case VIDEOSIZE_CIF:
1419 		cam->vw.width = 352;
1420 		cam->vw.height = 288;
1421 		cam->params.format.videoSize=VIDEOSIZE_CIF;
1422 		cam->params.roi.colStart=0;
1423 		cam->params.roi.colEnd=44;
1424 		cam->params.roi.rowStart=0;
1425 		cam->params.roi.rowEnd=72;
1426 		cam->params.streamStartLine = 120;
1427 		break;
1428 	case VIDEOSIZE_SIF:
1429 		cam->vw.width = 320;
1430 		cam->vw.height = 240;
1431 		cam->params.format.videoSize=VIDEOSIZE_CIF;
1432 		cam->params.roi.colStart=2;
1433 		cam->params.roi.colEnd=42;
1434 		cam->params.roi.rowStart=6;
1435 		cam->params.roi.rowEnd=66;
1436 		cam->params.streamStartLine = 120;
1437 		break;
1438 	case VIDEOSIZE_288_216:
1439 		cam->vw.width = 288;
1440 		cam->vw.height = 216;
1441 		cam->params.format.videoSize=VIDEOSIZE_CIF;
1442 		cam->params.roi.colStart=4;
1443 		cam->params.roi.colEnd=40;
1444 		cam->params.roi.rowStart=9;
1445 		cam->params.roi.rowEnd=63;
1446 		cam->params.streamStartLine = 120;
1447 		break;
1448 	case VIDEOSIZE_256_192:
1449 		cam->vw.width = 256;
1450 		cam->vw.height = 192;
1451 		cam->params.format.videoSize=VIDEOSIZE_CIF;
1452 		cam->params.roi.colStart=6;
1453 		cam->params.roi.colEnd=38;
1454 		cam->params.roi.rowStart=12;
1455 		cam->params.roi.rowEnd=60;
1456 		cam->params.streamStartLine = 120;
1457 		break;
1458 	case VIDEOSIZE_224_168:
1459 		cam->vw.width = 224;
1460 		cam->vw.height = 168;
1461 		cam->params.format.videoSize=VIDEOSIZE_CIF;
1462 		cam->params.roi.colStart=8;
1463 		cam->params.roi.colEnd=36;
1464 		cam->params.roi.rowStart=15;
1465 		cam->params.roi.rowEnd=57;
1466 		cam->params.streamStartLine = 120;
1467 		break;
1468 	case VIDEOSIZE_192_144:
1469 		cam->vw.width = 192;
1470 		cam->vw.height = 144;
1471 		cam->params.format.videoSize=VIDEOSIZE_CIF;
1472 		cam->params.roi.colStart=10;
1473 		cam->params.roi.colEnd=34;
1474 		cam->params.roi.rowStart=18;
1475 		cam->params.roi.rowEnd=54;
1476 		cam->params.streamStartLine = 120;
1477 		break;
1478 	case VIDEOSIZE_QCIF:
1479 		cam->vw.width = 176;
1480 		cam->vw.height = 144;
1481 		cam->params.format.videoSize=VIDEOSIZE_QCIF;
1482 		cam->params.roi.colStart=0;
1483 		cam->params.roi.colEnd=22;
1484 		cam->params.roi.rowStart=0;
1485 		cam->params.roi.rowEnd=36;
1486 		cam->params.streamStartLine = 60;
1487 		break;
1488 	case VIDEOSIZE_QSIF:
1489 		cam->vw.width = 160;
1490 		cam->vw.height = 120;
1491 		cam->params.format.videoSize=VIDEOSIZE_QCIF;
1492 		cam->params.roi.colStart=1;
1493 		cam->params.roi.colEnd=21;
1494 		cam->params.roi.rowStart=3;
1495 		cam->params.roi.rowEnd=33;
1496 		cam->params.streamStartLine = 60;
1497 		break;
1498 	case VIDEOSIZE_128_96:
1499 		cam->vw.width = 128;
1500 		cam->vw.height = 96;
1501 		cam->params.format.videoSize=VIDEOSIZE_QCIF;
1502 		cam->params.roi.colStart=3;
1503 		cam->params.roi.colEnd=19;
1504 		cam->params.roi.rowStart=6;
1505 		cam->params.roi.rowEnd=30;
1506 		cam->params.streamStartLine = 60;
1507 		break;
1508 	case VIDEOSIZE_88_72:
1509 		cam->vw.width = 88;
1510 		cam->vw.height = 72;
1511 		cam->params.format.videoSize=VIDEOSIZE_QCIF;
1512 		cam->params.roi.colStart=5;
1513 		cam->params.roi.colEnd=16;
1514 		cam->params.roi.rowStart=9;
1515 		cam->params.roi.rowEnd=27;
1516 		cam->params.streamStartLine = 60;
1517 		break;
1518 	case VIDEOSIZE_64_48:
1519 		cam->vw.width = 64;
1520 		cam->vw.height = 48;
1521 		cam->params.format.videoSize=VIDEOSIZE_QCIF;
1522 		cam->params.roi.colStart=7;
1523 		cam->params.roi.colEnd=15;
1524 		cam->params.roi.rowStart=12;
1525 		cam->params.roi.rowEnd=24;
1526 		cam->params.streamStartLine = 60;
1527 		break;
1528 	case VIDEOSIZE_48_48:
1529 		cam->vw.width = 48;
1530 		cam->vw.height = 48;
1531 		cam->params.format.videoSize=VIDEOSIZE_QCIF;
1532 		cam->params.roi.colStart=8;
1533 		cam->params.roi.colEnd=14;
1534 		cam->params.roi.rowStart=6;
1535 		cam->params.roi.rowEnd=30;
1536 		cam->params.streamStartLine = 60;
1537 		break;
1538 	default:
1539 		LOG("bad videosize value: %d\n", cam->video_size);
1540 	}
1541 
1542 	return;
1543 }
1544 
allocate_frame_buf(struct cam_data * cam)1545 static int allocate_frame_buf(struct cam_data *cam)
1546 {
1547 	int i;
1548 
1549 	cam->frame_buf = rvmalloc(FRAME_NUM * CPIA_MAX_FRAME_SIZE);
1550 	if (!cam->frame_buf)
1551 		return -ENOBUFS;
1552 
1553 	for (i = 0; i < FRAME_NUM; i++)
1554 		cam->frame[i].data = cam->frame_buf + i * CPIA_MAX_FRAME_SIZE;
1555 
1556 	return 0;
1557 }
1558 
free_frame_buf(struct cam_data * cam)1559 static int free_frame_buf(struct cam_data *cam)
1560 {
1561 	int i;
1562 
1563 	rvfree(cam->frame_buf, FRAME_NUM*CPIA_MAX_FRAME_SIZE);
1564 	cam->frame_buf = 0;
1565 	for (i=0; i < FRAME_NUM; i++)
1566 		cam->frame[i].data = NULL;
1567 
1568 	return 0;
1569 }
1570 
1571 
free_frames(struct cpia_frame frame[FRAME_NUM])1572 static inline void free_frames(struct cpia_frame frame[FRAME_NUM])
1573 {
1574 	int i;
1575 
1576 	for (i=0; i < FRAME_NUM; i++)
1577 		frame[i].state = FRAME_UNUSED;
1578 	return;
1579 }
1580 
1581 /**********************************************************************
1582  *
1583  * General functions
1584  *
1585  **********************************************************************/
1586 /* send an arbitrary command to the camera */
do_command(struct cam_data * cam,u16 command,u8 a,u8 b,u8 c,u8 d)1587 static int do_command(struct cam_data *cam, u16 command, u8 a, u8 b, u8 c, u8 d)
1588 {
1589 	int retval, datasize;
1590 	u8 cmd[8], data[8];
1591 
1592 	switch(command) {
1593 	case CPIA_COMMAND_GetCPIAVersion:
1594 	case CPIA_COMMAND_GetPnPID:
1595 	case CPIA_COMMAND_GetCameraStatus:
1596 	case CPIA_COMMAND_GetVPVersion:
1597 		datasize=8;
1598 		break;
1599 	case CPIA_COMMAND_GetColourParams:
1600 	case CPIA_COMMAND_GetColourBalance:
1601 	case CPIA_COMMAND_GetExposure:
1602 		down(&cam->param_lock);
1603 		datasize=8;
1604 		break;
1605 	case CPIA_COMMAND_ReadMCPorts:
1606 	case CPIA_COMMAND_ReadVCRegs:
1607 		datasize = 4;
1608 		break;
1609 	default:
1610 		datasize=0;
1611 		break;
1612 	}
1613 
1614 	cmd[0] = command>>8;
1615 	cmd[1] = command&0xff;
1616 	cmd[2] = a;
1617 	cmd[3] = b;
1618 	cmd[4] = c;
1619 	cmd[5] = d;
1620 	cmd[6] = datasize;
1621 	cmd[7] = 0;
1622 
1623 	retval = cam->ops->transferCmd(cam->lowlevel_data, cmd, data);
1624 	if (retval) {
1625 		DBG("%x - failed, retval=%d\n", command, retval);
1626 		if (command == CPIA_COMMAND_GetColourParams ||
1627 		    command == CPIA_COMMAND_GetColourBalance ||
1628 		    command == CPIA_COMMAND_GetExposure)
1629 			up(&cam->param_lock);
1630 	} else {
1631 		switch(command) {
1632 		case CPIA_COMMAND_GetCPIAVersion:
1633 			cam->params.version.firmwareVersion = data[0];
1634 			cam->params.version.firmwareRevision = data[1];
1635 			cam->params.version.vcVersion = data[2];
1636 			cam->params.version.vcRevision = data[3];
1637 			break;
1638 		case CPIA_COMMAND_GetPnPID:
1639 			cam->params.pnpID.vendor = data[0]+(((u16)data[1])<<8);
1640 			cam->params.pnpID.product = data[2]+(((u16)data[3])<<8);
1641 			cam->params.pnpID.deviceRevision =
1642 				data[4]+(((u16)data[5])<<8);
1643 			break;
1644 		case CPIA_COMMAND_GetCameraStatus:
1645 			cam->params.status.systemState = data[0];
1646 			cam->params.status.grabState = data[1];
1647 			cam->params.status.streamState = data[2];
1648 			cam->params.status.fatalError = data[3];
1649 			cam->params.status.cmdError = data[4];
1650 			cam->params.status.debugFlags = data[5];
1651 			cam->params.status.vpStatus = data[6];
1652 			cam->params.status.errorCode = data[7];
1653 			break;
1654 		case CPIA_COMMAND_GetVPVersion:
1655 			cam->params.vpVersion.vpVersion = data[0];
1656 			cam->params.vpVersion.vpRevision = data[1];
1657 			cam->params.vpVersion.cameraHeadID =
1658 				data[2]+(((u16)data[3])<<8);
1659 			break;
1660 		case CPIA_COMMAND_GetColourParams:
1661 			cam->params.colourParams.brightness = data[0];
1662 			cam->params.colourParams.contrast = data[1];
1663 			cam->params.colourParams.saturation = data[2];
1664 			up(&cam->param_lock);
1665 			break;
1666 		case CPIA_COMMAND_GetColourBalance:
1667 			cam->params.colourBalance.redGain = data[0];
1668 			cam->params.colourBalance.greenGain = data[1];
1669 			cam->params.colourBalance.blueGain = data[2];
1670 			up(&cam->param_lock);
1671 			break;
1672 		case CPIA_COMMAND_GetExposure:
1673 			cam->params.exposure.gain = data[0];
1674 			cam->params.exposure.fineExp = data[1];
1675 			cam->params.exposure.coarseExpLo = data[2];
1676 			cam->params.exposure.coarseExpHi = data[3];
1677 			cam->params.exposure.redComp = data[4];
1678 			cam->params.exposure.green1Comp = data[5];
1679 			cam->params.exposure.green2Comp = data[6];
1680 			cam->params.exposure.blueComp = data[7];
1681 			/* If the *Comp parameters are wacko, generate
1682 			 * a warning, and reset them back to default
1683 			 * values.             - rich@annexia.org
1684 			 */
1685 			if (cam->params.exposure.redComp < 220 ||
1686 			    cam->params.exposure.green1Comp < 214 ||
1687 			    cam->params.exposure.green2Comp < 214 ||
1688 			    cam->params.exposure.blueComp < 230)
1689 			  {
1690 			    printk (KERN_WARNING "*_comp parameters have gone AWOL (%d/%d/%d/%d) - reseting them\n",
1691 				    cam->params.exposure.redComp,
1692 				    cam->params.exposure.green1Comp,
1693 				    cam->params.exposure.green2Comp,
1694 				    cam->params.exposure.blueComp);
1695 			    cam->params.exposure.redComp = 220;
1696 			    cam->params.exposure.green1Comp = 214;
1697 			    cam->params.exposure.green2Comp = 214;
1698 			    cam->params.exposure.blueComp = 230;
1699 			  }
1700 			up(&cam->param_lock);
1701 			break;
1702 
1703 		case CPIA_COMMAND_ReadMCPorts:
1704 			if (!cam->params.qx3.qx3_detected)
1705 				break;
1706 			/* test button press */
1707 			cam->params.qx3.button = ((data[1] & 0x02) == 0);
1708 			if (cam->params.qx3.button) {
1709 				/* button pressed - unlock the latch */
1710 				do_command(cam,CPIA_COMMAND_WriteMCPort,3,0xDF,0xDF,0);
1711 				do_command(cam,CPIA_COMMAND_WriteMCPort,3,0xFF,0xFF,0);
1712 			}
1713 
1714 			/* test whether microscope is cradled */
1715 			cam->params.qx3.cradled = ((data[2] & 0x40) == 0);
1716 			break;
1717 
1718 		default:
1719 			break;
1720 		}
1721 	}
1722 	return retval;
1723 }
1724 
1725 /* send a command  to the camera with an additional data transaction */
do_command_extended(struct cam_data * cam,u16 command,u8 a,u8 b,u8 c,u8 d,u8 e,u8 f,u8 g,u8 h,u8 i,u8 j,u8 k,u8 l)1726 static int do_command_extended(struct cam_data *cam, u16 command,
1727                                u8 a, u8 b, u8 c, u8 d,
1728                                u8 e, u8 f, u8 g, u8 h,
1729                                u8 i, u8 j, u8 k, u8 l)
1730 {
1731 	int retval;
1732 	u8 cmd[8], data[8];
1733 
1734 	cmd[0] = command>>8;
1735 	cmd[1] = command&0xff;
1736 	cmd[2] = a;
1737 	cmd[3] = b;
1738 	cmd[4] = c;
1739 	cmd[5] = d;
1740 	cmd[6] = 8;
1741 	cmd[7] = 0;
1742 	data[0] = e;
1743 	data[1] = f;
1744 	data[2] = g;
1745 	data[3] = h;
1746 	data[4] = i;
1747 	data[5] = j;
1748 	data[6] = k;
1749 	data[7] = l;
1750 
1751 	retval = cam->ops->transferCmd(cam->lowlevel_data, cmd, data);
1752 	if (retval)
1753 		DBG("%x - failed\n", command);
1754 
1755 	return retval;
1756 }
1757 
1758 /**********************************************************************
1759  *
1760  * Colorspace conversion
1761  *
1762  **********************************************************************/
1763 #define LIMIT(x) ((((x)>0xffffff)?0xff0000:(((x)<=0xffff)?0:(x)&0xff0000))>>16)
1764 
yuvconvert(unsigned char * yuv,unsigned char * rgb,int out_fmt,int in_uyvy,int mmap_kludge)1765 static int yuvconvert(unsigned char *yuv, unsigned char *rgb, int out_fmt,
1766                       int in_uyvy, int mmap_kludge)
1767 {
1768 	int y, u, v, r, g, b, y1;
1769 
1770 	switch(out_fmt) {
1771 	case VIDEO_PALETTE_RGB555:
1772 	case VIDEO_PALETTE_RGB565:
1773 	case VIDEO_PALETTE_RGB24:
1774 	case VIDEO_PALETTE_RGB32:
1775 		if (in_uyvy) {
1776 			u = *yuv++ - 128;
1777 			y = (*yuv++ - 16) * 76310;
1778 			v = *yuv++ - 128;
1779 			y1 = (*yuv - 16) * 76310;
1780 		} else {
1781 			y = (*yuv++ - 16) * 76310;
1782 			u = *yuv++ - 128;
1783 			y1 = (*yuv++ - 16) * 76310;
1784 			v = *yuv - 128;
1785 		}
1786 		r = 104635 * v;
1787 		g = -25690 * u + -53294 * v;
1788 		b = 132278 * u;
1789 		break;
1790 	default:
1791 		y = *yuv++;
1792 		u = *yuv++;
1793 		y1 = *yuv++;
1794 		v = *yuv;
1795 		/* Just to avoid compiler warnings */
1796 		r = 0;
1797 		g = 0;
1798 		b = 0;
1799 		break;
1800 	}
1801 	switch(out_fmt) {
1802 	case VIDEO_PALETTE_RGB555:
1803 		*rgb++ = ((LIMIT(g+y) & 0xf8) << 2) | (LIMIT(b+y) >> 3);
1804 		*rgb++ = ((LIMIT(r+y) & 0xf8) >> 1) | (LIMIT(g+y) >> 6);
1805 		*rgb++ = ((LIMIT(g+y1) & 0xf8) << 2) | (LIMIT(b+y1) >> 3);
1806 		*rgb = ((LIMIT(r+y1) & 0xf8) >> 1) | (LIMIT(g+y1) >> 6);
1807 		return 4;
1808 	case VIDEO_PALETTE_RGB565:
1809 		*rgb++ = ((LIMIT(g+y) & 0xfc) << 3) | (LIMIT(b+y) >> 3);
1810 		*rgb++ = (LIMIT(r+y) & 0xf8) | (LIMIT(g+y) >> 5);
1811 		*rgb++ = ((LIMIT(g+y1) & 0xfc) << 3) | (LIMIT(b+y1) >> 3);
1812 		*rgb = (LIMIT(r+y1) & 0xf8) | (LIMIT(g+y1) >> 5);
1813 		return 4;
1814 	case VIDEO_PALETTE_RGB24:
1815 		if (mmap_kludge) {
1816 			*rgb++ = LIMIT(b+y);
1817 			*rgb++ = LIMIT(g+y);
1818 			*rgb++ = LIMIT(r+y);
1819 			*rgb++ = LIMIT(b+y1);
1820 			*rgb++ = LIMIT(g+y1);
1821 			*rgb = LIMIT(r+y1);
1822 		} else {
1823 			*rgb++ = LIMIT(r+y);
1824 			*rgb++ = LIMIT(g+y);
1825 			*rgb++ = LIMIT(b+y);
1826 			*rgb++ = LIMIT(r+y1);
1827 			*rgb++ = LIMIT(g+y1);
1828 			*rgb = LIMIT(b+y1);
1829 		}
1830 		return 6;
1831 	case VIDEO_PALETTE_RGB32:
1832 		if (mmap_kludge) {
1833 			*rgb++ = LIMIT(b+y);
1834 			*rgb++ = LIMIT(g+y);
1835 			*rgb++ = LIMIT(r+y);
1836 			rgb++;
1837 			*rgb++ = LIMIT(b+y1);
1838 			*rgb++ = LIMIT(g+y1);
1839 			*rgb = LIMIT(r+y1);
1840 		} else {
1841 			*rgb++ = LIMIT(r+y);
1842 			*rgb++ = LIMIT(g+y);
1843 			*rgb++ = LIMIT(b+y);
1844 			rgb++;
1845 			*rgb++ = LIMIT(r+y1);
1846 			*rgb++ = LIMIT(g+y1);
1847 			*rgb = LIMIT(b+y1);
1848 		}
1849 		return 8;
1850 	case VIDEO_PALETTE_GREY:
1851 		*rgb++ = y;
1852 		*rgb = y1;
1853 		return 2;
1854 	case VIDEO_PALETTE_YUV422:
1855 	case VIDEO_PALETTE_YUYV:
1856 		*rgb++ = y;
1857 		*rgb++ = u;
1858 		*rgb++ = y1;
1859 		*rgb = v;
1860 		return 4;
1861 	case VIDEO_PALETTE_UYVY:
1862 		*rgb++ = u;
1863 		*rgb++ = y;
1864 		*rgb++ = v;
1865 		*rgb = y1;
1866 		return 4;
1867 	default:
1868 		DBG("Empty: %d\n", out_fmt);
1869 		return 0;
1870 	}
1871 }
1872 
skipcount(int count,int fmt)1873 static int skipcount(int count, int fmt)
1874 {
1875 	switch(fmt) {
1876 	case VIDEO_PALETTE_GREY:
1877 		return count;
1878 	case VIDEO_PALETTE_RGB555:
1879 	case VIDEO_PALETTE_RGB565:
1880 	case VIDEO_PALETTE_YUV422:
1881 	case VIDEO_PALETTE_YUYV:
1882 	case VIDEO_PALETTE_UYVY:
1883 		return 2*count;
1884 	case VIDEO_PALETTE_RGB24:
1885 		return 3*count;
1886 	case VIDEO_PALETTE_RGB32:
1887 		return 4*count;
1888 	default:
1889 		return 0;
1890 	}
1891 }
1892 
parse_picture(struct cam_data * cam,int size)1893 static int parse_picture(struct cam_data *cam, int size)
1894 {
1895 	u8 *obuf, *ibuf, *end_obuf;
1896 	int ll, in_uyvy, compressed, origsize, out_fmt;
1897 
1898 	/* make sure params don't change while we are decoding */
1899 	down(&cam->param_lock);
1900 
1901 	obuf = cam->decompressed_frame.data;
1902 	end_obuf = obuf+CPIA_MAX_FRAME_SIZE;
1903 	ibuf = cam->raw_image;
1904 	origsize = size;
1905 	out_fmt = cam->vp.palette;
1906 
1907 	if ((ibuf[0] != MAGIC_0) || (ibuf[1] != MAGIC_1)) {
1908 		LOG("header not found\n");
1909 		up(&cam->param_lock);
1910 		return -1;
1911 	}
1912 
1913 	if ((ibuf[16] != VIDEOSIZE_QCIF) && (ibuf[16] != VIDEOSIZE_CIF)) {
1914 		LOG("wrong video size\n");
1915 		up(&cam->param_lock);
1916 		return -1;
1917 	}
1918 
1919 	if (ibuf[17] != SUBSAMPLE_422) {
1920 		LOG("illegal subtype %d\n",ibuf[17]);
1921 		up(&cam->param_lock);
1922 		return -1;
1923 	}
1924 
1925 	if (ibuf[18] != YUVORDER_YUYV && ibuf[18] != YUVORDER_UYVY) {
1926 		LOG("illegal yuvorder %d\n",ibuf[18]);
1927 		up(&cam->param_lock);
1928 		return -1;
1929 	}
1930 	in_uyvy = ibuf[18] == YUVORDER_UYVY;
1931 
1932 #if 0
1933 	/* FIXME: ROI mismatch occurs when switching capture sizes */
1934 	if ((ibuf[24] != cam->params.roi.colStart) ||
1935 	    (ibuf[25] != cam->params.roi.colEnd) ||
1936 	    (ibuf[26] != cam->params.roi.rowStart) ||
1937 	    (ibuf[27] != cam->params.roi.rowEnd)) {
1938 		LOG("ROI mismatch\n");
1939 		up(&cam->param_lock);
1940 		return -1;
1941 	}
1942 #endif
1943 
1944 	if ((ibuf[28] != NOT_COMPRESSED) && (ibuf[28] != COMPRESSED)) {
1945 		LOG("illegal compression %d\n",ibuf[28]);
1946 		up(&cam->param_lock);
1947 		return -1;
1948 	}
1949 	compressed = (ibuf[28] == COMPRESSED);
1950 
1951 	if (ibuf[29] != NO_DECIMATION) {
1952 		LOG("decimation not supported\n");
1953 		up(&cam->param_lock);
1954 		return -1;
1955 	}
1956 
1957 	cam->params.yuvThreshold.yThreshold = ibuf[30];
1958 	cam->params.yuvThreshold.uvThreshold = ibuf[31];
1959 	cam->params.status.systemState = ibuf[32];
1960 	cam->params.status.grabState = ibuf[33];
1961 	cam->params.status.streamState = ibuf[34];
1962 	cam->params.status.fatalError = ibuf[35];
1963 	cam->params.status.cmdError = ibuf[36];
1964 	cam->params.status.debugFlags = ibuf[37];
1965 	cam->params.status.vpStatus = ibuf[38];
1966 	cam->params.status.errorCode = ibuf[39];
1967 	cam->fps = ibuf[41];
1968 	up(&cam->param_lock);
1969 
1970 	ibuf += FRAME_HEADER_SIZE;
1971 	size -= FRAME_HEADER_SIZE;
1972 	ll = ibuf[0] | (ibuf[1] << 8);
1973 	ibuf += 2;
1974 
1975 	while (size > 0) {
1976 		size -= (ll+2);
1977 		if (size < 0) {
1978 			DBG("Insufficient data in buffer\n");
1979 			return -1;
1980 		}
1981 
1982 		while (ll > 1) {
1983 			if (!compressed || (compressed && !(*ibuf & 1))) {
1984 				obuf += yuvconvert(ibuf, obuf, out_fmt,
1985 				                   in_uyvy, cam->mmap_kludge);
1986 				ibuf += 4;
1987 				ll -= 4;
1988 			} else {
1989 				/*skip compressed interval from previous frame*/
1990 				int skipsize = skipcount(*ibuf >> 1, out_fmt);
1991 				obuf += skipsize;
1992 				if (obuf > end_obuf) {
1993 					DBG("Insufficient data in buffer\n");
1994 					return -1;
1995 				}
1996 				++ibuf;
1997 				ll--;
1998 			}
1999 		}
2000 		if (ll == 1) {
2001 			if (*ibuf != EOL) {
2002 				DBG("EOL not found giving up after %d/%d"
2003 				    " bytes\n", origsize-size, origsize);
2004 				return -1;
2005 			}
2006 
2007 			ibuf++; /* skip over EOL */
2008 
2009 			if ((size > 3) && (ibuf[0] == EOI) && (ibuf[1] == EOI) &&
2010 			   (ibuf[2] == EOI) && (ibuf[3] == EOI)) {
2011 			 	size -= 4;
2012 				break;
2013 			}
2014 
2015 			if (size > 1) {
2016 				ll = ibuf[0] | (ibuf[1] << 8);
2017 				ibuf += 2; /* skip over line length */
2018 			}
2019 		} else {
2020 			DBG("line length was not 1 but %d after %d/%d bytes\n",
2021 			    ll, origsize-size, origsize);
2022 			return -1;
2023 		}
2024 	}
2025 
2026 	cam->decompressed_frame.count = obuf-cam->decompressed_frame.data;
2027 
2028 	return cam->decompressed_frame.count;
2029 }
2030 
2031 /* InitStreamCap wrapper to select correct start line */
init_stream_cap(struct cam_data * cam)2032 static inline int init_stream_cap(struct cam_data *cam)
2033 {
2034 	return do_command(cam, CPIA_COMMAND_InitStreamCap,
2035 	                  0, cam->params.streamStartLine, 0, 0);
2036 }
2037 
2038 /* update various camera modes and settings */
dispatch_commands(struct cam_data * cam)2039 static void dispatch_commands(struct cam_data *cam)
2040 {
2041 	down(&cam->param_lock);
2042 	if (cam->cmd_queue==COMMAND_NONE) {
2043 		up(&cam->param_lock);
2044 		return;
2045 	}
2046 	DEB_BYTE(cam->cmd_queue);
2047 	DEB_BYTE(cam->cmd_queue>>8);
2048 	if (cam->cmd_queue & COMMAND_SETCOLOURPARAMS)
2049 		do_command(cam, CPIA_COMMAND_SetColourParams,
2050 		           cam->params.colourParams.brightness,
2051 		           cam->params.colourParams.contrast,
2052 		           cam->params.colourParams.saturation, 0);
2053 
2054 	if (cam->cmd_queue & COMMAND_SETCOMPRESSION)
2055 		do_command(cam, CPIA_COMMAND_SetCompression,
2056 		           cam->params.compression.mode,
2057 			   cam->params.compression.decimation, 0, 0);
2058 
2059 	if (cam->cmd_queue & COMMAND_SETFORMAT) {
2060 		do_command(cam, CPIA_COMMAND_SetFormat,
2061 	        	   cam->params.format.videoSize,
2062 	        	   cam->params.format.subSample,
2063 	        	   cam->params.format.yuvOrder, 0);
2064 		do_command(cam, CPIA_COMMAND_SetROI,
2065 	        	   cam->params.roi.colStart, cam->params.roi.colEnd,
2066 	        	   cam->params.roi.rowStart, cam->params.roi.rowEnd);
2067 		cam->first_frame = 1;
2068 	}
2069 
2070 	if (cam->cmd_queue & COMMAND_SETCOMPRESSIONTARGET)
2071 		do_command(cam, CPIA_COMMAND_SetCompressionTarget,
2072 		           cam->params.compressionTarget.frTargeting,
2073 		           cam->params.compressionTarget.targetFR,
2074 		           cam->params.compressionTarget.targetQ, 0);
2075 
2076 	if (cam->cmd_queue & COMMAND_SETYUVTHRESH)
2077 		do_command(cam, CPIA_COMMAND_SetYUVThresh,
2078 		           cam->params.yuvThreshold.yThreshold,
2079 		           cam->params.yuvThreshold.uvThreshold, 0, 0);
2080 
2081 	if (cam->cmd_queue & COMMAND_SETECPTIMING)
2082 		do_command(cam, CPIA_COMMAND_SetECPTiming,
2083 		           cam->params.ecpTiming, 0, 0, 0);
2084 
2085 	if (cam->cmd_queue & COMMAND_SETCOMPRESSIONPARAMS)
2086 		do_command_extended(cam, CPIA_COMMAND_SetCompressionParams,
2087 		            0, 0, 0, 0,
2088 		            cam->params.compressionParams.hysteresis,
2089 		            cam->params.compressionParams.threshMax,
2090 		            cam->params.compressionParams.smallStep,
2091 		            cam->params.compressionParams.largeStep,
2092 		            cam->params.compressionParams.decimationHysteresis,
2093 		            cam->params.compressionParams.frDiffStepThresh,
2094 		            cam->params.compressionParams.qDiffStepThresh,
2095 		            cam->params.compressionParams.decimationThreshMod);
2096 
2097 	if (cam->cmd_queue & COMMAND_SETEXPOSURE)
2098 		do_command_extended(cam, CPIA_COMMAND_SetExposure,
2099 		                    cam->params.exposure.gainMode,
2100 		                    cam->params.exposure.expMode,
2101 		                    cam->params.exposure.compMode,
2102 		                    cam->params.exposure.centreWeight,
2103 		                    cam->params.exposure.gain,
2104 		                    cam->params.exposure.fineExp,
2105 		                    cam->params.exposure.coarseExpLo,
2106 		                    cam->params.exposure.coarseExpHi,
2107 		                    cam->params.exposure.redComp,
2108 		                    cam->params.exposure.green1Comp,
2109 		                    cam->params.exposure.green2Comp,
2110 		                    cam->params.exposure.blueComp);
2111 
2112 	if (cam->cmd_queue & COMMAND_SETCOLOURBALANCE) {
2113 		if (cam->params.colourBalance.balanceModeIsAuto) {
2114 			do_command(cam, CPIA_COMMAND_SetColourBalance,
2115 				   2, 0, 0, 0);
2116 		} else {
2117 			do_command(cam, CPIA_COMMAND_SetColourBalance,
2118 				   1,
2119 				   cam->params.colourBalance.redGain,
2120 				   cam->params.colourBalance.greenGain,
2121 				   cam->params.colourBalance.blueGain);
2122 			do_command(cam, CPIA_COMMAND_SetColourBalance,
2123 				   3, 0, 0, 0);
2124 		}
2125 	}
2126 
2127 	if (cam->cmd_queue & COMMAND_SETSENSORFPS)
2128 		do_command(cam, CPIA_COMMAND_SetSensorFPS,
2129 		           cam->params.sensorFps.divisor,
2130 		           cam->params.sensorFps.baserate, 0, 0);
2131 
2132 	if (cam->cmd_queue & COMMAND_SETAPCOR)
2133 		do_command(cam, CPIA_COMMAND_SetApcor,
2134 		           cam->params.apcor.gain1,
2135 		           cam->params.apcor.gain2,
2136 		           cam->params.apcor.gain4,
2137 		           cam->params.apcor.gain8);
2138 
2139 	if (cam->cmd_queue & COMMAND_SETFLICKERCTRL)
2140 		do_command(cam, CPIA_COMMAND_SetFlickerCtrl,
2141 		           cam->params.flickerControl.flickerMode,
2142 		           cam->params.flickerControl.coarseJump,
2143 		           cam->params.flickerControl.allowableOverExposure, 0);
2144 
2145 	if (cam->cmd_queue & COMMAND_SETVLOFFSET)
2146 		do_command(cam, CPIA_COMMAND_SetVLOffset,
2147 		           cam->params.vlOffset.gain1,
2148 		           cam->params.vlOffset.gain2,
2149 		           cam->params.vlOffset.gain4,
2150 		           cam->params.vlOffset.gain8);
2151 
2152 	if (cam->cmd_queue & COMMAND_PAUSE)
2153 		do_command(cam, CPIA_COMMAND_EndStreamCap, 0, 0, 0, 0);
2154 
2155 	if (cam->cmd_queue & COMMAND_RESUME)
2156 		init_stream_cap(cam);
2157 
2158 	if (cam->cmd_queue & COMMAND_SETLIGHTS && cam->params.qx3.qx3_detected) {
2159 		int p1 = (cam->params.qx3.bottomlight == 0) << 1;
2160 		int p2 = (cam->params.qx3.toplight == 0) << 3;
2161 		do_command(cam, CPIA_COMMAND_WriteVCReg,  0x90, 0x8F, 0x50, 0);
2162 		do_command(cam, CPIA_COMMAND_WriteMCPort, 2, 0, (p1|p2|0xE0), 0);
2163 	}
2164 
2165 	up(&cam->param_lock);
2166 	cam->cmd_queue = COMMAND_NONE;
2167 	return;
2168 }
2169 
2170 /* kernel thread function to read image from camera */
fetch_frame(void * data)2171 static void fetch_frame(void *data)
2172 {
2173 	int image_size, retry;
2174 	struct cam_data *cam = (struct cam_data *)data;
2175 	unsigned long oldjif, rate, diff;
2176 
2177 	/* Allow up to two bad images in a row to be read and
2178 	 * ignored before an error is reported */
2179 	for (retry = 0; retry < 3; ++retry) {
2180 		if (retry)
2181 			DBG("retry=%d\n", retry);
2182 
2183 		if (!cam->ops)
2184 			continue;
2185 
2186 		/* load first frame always uncompressed */
2187 		if (cam->first_frame &&
2188 		    cam->params.compression.mode != CPIA_COMPRESSION_NONE)
2189 			do_command(cam, CPIA_COMMAND_SetCompression,
2190 				   CPIA_COMPRESSION_NONE,
2191 				   NO_DECIMATION, 0, 0);
2192 
2193 		/* init camera upload */
2194 		if (do_command(cam, CPIA_COMMAND_SetGrabMode,
2195 			       CPIA_GRAB_CONTINUOUS, 0, 0, 0))
2196 			continue;
2197 
2198 		if (do_command(cam, CPIA_COMMAND_GrabFrame, 0,
2199 			       cam->params.streamStartLine, 0, 0))
2200 			continue;
2201 
2202 		if (cam->ops->wait_for_stream_ready) {
2203 			/* loop until image ready */
2204 			do_command(cam, CPIA_COMMAND_GetCameraStatus,0,0,0,0);
2205 			while (cam->params.status.streamState != STREAM_READY) {
2206 				if (current->need_resched)
2207 					schedule();
2208 
2209 				current->state = TASK_INTERRUPTIBLE;
2210 
2211 				/* sleep for 10 ms, hopefully ;) */
2212 				schedule_timeout(10*HZ/1000);
2213 				if (signal_pending(current))
2214 					return;
2215 
2216 				do_command(cam, CPIA_COMMAND_GetCameraStatus,
2217 				           0, 0, 0, 0);
2218 			}
2219 		}
2220 
2221 		/* grab image from camera */
2222 		if (current->need_resched)
2223 			schedule();
2224 
2225 		oldjif = jiffies;
2226 		image_size = cam->ops->streamRead(cam->lowlevel_data,
2227 						  cam->raw_image, 0);
2228 		if (image_size <= 0) {
2229 			DBG("streamRead failed: %d\n", image_size);
2230 			continue;
2231 		}
2232 
2233 		rate = image_size * HZ / 1024;
2234 		diff = jiffies-oldjif;
2235 		cam->transfer_rate = diff==0 ? rate : rate/diff;
2236 			/* diff==0 ? unlikely but possible */
2237 
2238 		/* camera idle now so dispatch queued commands */
2239 		dispatch_commands(cam);
2240 
2241 		/* Update our knowledge of the camera state */
2242 		do_command(cam, CPIA_COMMAND_GetColourBalance, 0, 0, 0, 0);
2243 		do_command(cam, CPIA_COMMAND_GetExposure, 0, 0, 0, 0);
2244 		do_command(cam, CPIA_COMMAND_ReadMCPorts, 0, 0, 0, 0);
2245 
2246 		/* decompress and convert image to by copying it from
2247 		 * raw_image to decompressed_frame
2248 		 */
2249 		if (current->need_resched)
2250 			schedule();
2251 
2252 		cam->image_size = parse_picture(cam, image_size);
2253 		if (cam->image_size <= 0)
2254 			DBG("parse_picture failed %d\n", cam->image_size);
2255 		else
2256 			break;
2257 	}
2258 
2259 	if (retry < 3) {
2260 		/* FIXME: this only works for double buffering */
2261 		if (cam->frame[cam->curframe].state == FRAME_READY) {
2262 			memcpy(cam->frame[cam->curframe].data,
2263 			       cam->decompressed_frame.data,
2264 			       cam->decompressed_frame.count);
2265 			cam->frame[cam->curframe].state = FRAME_DONE;
2266 		} else
2267 			cam->decompressed_frame.state = FRAME_DONE;
2268 
2269 #if 0
2270 		if (cam->first_frame &&
2271 		    cam->params.compression.mode != CPIA_COMPRESSION_NONE) {
2272 			cam->first_frame = 0;
2273 			cam->cmd_queue |= COMMAND_SETCOMPRESSION;
2274 		}
2275 #else
2276 		if (cam->first_frame) {
2277 			cam->first_frame = 0;
2278 			cam->cmd_queue |= COMMAND_SETCOMPRESSION;
2279 			cam->cmd_queue |= COMMAND_SETEXPOSURE;
2280 		}
2281 #endif
2282 	}
2283 }
2284 
capture_frame(struct cam_data * cam,struct video_mmap * vm)2285 static int capture_frame(struct cam_data *cam, struct video_mmap *vm)
2286 {
2287 	int retval = 0;
2288 
2289 	if (!cam->frame_buf) {
2290 		/* we do lazy allocation */
2291 		if ((retval = allocate_frame_buf(cam)))
2292 			return retval;
2293 	}
2294 
2295 	/* FIXME: the first frame seems to be captured by the camera
2296 	   without regards to any initial settings, so we throw away
2297 	   that one, the next one is generated with our settings
2298 	   (exposure, color balance, ...)
2299 	*/
2300 	if (cam->first_frame) {
2301 		cam->curframe = vm->frame;
2302 		cam->frame[cam->curframe].state = FRAME_READY;
2303 		fetch_frame(cam);
2304 		if (cam->frame[cam->curframe].state != FRAME_DONE)
2305 			retval = -EIO;
2306 	}
2307 	cam->curframe = vm->frame;
2308 	cam->frame[cam->curframe].state = FRAME_READY;
2309 	fetch_frame(cam);
2310 	if (cam->frame[cam->curframe].state != FRAME_DONE)
2311 		retval=-EIO;
2312 
2313 	return retval;
2314 }
2315 
goto_high_power(struct cam_data * cam)2316 static int goto_high_power(struct cam_data *cam)
2317 {
2318 	if (do_command(cam, CPIA_COMMAND_GotoHiPower, 0, 0, 0, 0))
2319 		return -1;
2320 	mdelay(100);		/* windows driver does it too */
2321 	if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0))
2322 		return -1;
2323 	if (cam->params.status.systemState == HI_POWER_STATE) {
2324 		DBG("camera now in HIGH power state\n");
2325 		return 0;
2326 	}
2327 	printstatus(cam);
2328 	return -1;
2329 }
2330 
goto_low_power(struct cam_data * cam)2331 static int goto_low_power(struct cam_data *cam)
2332 {
2333 	if (do_command(cam, CPIA_COMMAND_GotoLoPower, 0, 0, 0, 0))
2334 		return -1;
2335 	if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0))
2336 		return -1;
2337 	if (cam->params.status.systemState == LO_POWER_STATE) {
2338 		DBG("camera now in LOW power state\n");
2339 		return 0;
2340 	}
2341 	printstatus(cam);
2342 	return -1;
2343 }
2344 
save_camera_state(struct cam_data * cam)2345 static void save_camera_state(struct cam_data *cam)
2346 {
2347 	do_command(cam, CPIA_COMMAND_GetColourBalance, 0, 0, 0, 0);
2348 	do_command(cam, CPIA_COMMAND_GetExposure, 0, 0, 0, 0);
2349 
2350 	DBG("%d/%d/%d/%d/%d/%d/%d/%d\n",
2351 	     cam->params.exposure.gain,
2352 	     cam->params.exposure.fineExp,
2353 	     cam->params.exposure.coarseExpLo,
2354 	     cam->params.exposure.coarseExpHi,
2355 	     cam->params.exposure.redComp,
2356 	     cam->params.exposure.green1Comp,
2357 	     cam->params.exposure.green2Comp,
2358 	     cam->params.exposure.blueComp);
2359 	DBG("%d/%d/%d\n",
2360 	     cam->params.colourBalance.redGain,
2361 	     cam->params.colourBalance.greenGain,
2362 	     cam->params.colourBalance.blueGain);
2363 }
2364 
set_camera_state(struct cam_data * cam)2365 static void set_camera_state(struct cam_data *cam)
2366 {
2367 	if(cam->params.colourBalance.balanceModeIsAuto) {
2368 		do_command(cam, CPIA_COMMAND_SetColourBalance,
2369 	        	   2, 0, 0, 0);
2370 	} else {
2371 		do_command(cam, CPIA_COMMAND_SetColourBalance,
2372 	        	   1,
2373 	        	   cam->params.colourBalance.redGain,
2374 	        	   cam->params.colourBalance.greenGain,
2375 	        	   cam->params.colourBalance.blueGain);
2376 		do_command(cam, CPIA_COMMAND_SetColourBalance,
2377 	        	   3, 0, 0, 0);
2378 	}
2379 
2380 
2381 	do_command_extended(cam, CPIA_COMMAND_SetExposure,
2382 			    cam->params.exposure.gainMode, 1, 1,
2383 			    cam->params.exposure.centreWeight,
2384 	                    cam->params.exposure.gain,
2385 	                    cam->params.exposure.fineExp,
2386 	                    cam->params.exposure.coarseExpLo,
2387 	                    cam->params.exposure.coarseExpHi,
2388 			    cam->params.exposure.redComp,
2389 			    cam->params.exposure.green1Comp,
2390 			    cam->params.exposure.green2Comp,
2391 			    cam->params.exposure.blueComp);
2392 	do_command_extended(cam, CPIA_COMMAND_SetExposure,
2393 			    0, 3, 0, 0,
2394 			    0, 0, 0, 0, 0, 0, 0, 0);
2395 
2396 	if (!cam->params.exposure.gainMode)
2397 		cam->params.exposure.gainMode = 2;
2398 	if (!cam->params.exposure.expMode)
2399 		cam->params.exposure.expMode = 2;
2400 	if (!cam->params.exposure.centreWeight)
2401 		cam->params.exposure.centreWeight = 1;
2402 
2403 	cam->cmd_queue = COMMAND_SETCOMPRESSION |
2404 	                 COMMAND_SETCOMPRESSIONTARGET |
2405 	                 COMMAND_SETCOLOURPARAMS |
2406 	                 COMMAND_SETFORMAT |
2407 	                 COMMAND_SETYUVTHRESH |
2408 	                 COMMAND_SETECPTIMING |
2409 	                 COMMAND_SETCOMPRESSIONPARAMS |
2410 #if 0
2411 	                 COMMAND_SETEXPOSURE |
2412 #endif
2413 	                 COMMAND_SETCOLOURBALANCE |
2414 	                 COMMAND_SETSENSORFPS |
2415 	                 COMMAND_SETAPCOR |
2416 	                 COMMAND_SETFLICKERCTRL |
2417 	                 COMMAND_SETVLOFFSET;
2418 	dispatch_commands(cam);
2419 	save_camera_state(cam);
2420 
2421 	return;
2422 }
2423 
get_version_information(struct cam_data * cam)2424 static void get_version_information(struct cam_data *cam)
2425 {
2426 	/* GetCPIAVersion */
2427 	do_command(cam, CPIA_COMMAND_GetCPIAVersion, 0, 0, 0, 0);
2428 
2429 	/* GetPnPID */
2430 	do_command(cam, CPIA_COMMAND_GetPnPID, 0, 0, 0, 0);
2431 }
2432 
2433 /* initialize camera */
reset_camera(struct cam_data * cam)2434 static int reset_camera(struct cam_data *cam)
2435 {
2436 	/* Start the camera in low power mode */
2437 	if (goto_low_power(cam)) {
2438 		if (cam->params.status.systemState != WARM_BOOT_STATE)
2439 			return -ENODEV;
2440 
2441 		/* FIXME: this is just dirty trial and error */
2442 		reset_camera_struct(cam);
2443 		goto_high_power(cam);
2444 		do_command(cam, CPIA_COMMAND_DiscardFrame, 0, 0, 0, 0);
2445 		if (goto_low_power(cam))
2446 			return -ENODEV;
2447 	}
2448 
2449 	/* procedure described in developer's guide p3-28 */
2450 
2451 	/* Check the firmware version FIXME: should we check PNPID? */
2452 	cam->params.version.firmwareVersion = 0;
2453 	get_version_information(cam);
2454 	if (cam->params.version.firmwareVersion != 1)
2455 		return -ENODEV;
2456 
2457 	/* set QX3 detected flag */
2458 	cam->params.qx3.qx3_detected = (cam->params.pnpID.vendor == 0x0813 &&
2459 					cam->params.pnpID.product == 0x0001);
2460 
2461 	/* The fatal error checking should be done after
2462 	 * the camera powers up (developer's guide p 3-38) */
2463 
2464 	/* Set streamState before transition to high power to avoid bug
2465 	 * in firmware 1-02 */
2466 	do_command(cam, CPIA_COMMAND_ModifyCameraStatus, STREAMSTATE, 0,
2467 	           STREAM_NOT_READY, 0);
2468 
2469 	/* GotoHiPower */
2470 	if (goto_high_power(cam))
2471 		return -ENODEV;
2472 
2473 	/* Check the camera status */
2474 	if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0))
2475 		return -EIO;
2476 
2477 	if (cam->params.status.fatalError) {
2478 		DBG("fatal_error:              %#04x\n",
2479 		    cam->params.status.fatalError);
2480 		DBG("vp_status:                %#04x\n",
2481 		    cam->params.status.vpStatus);
2482 		if (cam->params.status.fatalError & ~(COM_FLAG|CPIA_FLAG)) {
2483 			/* Fatal error in camera */
2484 			return -EIO;
2485 		} else if (cam->params.status.fatalError & (COM_FLAG|CPIA_FLAG)) {
2486 			/* Firmware 1-02 may do this for parallel port cameras,
2487 			 * just clear the flags (developer's guide p 3-38) */
2488 			do_command(cam, CPIA_COMMAND_ModifyCameraStatus,
2489 			           FATALERROR, ~(COM_FLAG|CPIA_FLAG), 0, 0);
2490 		}
2491 	}
2492 
2493 	/* Check the camera status again */
2494 	if (cam->params.status.fatalError) {
2495 		if (cam->params.status.fatalError)
2496 			return -EIO;
2497 	}
2498 
2499 	/* VPVersion can't be retrieved before the camera is in HiPower,
2500 	 * so get it here instead of in get_version_information. */
2501 	do_command(cam, CPIA_COMMAND_GetVPVersion, 0, 0, 0, 0);
2502 
2503 	/* set camera to a known state */
2504 	set_camera_state(cam);
2505 
2506 	return 0;
2507 }
2508 
put_cam(struct cpia_camera_ops * ops)2509 static void put_cam(struct cpia_camera_ops* ops)
2510 {
2511 	if (ops->owner)
2512 		__MOD_DEC_USE_COUNT(ops->owner);
2513 }
2514 
2515 /* ------------------------- V4L interface --------------------- */
cpia_open(struct inode * inode,struct file * file)2516 static int cpia_open(struct inode *inode, struct file *file)
2517 {
2518 	struct video_device *dev = video_devdata(file);
2519 	struct cam_data *cam = dev->priv;
2520 	int err;
2521 
2522 	if (!cam) {
2523 		DBG("Internal error, cam_data not found!\n");
2524 		return -ENODEV;
2525 	}
2526 
2527 	if (cam->open_count > 0) {
2528 		DBG("Camera already open\n");
2529 		return -EBUSY;
2530 	}
2531 
2532 	if (!try_inc_mod_count(cam->ops->owner))
2533 	  return -ENODEV;
2534 
2535 	down(&cam->busy_lock);
2536 
2537 	err = -ENOMEM;
2538 	if (!cam->raw_image) {
2539 		cam->raw_image = rvmalloc(CPIA_MAX_IMAGE_SIZE);
2540 		if (!cam->raw_image)
2541 			goto oops;
2542 	}
2543 
2544 	if (!cam->decompressed_frame.data) {
2545 		cam->decompressed_frame.data = rvmalloc(CPIA_MAX_FRAME_SIZE);
2546 		if (!cam->decompressed_frame.data)
2547 			goto oops;
2548 	}
2549 
2550 	/* open cpia */
2551 	err = -ENODEV;
2552 	if (cam->ops->open(cam->lowlevel_data))
2553 		goto oops;
2554 
2555 	/* reset the camera */
2556 	if ((err = reset_camera(cam)) != 0) {
2557 		cam->ops->close(cam->lowlevel_data);
2558 		goto oops;
2559 	}
2560 
2561 	/* Set ownership of /proc/cpia/videoX to current user */
2562 	if(cam->proc_entry)
2563 		cam->proc_entry->uid = current->uid;
2564 
2565 	/* set mark for loading first frame uncompressed */
2566 	cam->first_frame = 1;
2567 
2568 	/* init it to something */
2569 	cam->mmap_kludge = 0;
2570 
2571 	++cam->open_count;
2572 	file->private_data = dev;
2573 	up(&cam->busy_lock);
2574 	return 0;
2575 
2576  oops:
2577 	if (cam->decompressed_frame.data) {
2578 		rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE);
2579 		cam->decompressed_frame.data = NULL;
2580 	}
2581 	if (cam->raw_image) {
2582 		rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
2583 		cam->raw_image = NULL;
2584 	}
2585 	up(&cam->busy_lock);
2586 	put_cam(cam->ops);
2587 	return err;
2588 }
2589 
cpia_close(struct inode * inode,struct file * file)2590 static int cpia_close(struct inode *inode, struct file *file)
2591 {
2592 	struct  video_device *dev = file->private_data;
2593 	struct cam_data *cam = dev->priv;
2594 
2595 	if (cam->ops) {
2596 	        /* Return ownership of /proc/cpia/videoX to root */
2597 		if(cam->proc_entry)
2598 			cam->proc_entry->uid = 0;
2599 
2600 		/* save camera state for later open (developers guide ch 3.5.3) */
2601 		save_camera_state(cam);
2602 
2603 		/* GotoLoPower */
2604 		goto_low_power(cam);
2605 
2606 		/* Update the camera status */
2607 		do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0);
2608 
2609 		/* cleanup internal state stuff */
2610 		free_frames(cam->frame);
2611 
2612 		/* close cpia */
2613 		cam->ops->close(cam->lowlevel_data);
2614 		put_cam(cam->ops);
2615 	}
2616 
2617 	if (--cam->open_count == 0) {
2618 		/* clean up capture-buffers */
2619 		if (cam->raw_image) {
2620 			rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
2621 			cam->raw_image = NULL;
2622 		}
2623 
2624 		if (cam->decompressed_frame.data) {
2625 			rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE);
2626 			cam->decompressed_frame.data = NULL;
2627 		}
2628 
2629 		if (cam->frame_buf)
2630 			free_frame_buf(cam);
2631 
2632 		if (!cam->ops)
2633 			kfree(cam);
2634 	}
2635 
2636 	file->private_data = NULL;
2637 
2638 	return 0;
2639 }
2640 
cpia_read(struct file * file,char * buf,size_t count,loff_t * ppos)2641 static int cpia_read(struct file *file, char *buf,
2642 		     size_t count, loff_t *ppos)
2643 {
2644 	struct video_device *dev = file->private_data;
2645  	struct cam_data *cam = dev->priv;
2646 
2647 	/* make this _really_ smp and multithread-safe */
2648 	if (down_interruptible(&cam->busy_lock))
2649 		return -EINTR;
2650 
2651 	if (!buf) {
2652 		DBG("buf NULL\n");
2653 		up(&cam->busy_lock);
2654 		return -EINVAL;
2655 	}
2656 
2657 	if (!count) {
2658 		DBG("count 0\n");
2659 		up(&cam->busy_lock);
2660 		return 0;
2661 	}
2662 
2663 	if (!cam->ops) {
2664 		DBG("ops NULL\n");
2665 		up(&cam->busy_lock);
2666 		return -ENODEV;
2667 	}
2668 
2669 	/* upload frame */
2670 	cam->decompressed_frame.state = FRAME_READY;
2671 	cam->mmap_kludge=0;
2672 	fetch_frame(cam);
2673 	if (cam->decompressed_frame.state != FRAME_DONE) {
2674 		DBG("upload failed %d/%d\n", cam->decompressed_frame.count,
2675 		    cam->decompressed_frame.state);
2676 		up(&cam->busy_lock);
2677 		return -EIO;
2678 	}
2679 	cam->decompressed_frame.state = FRAME_UNUSED;
2680 
2681 	/* copy data to user space */
2682 	if (cam->decompressed_frame.count > count) {
2683 		DBG("count wrong: %d, %lu\n", cam->decompressed_frame.count,
2684 		    (unsigned long) count);
2685 		up(&cam->busy_lock);
2686 		return -EFAULT;
2687 	}
2688 	if (copy_to_user(buf, cam->decompressed_frame.data,
2689 	                cam->decompressed_frame.count)) {
2690 		DBG("copy_to_user failed\n");
2691 		up(&cam->busy_lock);
2692 		return -EFAULT;
2693 	}
2694 
2695 	up(&cam->busy_lock);
2696 	return cam->decompressed_frame.count;
2697 }
2698 
cpia_do_ioctl(struct inode * inode,struct file * file,unsigned int ioctlnr,void * arg)2699 static int cpia_do_ioctl(struct inode *inode, struct file *file,
2700 			 unsigned int ioctlnr, void *arg)
2701 {
2702 	struct video_device *dev = file->private_data;
2703 	struct cam_data *cam = dev->priv;
2704 	int retval = 0;
2705 
2706 	if (!cam || !cam->ops)
2707 		return -ENODEV;
2708 
2709 	/* make this _really_ smp-safe */
2710 	if (down_interruptible(&cam->busy_lock))
2711 		return -EINTR;
2712 
2713 	//DBG("cpia_ioctl: %u\n", ioctlnr);
2714 
2715 	switch (ioctlnr) {
2716 	/* query capabilites */
2717 	case VIDIOCGCAP:
2718 	{
2719 		struct video_capability *b = arg;
2720 
2721 		DBG("VIDIOCGCAP\n");
2722 		strcpy(b->name, "CPiA Camera");
2723 		b->type = VID_TYPE_CAPTURE;
2724 		b->channels = 1;
2725 		b->audios = 0;
2726 		b->maxwidth = 352;	/* VIDEOSIZE_CIF */
2727 		b->maxheight = 288;
2728 		b->minwidth = 48;	/* VIDEOSIZE_48_48 */
2729 		b->minheight = 48;
2730 
2731 		break;
2732 	}
2733 
2734 	/* get/set video source - we are a camera and nothing else */
2735 	case VIDIOCGCHAN:
2736 	{
2737 		struct video_channel *v = arg;
2738 
2739 		DBG("VIDIOCGCHAN\n");
2740 		if (v->channel != 0) {
2741 			retval = -EINVAL;
2742 			break;
2743 		}
2744 
2745 		v->channel = 0;
2746 		strcpy(v->name, "Camera");
2747 		v->tuners = 0;
2748 		v->flags = 0;
2749 		v->type = VIDEO_TYPE_CAMERA;
2750 		v->norm = 0;
2751 
2752 		break;
2753 	}
2754 
2755 	case VIDIOCSCHAN:
2756 	{
2757 		struct video_channel *v = arg;
2758 
2759 		DBG("VIDIOCSCHAN\n");
2760 		if (v->channel != 0)
2761 			retval = -EINVAL;
2762 
2763 		break;
2764 	}
2765 
2766 	/* image properties */
2767 	case VIDIOCGPICT:
2768 	{
2769  		struct video_picture *pic = arg;
2770 
2771 		DBG("VIDIOCGPICT\n");
2772  		*pic = cam->vp;
2773 		break;
2774 	}
2775 
2776 	case VIDIOCSPICT:
2777 	{
2778 		struct video_picture *vp = arg;
2779 
2780 		DBG("VIDIOCSPICT\n");
2781 
2782 		/* check validity */
2783 		DBG("palette: %d\n", vp->palette);
2784 		DBG("depth: %d\n", vp->depth);
2785 		if (!valid_mode(vp->palette, vp->depth)) {
2786 			retval = -EINVAL;
2787 			break;
2788 		}
2789 
2790 		down(&cam->param_lock);
2791 		/* brightness, colour, contrast need no check 0-65535 */
2792 		cam->vp = *vp;
2793 		/* update cam->params.colourParams */
2794 		cam->params.colourParams.brightness = vp->brightness*100/65535;
2795 		cam->params.colourParams.contrast = vp->contrast*100/65535;
2796 		cam->params.colourParams.saturation = vp->colour*100/65535;
2797 		/* contrast is in steps of 8, so round */
2798 		cam->params.colourParams.contrast =
2799 			((cam->params.colourParams.contrast + 3) / 8) * 8;
2800 		if (cam->params.version.firmwareVersion == 1 &&
2801 		    cam->params.version.firmwareRevision == 2 &&
2802 		    cam->params.colourParams.contrast > 80) {
2803 			/* 1-02 firmware limits contrast to 80 */
2804 			cam->params.colourParams.contrast = 80;
2805 		}
2806 
2807 		/* queue command to update camera */
2808 		cam->cmd_queue |= COMMAND_SETCOLOURPARAMS;
2809 		up(&cam->param_lock);
2810 		DBG("VIDIOCSPICT: %d / %d // %d / %d / %d / %d\n",
2811 		    vp->depth, vp->palette, vp->brightness, vp->hue,
2812 		    vp->colour, vp->contrast);
2813 		break;
2814 	}
2815 
2816 	/* get/set capture window */
2817 	case VIDIOCGWIN:
2818 	{
2819 		struct video_window *vw = arg;
2820 
2821 		DBG("VIDIOCGWIN\n");
2822 
2823 		*vw = cam->vw;
2824 		break;
2825 	}
2826 
2827 	case VIDIOCSWIN:
2828 	{
2829 		/* copy_from_user, check validity, copy to internal structure */
2830 		struct video_window *vw = arg;
2831 		DBG("VIDIOCSWIN\n");
2832 
2833 		if (vw->clipcount != 0) {    /* clipping not supported */
2834 			retval = -EINVAL;
2835 			break;
2836 		}
2837 		if (vw->clips != NULL) {     /* clipping not supported */
2838 			retval = -EINVAL;
2839 			break;
2840 		}
2841 
2842 		/* we set the video window to something smaller or equal to what
2843 		* is requested by the user???
2844 		*/
2845 		down(&cam->param_lock);
2846 		if (vw->width != cam->vw.width || vw->height != cam->vw.height) {
2847 			int video_size = match_videosize(vw->width, vw->height);
2848 
2849 			if (video_size < 0) {
2850 				retval = -EINVAL;
2851 				up(&cam->param_lock);
2852 				break;
2853 			}
2854 			cam->video_size = video_size;
2855 			set_vw_size(cam);
2856 			DBG("%d / %d\n", cam->vw.width, cam->vw.height);
2857 			cam->cmd_queue |= COMMAND_SETFORMAT;
2858 		}
2859 
2860 		up(&cam->param_lock);
2861 
2862 		/* setformat ignored by camera during streaming,
2863 		 * so stop/dispatch/start */
2864 		if (cam->cmd_queue & COMMAND_SETFORMAT) {
2865 			DBG("\n");
2866 			dispatch_commands(cam);
2867 		}
2868 		DBG("%d/%d:%d\n", cam->video_size,
2869 		    cam->vw.width, cam->vw.height);
2870 		break;
2871 	}
2872 
2873 	/* mmap interface */
2874 	case VIDIOCGMBUF:
2875 	{
2876 		struct video_mbuf *vm = arg;
2877 		int i;
2878 
2879 		DBG("VIDIOCGMBUF\n");
2880 		memset(vm, 0, sizeof(*vm));
2881 		vm->size = CPIA_MAX_FRAME_SIZE*FRAME_NUM;
2882 		vm->frames = FRAME_NUM;
2883 		for (i = 0; i < FRAME_NUM; i++)
2884 			vm->offsets[i] = CPIA_MAX_FRAME_SIZE * i;
2885 
2886 		break;
2887 	}
2888 
2889 	case VIDIOCMCAPTURE:
2890 	{
2891 		struct video_mmap *vm = arg;
2892 		int video_size;
2893 
2894 		DBG("VIDIOCMCAPTURE: %d / %d / %dx%d\n", vm->format, vm->frame,
2895 		    vm->width, vm->height);
2896 		if (vm->frame<0||vm->frame>=FRAME_NUM) {
2897 			retval = -EINVAL;
2898 			break;
2899 		}
2900 
2901 		/* set video format */
2902 		cam->vp.palette = vm->format;
2903 		switch(vm->format) {
2904 		case VIDEO_PALETTE_GREY:
2905 			cam->vp.depth=8;
2906 			break;
2907 		case VIDEO_PALETTE_RGB555:
2908 		case VIDEO_PALETTE_RGB565:
2909 		case VIDEO_PALETTE_YUV422:
2910 		case VIDEO_PALETTE_YUYV:
2911 		case VIDEO_PALETTE_UYVY:
2912 			cam->vp.depth = 16;
2913 			break;
2914 		case VIDEO_PALETTE_RGB24:
2915 			cam->vp.depth = 24;
2916 			break;
2917 		case VIDEO_PALETTE_RGB32:
2918 			cam->vp.depth = 32;
2919 			break;
2920 		default:
2921 			retval = -EINVAL;
2922 			break;
2923 		}
2924 		if (retval)
2925 			break;
2926 
2927 		/* set video size */
2928 		video_size = match_videosize(vm->width, vm->height);
2929 		if (video_size < 0) {
2930 			retval = -EINVAL;
2931 			break;
2932 		}
2933 		if (video_size != cam->video_size) {
2934 			cam->video_size = video_size;
2935 			set_vw_size(cam);
2936 			cam->cmd_queue |= COMMAND_SETFORMAT;
2937 			dispatch_commands(cam);
2938 		}
2939 		/* according to v4l-spec we must start streaming here */
2940 		cam->mmap_kludge = 1;
2941 		retval = capture_frame(cam, vm);
2942 
2943 		break;
2944 	}
2945 
2946 	case VIDIOCSYNC:
2947 	{
2948 		int *frame = arg;
2949 
2950 		//DBG("VIDIOCSYNC: %d\n", *frame);
2951 
2952 		if (*frame<0 || *frame >= FRAME_NUM) {
2953 			retval = -EINVAL;
2954 			break;
2955 		}
2956 
2957 		switch (cam->frame[*frame].state) {
2958 		case FRAME_UNUSED:
2959 		case FRAME_READY:
2960 		case FRAME_GRABBING:
2961 			DBG("sync to unused frame %d\n", *frame);
2962 			retval = -EINVAL;
2963 			break;
2964 
2965 		case FRAME_DONE:
2966 			cam->frame[*frame].state = FRAME_UNUSED;
2967 			//DBG("VIDIOCSYNC: %d synced\n", *frame);
2968 			break;
2969 		}
2970 		if (retval == -EINTR) {
2971 			/* FIXME - xawtv does not handle this nice */
2972 			retval = 0;
2973 		}
2974 		break;
2975 	}
2976 
2977 	/* pointless to implement overlay with this camera */
2978 	case VIDIOCCAPTURE:
2979 	case VIDIOCGFBUF:
2980 	case VIDIOCSFBUF:
2981 	case VIDIOCKEY:
2982 		retval = -EINVAL;
2983 		break;
2984 
2985 	/* tuner interface - we have none */
2986 	case VIDIOCGTUNER:
2987 	case VIDIOCSTUNER:
2988 	case VIDIOCGFREQ:
2989 	case VIDIOCSFREQ:
2990 		retval = -EINVAL;
2991 		break;
2992 
2993 	/* audio interface - we have none */
2994 	case VIDIOCGAUDIO:
2995 	case VIDIOCSAUDIO:
2996 		retval = -EINVAL;
2997 		break;
2998 	default:
2999 		retval = -ENOIOCTLCMD;
3000 		break;
3001 	}
3002 
3003 	up(&cam->busy_lock);
3004 	return retval;
3005 }
3006 
cpia_ioctl(struct inode * inode,struct file * file,unsigned int cmd,unsigned long arg)3007 static int cpia_ioctl(struct inode *inode, struct file *file,
3008 		     unsigned int cmd, unsigned long arg)
3009 {
3010 	return video_usercopy(inode, file, cmd, arg, cpia_do_ioctl);
3011 }
3012 
3013 
3014 /* FIXME */
cpia_mmap(struct file * file,struct vm_area_struct * vma)3015 static int cpia_mmap(struct file *file, struct vm_area_struct *vma)
3016 {
3017 	struct video_device *dev = file->private_data;
3018 	unsigned long start = vma->vm_start;
3019 	unsigned long size  = vma->vm_end - vma->vm_start;
3020 	unsigned long page, pos;
3021 	struct cam_data *cam = dev->priv;
3022 	int retval;
3023 
3024 	if (!cam || !cam->ops)
3025 		return -ENODEV;
3026 
3027 	DBG("cpia_mmap: %ld\n", size);
3028 
3029 	if (size > FRAME_NUM*CPIA_MAX_FRAME_SIZE)
3030 		return -EINVAL;
3031 
3032 	if (!cam || !cam->ops)
3033 		return -ENODEV;
3034 
3035 	/* make this _really_ smp-safe */
3036 	if (down_interruptible(&cam->busy_lock))
3037 		return -EINTR;
3038 
3039 	if (!cam->frame_buf) {	/* we do lazy allocation */
3040 		if ((retval = allocate_frame_buf(cam))) {
3041 			up(&cam->busy_lock);
3042 			return retval;
3043 		}
3044 	}
3045 
3046 	pos = (unsigned long)(cam->frame_buf);
3047 	while (size > 0) {
3048 		page = kvirt_to_pa(pos);
3049 		if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) {
3050 			up(&cam->busy_lock);
3051 			return -EAGAIN;
3052 		}
3053 		start += PAGE_SIZE;
3054 		pos += PAGE_SIZE;
3055 		if (size > PAGE_SIZE)
3056 			size -= PAGE_SIZE;
3057 		else
3058 			size = 0;
3059 	}
3060 
3061 	DBG("cpia_mmap: %ld\n", size);
3062 	up(&cam->busy_lock);
3063 
3064 	return 0;
3065 }
3066 
3067 static struct file_operations cpia_fops = {
3068 	owner:		THIS_MODULE,
3069 	open:		cpia_open,
3070 	release:	cpia_close,
3071 	read:		cpia_read,
3072 	mmap:		cpia_mmap,
3073 	ioctl:		cpia_ioctl,
3074 	llseek:         no_llseek,
3075 };
3076 
3077 static struct video_device cpia_template = {
3078 	owner:		THIS_MODULE,
3079 	name:		"CPiA Camera",
3080 	type:		VID_TYPE_CAPTURE,
3081 	hardware:	VID_HARDWARE_CPIA,
3082 	fops:           &cpia_fops,
3083 	minor:		-1,
3084 };
3085 
3086 /* initialise cam_data structure  */
reset_camera_struct(struct cam_data * cam)3087 static void reset_camera_struct(struct cam_data *cam)
3088 {
3089 	/* The following parameter values are the defaults from
3090 	 * "Software Developer's Guide for CPiA Cameras".  Any changes
3091 	 * to the defaults are noted in comments. */
3092 	cam->params.colourParams.brightness = 50;
3093 	cam->params.colourParams.contrast = 48;
3094 	cam->params.colourParams.saturation = 50;
3095 	cam->params.exposure.gainMode = 2;
3096 	cam->params.exposure.expMode = 2;		/* AEC */
3097 	cam->params.exposure.compMode = 1;
3098 	cam->params.exposure.centreWeight = 1;
3099 	cam->params.exposure.gain = 0;
3100 	cam->params.exposure.fineExp = 0;
3101 	cam->params.exposure.coarseExpLo = 185;
3102 	cam->params.exposure.coarseExpHi = 0;
3103 	cam->params.exposure.redComp = 220;
3104 	cam->params.exposure.green1Comp = 214;
3105 	cam->params.exposure.green2Comp = 214;
3106 	cam->params.exposure.blueComp = 230;
3107 	cam->params.colourBalance.balanceModeIsAuto = 1;
3108 	cam->params.colourBalance.redGain = 32;
3109 	cam->params.colourBalance.greenGain = 6;
3110 	cam->params.colourBalance.blueGain = 92;
3111 	cam->params.apcor.gain1 = 0x1c;
3112 	cam->params.apcor.gain2 = 0x1a;
3113 	cam->params.apcor.gain4 = 0x2d;
3114 	cam->params.apcor.gain8 = 0x2a;
3115 	cam->params.flickerControl.flickerMode = 0;
3116 	cam->params.flickerControl.coarseJump =
3117 		flicker_jumps[cam->mainsFreq]
3118 		             [cam->params.sensorFps.baserate]
3119 		             [cam->params.sensorFps.divisor];
3120 	cam->params.vlOffset.gain1 = 24;
3121 	cam->params.vlOffset.gain2 = 28;
3122 	cam->params.vlOffset.gain4 = 30;
3123 	cam->params.vlOffset.gain8 = 30;
3124 	cam->params.compressionParams.hysteresis = 3;
3125 	cam->params.compressionParams.threshMax = 11;
3126 	cam->params.compressionParams.smallStep = 1;
3127 	cam->params.compressionParams.largeStep = 3;
3128 	cam->params.compressionParams.decimationHysteresis = 2;
3129 	cam->params.compressionParams.frDiffStepThresh = 5;
3130 	cam->params.compressionParams.qDiffStepThresh = 3;
3131 	cam->params.compressionParams.decimationThreshMod = 2;
3132 	/* End of default values from Software Developer's Guide */
3133 
3134 	cam->transfer_rate = 0;
3135 
3136 	/* Set Sensor FPS to 15fps. This seems better than 30fps
3137 	 * for indoor lighting. */
3138 	cam->params.sensorFps.divisor = 1;
3139 	cam->params.sensorFps.baserate = 1;
3140 
3141 	cam->params.yuvThreshold.yThreshold = 6; /* From windows driver */
3142 	cam->params.yuvThreshold.uvThreshold = 6; /* From windows driver */
3143 
3144 	cam->params.format.subSample = SUBSAMPLE_422;
3145 	cam->params.format.yuvOrder = YUVORDER_YUYV;
3146 
3147 	cam->params.compression.mode = CPIA_COMPRESSION_AUTO;
3148 	cam->params.compressionTarget.frTargeting =
3149 		CPIA_COMPRESSION_TARGET_QUALITY;
3150 	cam->params.compressionTarget.targetFR = 15; /* From windows driver */
3151 	cam->params.compressionTarget.targetQ = 5; /* From windows driver */
3152 
3153 	cam->params.qx3.qx3_detected = 0;
3154 	cam->params.qx3.toplight = 0;
3155 	cam->params.qx3.bottomlight = 0;
3156 	cam->params.qx3.button = 0;
3157 	cam->params.qx3.cradled = 0;
3158 
3159 	cam->video_size = VIDEOSIZE_CIF;
3160 
3161 	cam->vp.colour = 32768;      /* 50% */
3162 	cam->vp.hue = 32768;         /* 50% */
3163 	cam->vp.brightness = 32768;  /* 50% */
3164 	cam->vp.contrast = 32768;    /* 50% */
3165 	cam->vp.whiteness = 0;       /* not used -> grayscale only */
3166 	cam->vp.depth = 24;          /* to be set by user */
3167 	cam->vp.palette = VIDEO_PALETTE_RGB24; /* to be set by user */
3168 
3169 	cam->vw.x = 0;
3170 	cam->vw.y = 0;
3171 	set_vw_size(cam);
3172 	cam->vw.chromakey = 0;
3173 	/* PP NOTE: my extension to use vw.flags for this, bear it! */
3174 	cam->vw.flags = 0;
3175 	cam->vw.clipcount = 0;
3176 	cam->vw.clips = NULL;
3177 
3178 	cam->cmd_queue = COMMAND_NONE;
3179 	cam->first_frame = 0;
3180 
3181 	return;
3182 }
3183 
3184 /* initialize cam_data structure  */
init_camera_struct(struct cam_data * cam,struct cpia_camera_ops * ops)3185 static void init_camera_struct(struct cam_data *cam,
3186                                struct cpia_camera_ops *ops )
3187 {
3188 	int i;
3189 
3190 	/* Default everything to 0 */
3191 	memset(cam, 0, sizeof(struct cam_data));
3192 
3193 	cam->ops = ops;
3194 	init_MUTEX(&cam->param_lock);
3195 	init_MUTEX(&cam->busy_lock);
3196 
3197 	reset_camera_struct(cam);
3198 
3199 	cam->proc_entry = NULL;
3200 
3201 	memcpy(&cam->vdev, &cpia_template, sizeof(cpia_template));
3202 	cam->vdev.priv = cam;
3203 
3204 	cam->curframe = 0;
3205 	for (i = 0; i < FRAME_NUM; i++) {
3206 		cam->frame[i].width = 0;
3207 		cam->frame[i].height = 0;
3208 		cam->frame[i].state = FRAME_UNUSED;
3209 		cam->frame[i].data = NULL;
3210 	}
3211 	cam->decompressed_frame.width = 0;
3212 	cam->decompressed_frame.height = 0;
3213 	cam->decompressed_frame.state = FRAME_UNUSED;
3214 	cam->decompressed_frame.data = NULL;
3215 }
3216 
cpia_register_camera(struct cpia_camera_ops * ops,void * lowlevel)3217 struct cam_data *cpia_register_camera(struct cpia_camera_ops *ops, void *lowlevel)
3218 {
3219 	struct cam_data *camera;
3220 
3221 	if ((camera = kmalloc(sizeof(struct cam_data), GFP_KERNEL)) == NULL)
3222 		return NULL;
3223 
3224 	init_camera_struct( camera, ops );
3225 	camera->lowlevel_data = lowlevel;
3226 
3227 	/* register v4l device */
3228 	if (video_register_device(&camera->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
3229 		kfree(camera);
3230 		printk(KERN_DEBUG "video_register_device failed\n");
3231 		return NULL;
3232 	}
3233 
3234 	/* get version information from camera: open/reset/close */
3235 
3236 	/* open cpia */
3237 	if (camera->ops->open(camera->lowlevel_data))
3238 		return camera;
3239 
3240 	/* reset the camera */
3241 	if (reset_camera(camera) != 0) {
3242 		camera->ops->close(camera->lowlevel_data);
3243 		return camera;
3244 	}
3245 
3246 	/* close cpia */
3247 	camera->ops->close(camera->lowlevel_data);
3248 
3249 #ifdef CONFIG_PROC_FS
3250 	create_proc_cpia_cam(camera);
3251 #endif
3252 
3253 	printk(KERN_INFO "  CPiA Version: %d.%02d (%d.%d)\n",
3254 	       camera->params.version.firmwareVersion,
3255 	       camera->params.version.firmwareRevision,
3256 	       camera->params.version.vcVersion,
3257 	       camera->params.version.vcRevision);
3258 	printk(KERN_INFO "  CPiA PnP-ID: %04x:%04x:%04x\n",
3259 	       camera->params.pnpID.vendor,
3260 	       camera->params.pnpID.product,
3261 	       camera->params.pnpID.deviceRevision);
3262 	printk(KERN_INFO "  VP-Version: %d.%d %04x\n",
3263 	       camera->params.vpVersion.vpVersion,
3264 	       camera->params.vpVersion.vpRevision,
3265 	       camera->params.vpVersion.cameraHeadID);
3266 
3267 	return camera;
3268 }
3269 
cpia_unregister_camera(struct cam_data * cam)3270 void cpia_unregister_camera(struct cam_data *cam)
3271 {
3272 	DBG("unregistering video\n");
3273 	video_unregister_device(&cam->vdev);
3274 	if (cam->open_count) {
3275 		put_cam(cam->ops);
3276 		DBG("camera open -- setting ops to NULL\n");
3277 		cam->ops = NULL;
3278 	}
3279 
3280 #ifdef CONFIG_PROC_FS
3281 	DBG("destroying /proc/cpia/video%d\n", cam->vdev.minor);
3282 	destroy_proc_cpia_cam(cam);
3283 #endif
3284 	if (!cam->open_count) {
3285 		DBG("freeing camera\n");
3286 		kfree(cam);
3287 	}
3288 }
3289 
cpia_init(void)3290 static int __init cpia_init(void)
3291 {
3292 	printk(KERN_INFO "%s v%d.%d.%d\n", ABOUT,
3293 	       CPIA_MAJ_VER, CPIA_MIN_VER, CPIA_PATCH_VER);
3294 #ifdef CONFIG_PROC_FS
3295 	proc_cpia_create();
3296 #endif
3297 
3298 #ifdef CONFIG_KMOD
3299 #ifdef CONFIG_VIDEO_CPIA_PP_MODULE
3300 	request_module("cpia_pp");
3301 #endif
3302 
3303 #ifdef CONFIG_VIDEO_CPIA_USB_MODULE
3304 	request_module("cpia_usb");
3305 #endif
3306 #endif	/* CONFIG_KMOD */
3307 
3308 #ifdef CONFIG_VIDEO_CPIA_PP
3309 	cpia_pp_init();
3310 #endif
3311 #ifdef CONFIG_VIDEO_CPIA_USB
3312 	cpia_usb_init();
3313 #endif
3314 	return 0;
3315 }
3316 
cpia_exit(void)3317 static void __exit cpia_exit(void)
3318 {
3319 #ifdef CONFIG_PROC_FS
3320 	proc_cpia_destroy();
3321 #endif
3322 }
3323 
3324 module_init(cpia_init);
3325 module_exit(cpia_exit);
3326 
3327 /* Exported symbols for modules. */
3328 
3329 EXPORT_SYMBOL(cpia_register_camera);
3330 EXPORT_SYMBOL(cpia_unregister_camera);
3331