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

1     /*
2     	Winbond w9966cf Webcam parport driver.
3     
4     	Version 0.32
5     
6     	Copyright (C) 2001 Jakob Kemi <jakob.kemi@post.utfors.se>
7     
8     	This program is free software; you can redistribute it and/or modify
9     	it under the terms of the GNU General Public License as published by
10     	the Free Software Foundation; either version 2 of the License, or
11     	(at your option) any later version.
12     
13     	This program is distributed in the hope that it will be useful,
14     	but WITHOUT ANY WARRANTY; without even the implied warranty of
15     	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16     	GNU General Public License for more details.
17     
18     	You should have received a copy of the GNU General Public License
19     	along with this program; if not, write to the Free Software
20     	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21     */
22     /*
23     	Supported devices:
24     	*Lifeview FlyCam Supra (using the Philips saa7111a chip)
25     
26     	Does any other model using the w9966 interface chip exist ?
27     
28     	Todo:
29     	
30     	*Add a working EPP mode, since DMA ECP read isn't implemented
31     	in the parport drivers. (That's why it's so sloow)
32     
33     	*Add support for other ccd-control chips than the saa7111
34     	please send me feedback on what kind of chips you have.
35     
36     	*Add proper probing. I don't know what's wrong with the IEEE1284
37     	parport drivers but (IEEE1284_MODE_NIBBLE|IEEE1284_DEVICE_ID)
38     	and nibble read seems to be broken for some peripherals.
39     
40     	*Add probing for onboard SRAM, port directions etc. (if possible)
41     
42     	*Add support for the hardware compressed modes (maybe using v4l2)
43     
44     	*Fix better support for the capture window (no skewed images, v4l
45     	interface to capt. window)
46     
47     	*Probably some bugs that I don't know of
48     
49     	Please support me by sending feedback!
50     	
51     	Changes:
52     	
53     	Alan Cox:	Removed RGB mode for kernel merge, added THIS_MODULE
54     			and owner support for newer module locks
55     */
56     
57     #include <linux/module.h>
58     #include <linux/init.h>
59     #include <linux/delay.h>
60     #include <linux/videodev.h>
61     #include <linux/parport.h>
62     
63     //#define DEBUG				// Undef me for production
64     
65     #ifdef DEBUG
66     #define DPRINTF(x, a...) printk(KERN_DEBUG "W9966: "__FUNCTION__ "(): "x, ##a)
67     #else
68     #define DPRINTF(x...)
69     #endif
70     
71     /*
72      *	Defines, simple typedefs etc.
73      */
74     
75     #define W9966_DRIVERNAME	"W9966CF Webcam"
76     #define W9966_MAXCAMS		4	// Maximum number of cameras
77     #define W9966_RBUFFER		2048	// Read buffer (must be an even number)
78     #define W9966_SRAMSIZE		131072	// 128kb
79     #define W9966_SRAMID		0x02	// check w9966cf.pdf
80     
81     // Empirically determined window limits
82     #define W9966_WND_MIN_X		16
83     #define W9966_WND_MIN_Y		14
84     #define W9966_WND_MAX_X		705
85     #define W9966_WND_MAX_Y		253
86     #define W9966_WND_MAX_W		(W9966_WND_MAX_X - W9966_WND_MIN_X)
87     #define W9966_WND_MAX_H		(W9966_WND_MAX_Y - W9966_WND_MIN_Y)
88     
89     // Keep track of our current state
90     #define W9966_STATE_PDEV	0x01
91     #define W9966_STATE_CLAIMED	0x02
92     #define W9966_STATE_VDEV	0x04
93     
94     #define W9966_I2C_W_ID		0x48
95     #define W9966_I2C_R_ID		0x49
96     #define W9966_I2C_R_DATA	0x08
97     #define W9966_I2C_R_CLOCK	0x04
98     #define W9966_I2C_W_DATA	0x02
99     #define W9966_I2C_W_CLOCK	0x01
100     
101     struct w9966_dev {
102     	unsigned char dev_state;
103     	unsigned char i2c_state;
104     	unsigned short ppmode;
105     	struct parport* pport;
106     	struct pardevice* pdev;
107     	struct video_device vdev;
108     	unsigned short width;
109     	unsigned short height;
110     	unsigned char brightness;
111     	signed char contrast;
112     	signed char color;
113     	signed char hue;
114     };
115     
116     /*
117      *	Module specific properties
118      */
119     
120     MODULE_AUTHOR("Jakob Kemi <jakob.kemi@post.utfors.se>");
121     MODULE_DESCRIPTION("Winbond w9966cf WebCam driver (0.32)");
122     
123     #ifdef MODULE
124     static const char* pardev[] = {[0 ... W9966_MAXCAMS] = ""};
125     #else
126     static const char* pardev[] = {[0 ... W9966_MAXCAMS] = "aggressive"};
127     #endif
128     MODULE_PARM(pardev, "1-" __MODULE_STRING(W9966_MAXCAMS) "s");
129     MODULE_PARM_DESC(pardev, "pardev: where to search for\n\
130     \teach camera. 'aggressive' means brute-force search.\n\
131     \tEg: >pardev=parport3,aggressive,parport2,parport1< would assign
132     \tcam 1 to parport3 and search every parport for cam 2 etc...");
133     
134     static int parmode = 0;
135     MODULE_PARM(parmode, "i");
136     MODULE_PARM_DESC(parmode, "parmode: transfer mode (0=auto, 1=ecp, 2=epp");
137     
138     static int video_nr = -1;
139     MODULE_PARM(video_nr, "i");
140     
141     /*
142      *	Private data
143      */
144     
145     static struct w9966_dev w9966_cams[W9966_MAXCAMS];
146     
147     /*
148      *	Private function declares
149      */
150     
151     static inline void w9966_setState(struct w9966_dev* cam, int mask, int val);
152     static inline int  w9966_getState(struct w9966_dev* cam, int mask, int val);
153     static inline void w9966_pdev_claim(struct w9966_dev *vdev);
154     static inline void w9966_pdev_release(struct w9966_dev *vdev);
155     
156     static int w9966_rReg(struct w9966_dev* cam, int reg);
157     static int w9966_wReg(struct w9966_dev* cam, int reg, int data);
158     static int w9966_rReg_i2c(struct w9966_dev* cam, int reg);
159     static int w9966_wReg_i2c(struct w9966_dev* cam, int reg, int data);
160     static int w9966_findlen(int near, int size, int maxlen);
161     static int w9966_calcscale(int size, int min, int max, int* beg, int* end, unsigned char* factor);
162     static int w9966_setup(struct w9966_dev* cam, int x1, int y1, int x2, int y2, int w, int h);
163     
164     static int  w9966_init(struct w9966_dev* cam, struct parport* port);
165     static void w9966_term(struct w9966_dev* cam);
166     
167     static inline void w9966_i2c_setsda(struct w9966_dev* cam, int state);
168     static inline int  w9966_i2c_setscl(struct w9966_dev* cam, int state);
169     static inline int  w9966_i2c_getsda(struct w9966_dev* cam);
170     static inline int  w9966_i2c_getscl(struct w9966_dev* cam);
171     static int w9966_i2c_wbyte(struct w9966_dev* cam, int data);
172     static int w9966_i2c_rbyte(struct w9966_dev* cam);
173     
174     static int  w9966_v4l_open(struct video_device *vdev, int mode);
175     static void w9966_v4l_close(struct video_device *vdev);
176     static int  w9966_v4l_ioctl(struct video_device *vdev, unsigned int cmd, void *arg);
177     static long w9966_v4l_read(struct video_device *vdev, char *buf, unsigned long count, int noblock);
178     
179     /*
180      *	Private function defines
181      */
182     
183     
184     // Set camera phase flags, so we know what to uninit when terminating 
185     static inline void w9966_setState(struct w9966_dev* cam, int mask, int val)
186     {
187     	cam->dev_state = (cam->dev_state & ~mask) ^ val;
188     }
189     
190     // Get camera phase flags
191     static inline int w9966_getState(struct w9966_dev* cam, int mask, int val)
192     {
193     	return ((cam->dev_state & mask) == val);
194     }
195     
196     // Claim parport for ourself
197     static inline void w9966_pdev_claim(struct w9966_dev* cam)
198     {
199     	if (w9966_getState(cam, W9966_STATE_CLAIMED, W9966_STATE_CLAIMED))
200     		return;
201     	parport_claim_or_block(cam->pdev);
202     	w9966_setState(cam, W9966_STATE_CLAIMED, W9966_STATE_CLAIMED);
203     }
204     
205     // Release parport for others to use
206     static inline void w9966_pdev_release(struct w9966_dev* cam)
207     {
208     	if (w9966_getState(cam, W9966_STATE_CLAIMED, 0))
209     		return;
210     	parport_release(cam->pdev);
211     	w9966_setState(cam, W9966_STATE_CLAIMED, 0);
212     }
213      
214     // Read register from W9966 interface-chip
215     // Expects a claimed pdev
216     // -1 on error, else register data (byte)
217     static int w9966_rReg(struct w9966_dev* cam, int reg)
218     {
219     	// ECP, read, regtransfer, REG, REG, REG, REG, REG
220     	const unsigned char addr = 0x80 | (reg & 0x1f);
221     	unsigned char val;
222     	
223     	if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_ADDR) != 0)
224     		return -1;
225     	if (parport_write(cam->pport, &addr, 1) != 1)
226     		return -1;
227     	if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_DATA) != 0)
228     		return -1;
229     	if (parport_read(cam->pport, &val, 1) != 1)
230     		return -1;
231     
232     	return val;
233     }
234     
235     // Write register to W9966 interface-chip
236     // Expects a claimed pdev
237     // -1 on error
238     static int w9966_wReg(struct w9966_dev* cam, int reg, int data)
239     {
240     	// ECP, write, regtransfer, REG, REG, REG, REG, REG
241     	const unsigned char addr = 0xc0 | (reg & 0x1f);
242     	const unsigned char val = data;
243     	
244     	if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_ADDR) != 0)
245     		return -1;
246     	if (parport_write(cam->pport, &addr, 1) != 1)
247     		return -1;
248     	if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_DATA) != 0)
249     		return -1;
250     	if (parport_write(cam->pport, &val, 1) != 1)
251     		return -1;
252     
253     	return 0;
254     }
255     
256     // Initialize camera device. Setup all internal flags, set a
257     // default video mode, setup ccd-chip, register v4l device etc..
258     // Also used for 'probing' of hardware.
259     // -1 on error
260     static int w9966_init(struct w9966_dev* cam, struct parport* port)
261     {
262     	if (cam->dev_state != 0)
263     		return -1;
264     	
265     	cam->pport = port;
266     	cam->brightness = 128;
267     	cam->contrast = 64;
268     	cam->color = 64;
269     	cam->hue = 0;
270     
271     // Select requested transfer mode
272     	switch(parmode)
273     	{
274     	default:	// Auto-detect (priority: hw-ecp, hw-epp, sw-ecp)
275     	case 0:
276     		if (port->modes & PARPORT_MODE_ECP)
277     			cam->ppmode = IEEE1284_MODE_ECP;
278     		else if (port->modes & PARPORT_MODE_EPP)
279     			cam->ppmode = IEEE1284_MODE_EPP;
280     		else
281     			cam->ppmode = IEEE1284_MODE_ECP;
282     		break;	
283     	case 1:		// hw- or sw-ecp
284     		cam->ppmode = IEEE1284_MODE_ECP;
285     		break;
286     	case 2:		// hw- or sw-epp
287     		cam->ppmode = IEEE1284_MODE_EPP;
288     	break;
289     	}
290     	
291     // Tell the parport driver that we exists
292     	cam->pdev = parport_register_device(port, "w9966", NULL, NULL, NULL, 0, NULL);
293     	if (cam->pdev == NULL) {
294     		DPRINTF("parport_register_device() failed\n");
295     		return -1;
296     	}
297     	w9966_setState(cam, W9966_STATE_PDEV, W9966_STATE_PDEV);
298     
299     	w9966_pdev_claim(cam);
300     	
301     // Setup a default capture mode
302     	if (w9966_setup(cam, 0, 0, 1023, 1023, 200, 160) != 0) {
303     		DPRINTF("w9966_setup() failed.\n");
304     		return -1;
305     	}
306     
307     	w9966_pdev_release(cam);
308     
309     // Fill in the video_device struct and register us to v4l
310     	memset(&cam->vdev, 0, sizeof(struct video_device));
311     	strcpy(cam->vdev.name, W9966_DRIVERNAME);
312     	cam->vdev.type = VID_TYPE_CAPTURE | VID_TYPE_SCALES;
313     	cam->vdev.hardware = VID_HARDWARE_W9966;
314     	cam->vdev.open = &w9966_v4l_open;
315     	cam->vdev.close = &w9966_v4l_close;
316     	cam->vdev.read = &w9966_v4l_read;
317     	cam->vdev.ioctl = &w9966_v4l_ioctl;
318     	cam->vdev.priv = (void*)cam;
319     	cam->vdev.owner = THIS_MODULE;
320     
321     	if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, video_nr) == -1)		 
322     		return -1;
323     	
324     	w9966_setState(cam, W9966_STATE_VDEV, W9966_STATE_VDEV);
325     	
326     	// All ok
327     	printk(
328     		"w9966cf: Found and initialized a webcam on %s.\n",
329     		cam->pport->name
330     	);
331     	return 0;
332     }
333     
334     
335     // Terminate everything gracefully
336     static void w9966_term(struct w9966_dev* cam)
337     {
338     // Unregister from v4l
339     	if (w9966_getState(cam, W9966_STATE_VDEV, W9966_STATE_VDEV)) {
340     		video_unregister_device(&cam->vdev);
341     		w9966_setState(cam, W9966_STATE_VDEV, 0);
342     	}
343     
344     // Terminate from IEEE1284 mode and release pdev block
345     	if (w9966_getState(cam, W9966_STATE_PDEV, W9966_STATE_PDEV)) {
346     		w9966_pdev_claim(cam);
347     		parport_negotiate(cam->pport, IEEE1284_MODE_COMPAT);
348     		w9966_pdev_release(cam);
349     	}
350     
351     // Unregister from parport
352     	if (w9966_getState(cam, W9966_STATE_PDEV, W9966_STATE_PDEV)) {
353     		parport_unregister_device(cam->pdev);
354     		w9966_setState(cam, W9966_STATE_PDEV, 0);
355     	}
356     }
357     
358     
359     // Find a good length for capture window (used both for W and H)
360     // A bit ugly but pretty functional. The capture length
361     // have to match the downscale
362     static int w9966_findlen(int near, int size, int maxlen)
363     {
364     	int bestlen = size;
365     	int besterr = abs(near - bestlen);
366     	int len;
367     
368     	for(len = size+1;len < maxlen;len++)
369     	{
370     		int err;
371     		if ( ((64*size) %len) != 0)
372     			continue;
373     
374     		err = abs(near - len);
375     
376     		// Only continue as long as we keep getting better values
377     		if (err > besterr)
378     			break;
379     		
380     		besterr = err;
381     		bestlen = len;
382     	}
383     
384     	return bestlen;
385     }
386     
387     // Modify capture window (if necessary) 
388     // and calculate downscaling
389     // Return -1 on error
390     static int w9966_calcscale(int size, int min, int max, int* beg, int* end, unsigned char* factor)
391     {
392     	int maxlen = max - min;
393     	int len = *end - *beg + 1;
394     	int newlen = w9966_findlen(len, size, maxlen);
395     	int err = newlen - len; 
396     
397     	// Check for bad format
398     	if (newlen > maxlen || newlen < size)
399     		return -1;
400     
401     	// Set factor (6 bit fixed)
402     	*factor = (64*size) / newlen;
403     	if (*factor == 64)
404     		*factor = 0x00;	// downscale is disabled
405     	else
406     		*factor |= 0x80; // set downscale-enable bit
407     
408     	// Modify old beginning and end
409     	*beg -= err / 2;
410     	*end += err - (err / 2);
411     
412     	// Move window if outside borders
413     	if (*beg < min) {
414     		*end += min - *beg;
415     		*beg += min - *beg;
416     	}
417     	if (*end > max) {
418     		*beg -= *end - max;
419     		*end -= *end - max;
420     	}
421     
422     	return 0;
423     }
424     
425     // Setup the cameras capture window etc.
426     // Expects a claimed pdev
427     // return -1 on error
428     static int w9966_setup(struct w9966_dev* cam, int x1, int y1, int x2, int y2, int w, int h)
429     {
430     	unsigned int i;
431     	unsigned int enh_s, enh_e;
432     	unsigned char scale_x, scale_y;
433     	unsigned char regs[0x1c];
434     	unsigned char saa7111_regs[] = {
435     		0x21, 0x00, 0xd8, 0x23, 0x00, 0x80, 0x80, 0x00,
436     		0x88, 0x10, 0x80, 0x40, 0x40, 0x00, 0x01, 0x00,
437     		0x48, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
438     		0x00, 0x00, 0x00, 0x71, 0xe7, 0x00, 0x00, 0xc0
439     	};
440     	
441     	
442     	if (w*h*2 > W9966_SRAMSIZE)
443     	{
444     		DPRINTF("capture window exceeds SRAM size!.\n");
445     		w = 200; h = 160;	// Pick default values
446     	}
447     
448     	w &= ~0x1;
449     	if (w < 2) w = 2;
450     	if (h < 1) h = 1;
451     	if (w > W9966_WND_MAX_W) w = W9966_WND_MAX_W;
452     	if (h > W9966_WND_MAX_H) h = W9966_WND_MAX_H;
453     
454     	cam->width = w;
455     	cam->height = h;
456     
457     	enh_s = 0;	
458     	enh_e = w*h*2;
459     	
460     // Modify capture window if necessary and calculate downscaling
461     	if (
462     		w9966_calcscale(w, W9966_WND_MIN_X, W9966_WND_MAX_X, &x1, &x2, &scale_x) != 0 ||
463     		w9966_calcscale(h, W9966_WND_MIN_Y, W9966_WND_MAX_Y, &y1, &y2, &scale_y) != 0
464     	) return -1;
465     
466     	DPRINTF(
467     		"%dx%d, x: %d<->%d, y: %d<->%d, sx: %d/64, sy: %d/64.\n",
468     		w, h, x1, x2, y1, y2, scale_x&~0x80, scale_y&~0x80
469     	);
470     	
471     // Setup registers
472     	regs[0x00] = 0x00;			// Set normal operation
473     	regs[0x01] = 0x18;			// Capture mode
474     	regs[0x02] = scale_y;			// V-scaling
475     	regs[0x03] = scale_x;			// H-scaling
476     	
477     	// Capture window	
478     	regs[0x04] = (x1 & 0x0ff);		// X-start (8 low bits)
479     	regs[0x05] = (x1 & 0x300)>>8;		// X-start (2 high bits)
480     	regs[0x06] = (y1 & 0x0ff);		// Y-start (8 low bits)
481     	regs[0x07] = (y1 & 0x300)>>8;		// Y-start (2 high bits)
482     	regs[0x08] = (x2 & 0x0ff);		// X-end (8 low bits)
483     	regs[0x09] = (x2 & 0x300)>>8;		// X-end (2 high bits)
484     	regs[0x0a] = (y2 & 0x0ff);		// Y-end (8 low bits)
485     
486     	regs[0x0c] = W9966_SRAMID;		// SRAM-banks (1x 128kb)
487     	
488     	// Enhancement layer
489     	regs[0x0d] = (enh_s& 0x000ff);		// Enh. start (0-7)
490     	regs[0x0e] = (enh_s& 0x0ff00)>>8;	// Enh. start (8-15)
491     	regs[0x0f] = (enh_s& 0x70000)>>16;	// Enh. start (16-17/18??)
492     	regs[0x10] = (enh_e& 0x000ff);		// Enh. end (0-7)
493     	regs[0x11] = (enh_e& 0x0ff00)>>8;	// Enh. end (8-15)
494     	regs[0x12] = (enh_e& 0x70000)>>16;	// Enh. end (16-17/18??)
495     
496     	// Misc
497     	regs[0x13] = 0x40;			// VEE control (raw 4:2:2)
498     	regs[0x17] = 0x00;			// ???
499     	regs[0x18] = cam->i2c_state = 0x00;	// Serial bus
500     	regs[0x19] = 0xff;			// I/O port direction control
501     	regs[0x1a] = 0xff;			// I/O port data register
502     	regs[0x1b] = 0x10;			// ???
503     	
504     	// SAA7111 chip settings
505     	saa7111_regs[0x0a] = cam->brightness;
506     	saa7111_regs[0x0b] = cam->contrast;
507     	saa7111_regs[0x0c] = cam->color;
508     	saa7111_regs[0x0d] = cam->hue;
509     
510     // Reset (ECP-fifo & serial-bus)
511     	if (w9966_wReg(cam, 0x00, 0x03) == -1)
512     		return -1;
513     
514     // Write regs to w9966cf chip
515     	for (i = 0; i < 0x1c; i++)
516     		if (w9966_wReg(cam, i, regs[i]) == -1)
517     			return -1;
518     
519     // Write regs to saa7111 chip
520     	for (i = 0; i < 0x20; i++)
521     		if (w9966_wReg_i2c(cam, i, saa7111_regs[i]) == -1)
522     			return -1;
523     
524     	return 0;
525     }
526     
527     /*
528      *	Ugly and primitive i2c protocol functions
529      */
530     
531     // Sets the data line on the i2c bus.
532     // Expects a claimed pdev.
533     static inline void w9966_i2c_setsda(struct w9966_dev* cam, int state)
534     {
535     	if (state)
536     		cam->i2c_state |= W9966_I2C_W_DATA;
537     	else
538     		cam->i2c_state &= ~W9966_I2C_W_DATA;
539     	
540     	w9966_wReg(cam, 0x18, cam->i2c_state);
541     	udelay(5);
542     }
543     
544     // Sets the clock line on the i2c bus.
545     // Expects a claimed pdev. -1 on error
546     static inline int w9966_i2c_setscl(struct w9966_dev* cam, int state)
547     {
548     	int timeout;
549     	if (state)
550     		cam->i2c_state |= W9966_I2C_W_CLOCK;
551     	else
552     		cam->i2c_state &= ~W9966_I2C_W_CLOCK;
553     
554     	w9966_wReg(cam, 0x18, cam->i2c_state);
555     	udelay(5);
556     	
557     	// we go to high, we also expect the peripheral to ack.
558     	if (state) {
559     		timeout = jiffies + 100;
560     		while (!w9966_i2c_getscl(cam)) {
561     			if (jiffies > timeout)
562     				return -1;
563     		}
564     	}
565     	return 0;
566     }
567     
568     // Get peripheral data line
569     // Expects a claimed pdev.
570     static inline int w9966_i2c_getsda(struct w9966_dev* cam)
571     {
572     	const unsigned char state = w9966_rReg(cam, 0x18);
573     	return ((state & W9966_I2C_R_DATA) > 0);
574     }
575     
576     // Get peripheral clock line
577     // Expects a claimed pdev.
578     static inline int w9966_i2c_getscl(struct w9966_dev* cam)
579     {
580     	const unsigned char state = w9966_rReg(cam, 0x18);
581     	return ((state & W9966_I2C_R_CLOCK) > 0);
582     }
583     
584     // Write a byte with ack to the i2c bus.
585     // Expects a claimed pdev. -1 on error
586     static int w9966_i2c_wbyte(struct w9966_dev* cam, int data)
587     {
588     	int i;
589     	for (i = 7; i >= 0; i--)
590     	{
591     		w9966_i2c_setsda(cam, (data >> i) & 0x01);
592     
593     		if (w9966_i2c_setscl(cam, 1) == -1)
594     			return -1;			
595     		w9966_i2c_setscl(cam, 0);
596     	}
597     
598     	w9966_i2c_setsda(cam, 1);
599     	
600     	if (w9966_i2c_setscl(cam, 1) == -1)
601     		return -1;
602     	w9966_i2c_setscl(cam, 0);
603     	
604     	return 0;
605     }
606     
607     // Read a data byte with ack from the i2c-bus
608     // Expects a claimed pdev. -1 on error
609     static int w9966_i2c_rbyte(struct w9966_dev* cam)
610     {
611     	unsigned char data = 0x00;
612     	int i;	
613     	
614     	w9966_i2c_setsda(cam, 1);
615     
616     	for (i = 0; i < 8; i++)
617     	{
618     		if (w9966_i2c_setscl(cam, 1) == -1)
619     			return -1;
620     		data = data << 1;
621     		if (w9966_i2c_getsda(cam))
622     			data |= 0x01;
623     		
624     		w9966_i2c_setscl(cam, 0);
625     	}
626     	return data;
627     }
628     
629     // Read a register from the i2c device.
630     // Expects claimed pdev. -1 on error
631     static int w9966_rReg_i2c(struct w9966_dev* cam, int reg)
632     {
633     	int data;
634     
635     	w9966_i2c_setsda(cam, 0);
636     	w9966_i2c_setscl(cam, 0);
637     
638     	if (
639     		w9966_i2c_wbyte(cam, W9966_I2C_W_ID) == -1 ||
640     		w9966_i2c_wbyte(cam, reg) == -1
641     	)
642     		return -1;
643     
644     	w9966_i2c_setsda(cam, 1);
645     	if (w9966_i2c_setscl(cam, 1) == -1)
646     		return -1;
647     	w9966_i2c_setsda(cam, 0);
648     	w9966_i2c_setscl(cam, 0);
649     
650     	if (
651     		w9966_i2c_wbyte(cam, W9966_I2C_R_ID) == -1 ||
652     		(data = w9966_i2c_rbyte(cam)) == -1
653     	)
654     		return -1;
655     
656     	w9966_i2c_setsda(cam, 0);
657     	
658     	if (w9966_i2c_setscl(cam, 1) == -1)
659     		return -1;
660     	w9966_i2c_setsda(cam, 1);
661     	
662     	return data;
663     }
664     
665     // Write a register to the i2c device.
666     // Expects claimed pdev. -1 on error
667     static int w9966_wReg_i2c(struct w9966_dev* cam, int reg, int data)
668     {
669     	w9966_i2c_setsda(cam, 0);
670     	w9966_i2c_setscl(cam, 0);
671     
672     	if (
673     		w9966_i2c_wbyte(cam, W9966_I2C_W_ID) == -1 ||
674     		w9966_i2c_wbyte(cam, reg) == -1 ||
675     		w9966_i2c_wbyte(cam, data) == -1
676     	)
677     		return -1;
678     
679     	w9966_i2c_setsda(cam, 0);
680     	if (w9966_i2c_setscl(cam, 1) == -1)
681     		return -1;
682     		
683     	w9966_i2c_setsda(cam, 1);
684     
685     	return 0;
686     }
687     
688     /*
689      *	Video4linux interfacing
690      */
691     
692     static int w9966_v4l_open(struct video_device *vdev, int flags)
693     {
694     	return 0;
695     }
696     
697     static void w9966_v4l_close(struct video_device *vdev)
698     {
699     }
700     
701     static int w9966_v4l_ioctl(struct video_device *vdev, unsigned int cmd, void *arg)
702     {
703     	struct w9966_dev *cam = (struct w9966_dev*)vdev->priv;
704     	
705     	switch(cmd)
706     	{
707     	case VIDIOCGCAP:
708     	{
709     		struct video_capability vcap = {
710     			W9966_DRIVERNAME,	// name
711     			VID_TYPE_CAPTURE | VID_TYPE_SCALES,	// type
712     			1, 0,			// vid, aud channels
713     			W9966_WND_MAX_W,	// max w
714     			W9966_WND_MAX_H,	// max h
715     			2, 1			// min w, min h
716     		};
717     
718     		if(copy_to_user(arg, &vcap, sizeof(vcap)) != 0)
719     			return -EFAULT;
720     
721     		return 0;
722     	}
723     	case VIDIOCGCHAN:
724     	{
725     		struct video_channel vch;
726     		if(copy_from_user(&vch, arg, sizeof(vch)) != 0)
727     			return -EFAULT;
728     
729     		if(vch.channel != 0)	// We only support one channel (#0)
730     			return -EINVAL;
731     
732     		strcpy(vch.name, "CCD-input");
733     		vch.flags = 0;		// We have no tuner or audio
734     		vch.tuners = 0;
735     		vch.type = VIDEO_TYPE_CAMERA;
736     		vch.norm = 0;		// ???
737     		
738     		if(copy_to_user(arg, &vch, sizeof(vch)) != 0)
739     			return -EFAULT;
740     		
741     		return 0;
742     	}
743     	case VIDIOCSCHAN:
744     	{
745     		struct video_channel vch;
746     		if(copy_from_user(&vch, arg, sizeof(vch) ) != 0)
747     			return -EFAULT;
748     		
749     		if(vch.channel != 0)
750     			return -EINVAL;
751     		
752     		return 0;
753     	}
754     	case VIDIOCGTUNER:
755     	{
756     		struct video_tuner vtune;
757     		if(copy_from_user(&vtune, arg, sizeof(vtune)) != 0)
758     			return -EFAULT;
759     		
760     		if(vtune.tuner != 0);
761     			return -EINVAL;
762     		
763     		strcpy(vtune.name, "no tuner");
764     		vtune.rangelow = 0;
765     		vtune.rangehigh = 0;
766     		vtune.flags = VIDEO_TUNER_NORM;
767     		vtune.mode = VIDEO_MODE_AUTO;
768     		vtune.signal = 0xffff;
769     		
770     		if(copy_to_user(arg, &vtune, sizeof(vtune)) != 0)
771     			return -EFAULT;
772     		
773     		return 0;
774     	}
775     	case VIDIOCSTUNER:
776     	{
777     		struct video_tuner vtune;
778     		if (copy_from_user(&vtune, arg, sizeof(vtune)) != 0)
779     			return -EFAULT;
780     		
781     		if (vtune.tuner != 0)
782     			return -EINVAL;
783     		
784     		if (vtune.mode != VIDEO_MODE_AUTO)
785     			return -EINVAL;
786     		
787     		return 0;
788     	}
789     	case VIDIOCGPICT:
790     	{
791     		struct video_picture vpic = {
792     			cam->brightness << 8,	// brightness
793     			(cam->hue + 128) << 8,	// hue
794     			cam->color << 9,	// color
795     			cam->contrast << 9,	// contrast
796     			0x8000,			// whiteness
797     			16, VIDEO_PALETTE_YUV422// bpp, palette format
798     		};
799     
800     		if(copy_to_user(arg, &vpic, sizeof(vpic)) != 0)
801     			return -EFAULT;
802     
803     		return 0;
804     	}
805     	case VIDIOCSPICT:
806     	{
807     		struct video_picture vpic;
808     		if(copy_from_user(&vpic, arg, sizeof(vpic)) != 0)
809     			return -EFAULT;
810     		
811     		if (vpic.depth != 16 || vpic.palette != VIDEO_PALETTE_YUV422)
812     			return -EINVAL;
813     			
814     		cam->brightness = vpic.brightness >> 8;
815     		cam->hue = (vpic.hue >> 8) - 128;
816     		cam->color = vpic.colour >> 9;
817     		cam->contrast = vpic.contrast >> 9;
818     
819     		w9966_pdev_claim(cam);
820     		
821     		if (
822     			w9966_wReg_i2c(cam, 0x0a, cam->brightness) == -1 ||
823     			w9966_wReg_i2c(cam, 0x0b, cam->contrast) == -1 ||
824     			w9966_wReg_i2c(cam, 0x0c, cam->color) == -1 ||
825     			w9966_wReg_i2c(cam, 0x0d, cam->hue) == -1
826     		) {
827     			w9966_pdev_release(cam);
828     			return -EFAULT;
829     		}
830     		
831     		w9966_pdev_release(cam);
832     		return 0;
833     	}
834     	case VIDIOCSWIN:
835     	{
836     		int ret;
837     		struct video_window vwin;
838     		
839     		if (copy_from_user(&vwin, arg, sizeof(vwin)) != 0)
840     			return -EFAULT;		
841     		if (vwin.flags != 0)
842     			return -EINVAL;
843     		if (vwin.clipcount != 0)
844     			return -EINVAL;
845     		if (vwin.width < 2 || vwin.width > W9966_WND_MAX_W)
846     			return -EINVAL;		
847     		if (vwin.height < 1 || vwin.height > W9966_WND_MAX_H)
848     			return -EINVAL;
849     
850     		// Update camera regs
851     		w9966_pdev_claim(cam);
852     		ret = w9966_setup(cam, 0, 0, 1023, 1023, vwin.width, vwin.height);
853     		w9966_pdev_release(cam);
854     		
855     		if (ret != 0) {
856     			DPRINTF("VIDIOCSWIN: w9966_setup() failed.\n");
857     			return -EFAULT;
858     		}
859     		
860     		return 0;
861     	}
862     	case VIDIOCGWIN:
863     	{
864     		struct video_window vwin;
865     		memset(&vwin, 0, sizeof(vwin));
866     		
867     		vwin.width = cam->width;
868     		vwin.height = cam->height;
869     		
870     		if(copy_to_user(arg, &vwin, sizeof(vwin)) != 0)
871     			return -EFAULT;
872     		
873     		return 0;
874     	}
875     	// Unimplemented
876     	case VIDIOCCAPTURE:	
877     	case VIDIOCGFBUF:
878     	case VIDIOCSFBUF:
879     	case VIDIOCKEY:
880     	case VIDIOCGFREQ:
881     	case VIDIOCSFREQ:
882     	case VIDIOCGAUDIO:
883     	case VIDIOCSAUDIO:
884     		return -EINVAL;
885     	default:
886     		return -ENOIOCTLCMD;
887     	}
888     	return 0;
889     }
890     
891     // Capture data
892     static long w9966_v4l_read(struct video_device *vdev, char *buf, unsigned long count,  int noblock)
893     {
894     	struct w9966_dev *cam = (struct w9966_dev *)vdev->priv;
895     	unsigned char addr = 0xa0;	// ECP, read, CCD-transfer, 00000
896     	unsigned char* dest = (unsigned char*)buf;
897     	unsigned long dleft = count;
898     	
899     	// Why would anyone want more than this??
900     	if (count > cam->width * cam->height * 2)
901     		return -EINVAL;
902     	
903     	w9966_pdev_claim(cam);
904     	w9966_wReg(cam, 0x00, 0x02);	// Reset ECP-FIFO buffer
905     	w9966_wReg(cam, 0x00, 0x00);	// Return to normal operation
906     	w9966_wReg(cam, 0x01, 0x98);	// Enable capture
907     
908     	// write special capture-addr and negotiate into data transfer	
909     	if (
910     		(parport_negotiate(cam->pport, cam->ppmode|IEEE1284_ADDR) != 0	)||
911     		(parport_write(cam->pport, &addr, 1) != 1						)||
912     		(parport_negotiate(cam->pport, cam->ppmode|IEEE1284_DATA) != 0	)
913     	) {
914     		w9966_pdev_release(cam);
915     		return -EFAULT;
916     	}
917     	
918     	while(dleft > 0)
919     	{
920     		unsigned long tsize = (dleft > W9966_RBUFFER) ? W9966_RBUFFER : dleft;
921     		unsigned char tbuf[W9966_RBUFFER];
922     	
923     		if (parport_read(cam->pport, tbuf, tsize) < tsize) {
924     			w9966_pdev_release(cam);
925     			return -EFAULT;
926     		}
927     		if (copy_to_user(dest, tbuf, tsize) != 0) {
928     			w9966_pdev_release(cam);
929     			return -EFAULT;
930     		}
931     		dest += tsize;
932     		dleft -= tsize;
933     	}
934     	
935     	w9966_wReg(cam, 0x01, 0x18);	// Disable capture
936     	w9966_pdev_release(cam);
937     
938     	return count;
939     }
940     
941     
942     // Called once for every parport on init
943     static void w9966_attach(struct parport *port)
944     {
945     	int i;
946     	
947     	for (i = 0; i < W9966_MAXCAMS; i++)
948     	{
949     		if (w9966_cams[i].dev_state != 0)	// Cam is already assigned
950     			continue;
951     		if (
952     			strcmp(pardev[i], "aggressive") == 0 ||
953     			strcmp(pardev[i], port->name) == 0
954     		) {
955     			if (w9966_init(&w9966_cams[i], port) != 0)
956     			w9966_term(&w9966_cams[i]);
957     			break;	// return
958     		}
959     	}
960     }
961     
962     // Called once for every parport on termination
963     static void w9966_detach(struct parport *port)
964     {
965     	int i;
966     	for (i = 0; i < W9966_MAXCAMS; i++)
967     	if (w9966_cams[i].dev_state != 0 && w9966_cams[i].pport == port)
968     		w9966_term(&w9966_cams[i]);
969     }
970     
971     
972     static struct parport_driver w9966_ppd = {
973     	W9966_DRIVERNAME,
974     	w9966_attach,
975     	w9966_detach,
976     	NULL
977     };
978     
979     // Module entry point
980     static int __init w9966_mod_init(void)
981     {
982     	int i;
983     	for (i = 0; i < W9966_MAXCAMS; i++)
984     		w9966_cams[i].dev_state = 0;
985     
986     	return parport_register_driver(&w9966_ppd);
987     }
988     
989     // Module cleanup
990     static void __exit w9966_mod_term(void)
991     {
992     	parport_unregister_driver(&w9966_ppd);
993     }
994     
995     module_init(w9966_mod_init);
996     module_exit(w9966_mod_term);
997