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