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