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