File: /usr/src/linux/drivers/media/video/cpia.c

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