• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/drivers/media/video/
1/*
2	Winbond w9966cf Webcam parport driver.
3
4	Version 0.33
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/version.h>
61#include <linux/videodev2.h>
62#include <linux/slab.h>
63#include <media/v4l2-common.h>
64#include <media/v4l2-ioctl.h>
65#include <media/v4l2-device.h>
66#include <linux/parport.h>
67
68/*#define DEBUG*/				/* Undef me for production */
69
70#ifdef DEBUG
71#define DPRINTF(x, a...) printk(KERN_DEBUG "W9966: %s(): "x, __func__ , ##a)
72#else
73#define DPRINTF(x...)
74#endif
75
76/*
77 *	Defines, simple typedefs etc.
78 */
79
80#define W9966_DRIVERNAME	"W9966CF Webcam"
81#define W9966_MAXCAMS		4	/* Maximum number of cameras */
82#define W9966_RBUFFER		2048	/* Read buffer (must be an even number) */
83#define W9966_SRAMSIZE		131072	/* 128kb */
84#define W9966_SRAMID		0x02	/* check w9966cf.pdf */
85
86/* Empirically determined window limits */
87#define W9966_WND_MIN_X		16
88#define W9966_WND_MIN_Y		14
89#define W9966_WND_MAX_X		705
90#define W9966_WND_MAX_Y		253
91#define W9966_WND_MAX_W		(W9966_WND_MAX_X - W9966_WND_MIN_X)
92#define W9966_WND_MAX_H		(W9966_WND_MAX_Y - W9966_WND_MIN_Y)
93
94/* Keep track of our current state */
95#define W9966_STATE_PDEV	0x01
96#define W9966_STATE_CLAIMED	0x02
97#define W9966_STATE_VDEV	0x04
98
99#define W9966_I2C_W_ID		0x48
100#define W9966_I2C_R_ID		0x49
101#define W9966_I2C_R_DATA	0x08
102#define W9966_I2C_R_CLOCK	0x04
103#define W9966_I2C_W_DATA	0x02
104#define W9966_I2C_W_CLOCK	0x01
105
106struct w9966 {
107	struct v4l2_device v4l2_dev;
108	unsigned char dev_state;
109	unsigned char i2c_state;
110	unsigned short ppmode;
111	struct parport *pport;
112	struct pardevice *pdev;
113	struct video_device vdev;
114	unsigned short width;
115	unsigned short height;
116	unsigned char brightness;
117	signed char contrast;
118	signed char color;
119	signed char hue;
120	struct mutex lock;
121};
122
123/*
124 *	Module specific properties
125 */
126
127MODULE_AUTHOR("Jakob Kemi <jakob.kemi@post.utfors.se>");
128MODULE_DESCRIPTION("Winbond w9966cf WebCam driver (0.32)");
129MODULE_LICENSE("GPL");
130
131
132#ifdef MODULE
133static const char *pardev[] = {[0 ... W9966_MAXCAMS] = ""};
134#else
135static const char *pardev[] = {[0 ... W9966_MAXCAMS] = "aggressive"};
136#endif
137module_param_array(pardev, charp, NULL, 0);
138MODULE_PARM_DESC(pardev, "pardev: where to search for\n"
139		"\teach camera. 'aggressive' means brute-force search.\n"
140		"\tEg: >pardev=parport3,aggressive,parport2,parport1< would assign\n"
141		"\tcam 1 to parport3 and search every parport for cam 2 etc...");
142
143static int parmode;
144module_param(parmode, int, 0);
145MODULE_PARM_DESC(parmode, "parmode: transfer mode (0=auto, 1=ecp, 2=epp");
146
147static int video_nr = -1;
148module_param(video_nr, int, 0);
149
150static struct w9966 w9966_cams[W9966_MAXCAMS];
151
152/*
153 *	Private function defines
154 */
155
156
157/* Set camera phase flags, so we know what to uninit when terminating */
158static inline void w9966_set_state(struct w9966 *cam, int mask, int val)
159{
160	cam->dev_state = (cam->dev_state & ~mask) ^ val;
161}
162
163/* Get camera phase flags */
164static inline int w9966_get_state(struct w9966 *cam, int mask, int val)
165{
166	return ((cam->dev_state & mask) == val);
167}
168
169/* Claim parport for ourself */
170static void w9966_pdev_claim(struct w9966 *cam)
171{
172	if (w9966_get_state(cam, W9966_STATE_CLAIMED, W9966_STATE_CLAIMED))
173		return;
174	parport_claim_or_block(cam->pdev);
175	w9966_set_state(cam, W9966_STATE_CLAIMED, W9966_STATE_CLAIMED);
176}
177
178/* Release parport for others to use */
179static void w9966_pdev_release(struct w9966 *cam)
180{
181	if (w9966_get_state(cam, W9966_STATE_CLAIMED, 0))
182		return;
183	parport_release(cam->pdev);
184	w9966_set_state(cam, W9966_STATE_CLAIMED, 0);
185}
186
187/* Read register from W9966 interface-chip
188   Expects a claimed pdev
189   -1 on error, else register data (byte) */
190static int w9966_read_reg(struct w9966 *cam, int reg)
191{
192	/* ECP, read, regtransfer, REG, REG, REG, REG, REG */
193	const unsigned char addr = 0x80 | (reg & 0x1f);
194	unsigned char val;
195
196	if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_ADDR) != 0)
197		return -1;
198	if (parport_write(cam->pport, &addr, 1) != 1)
199		return -1;
200	if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_DATA) != 0)
201		return -1;
202	if (parport_read(cam->pport, &val, 1) != 1)
203		return -1;
204
205	return val;
206}
207
208/* Write register to W9966 interface-chip
209   Expects a claimed pdev
210   -1 on error */
211static int w9966_write_reg(struct w9966 *cam, int reg, int data)
212{
213	/* ECP, write, regtransfer, REG, REG, REG, REG, REG */
214	const unsigned char addr = 0xc0 | (reg & 0x1f);
215	const unsigned char val = data;
216
217	if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_ADDR) != 0)
218		return -1;
219	if (parport_write(cam->pport, &addr, 1) != 1)
220		return -1;
221	if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_DATA) != 0)
222		return -1;
223	if (parport_write(cam->pport, &val, 1) != 1)
224		return -1;
225
226	return 0;
227}
228
229/*
230 *	Ugly and primitive i2c protocol functions
231 */
232
233/* Sets the data line on the i2c bus.
234   Expects a claimed pdev. */
235static void w9966_i2c_setsda(struct w9966 *cam, int state)
236{
237	if (state)
238		cam->i2c_state |= W9966_I2C_W_DATA;
239	else
240		cam->i2c_state &= ~W9966_I2C_W_DATA;
241
242	w9966_write_reg(cam, 0x18, cam->i2c_state);
243	udelay(5);
244}
245
246/* Get peripheral clock line
247   Expects a claimed pdev. */
248static int w9966_i2c_getscl(struct w9966 *cam)
249{
250	const unsigned char state = w9966_read_reg(cam, 0x18);
251	return ((state & W9966_I2C_R_CLOCK) > 0);
252}
253
254/* Sets the clock line on the i2c bus.
255   Expects a claimed pdev. -1 on error */
256static int w9966_i2c_setscl(struct w9966 *cam, int state)
257{
258	unsigned long timeout;
259
260	if (state)
261		cam->i2c_state |= W9966_I2C_W_CLOCK;
262	else
263		cam->i2c_state &= ~W9966_I2C_W_CLOCK;
264
265	w9966_write_reg(cam, 0x18, cam->i2c_state);
266	udelay(5);
267
268	/* we go to high, we also expect the peripheral to ack. */
269	if (state) {
270		timeout = jiffies + 100;
271		while (!w9966_i2c_getscl(cam)) {
272			if (time_after(jiffies, timeout))
273				return -1;
274		}
275	}
276	return 0;
277}
278
279
280/* Write a byte with ack to the i2c bus.
281   Expects a claimed pdev. -1 on error */
282static int w9966_i2c_wbyte(struct w9966 *cam, int data)
283{
284	int i;
285
286	for (i = 7; i >= 0; i--) {
287		w9966_i2c_setsda(cam, (data >> i) & 0x01);
288
289		if (w9966_i2c_setscl(cam, 1) == -1)
290			return -1;
291		w9966_i2c_setscl(cam, 0);
292	}
293
294	w9966_i2c_setsda(cam, 1);
295
296	if (w9966_i2c_setscl(cam, 1) == -1)
297		return -1;
298	w9966_i2c_setscl(cam, 0);
299
300	return 0;
301}
302
303/* Read a data byte with ack from the i2c-bus
304   Expects a claimed pdev. -1 on error */
305
306/* Read a register from the i2c device.
307   Expects claimed pdev. -1 on error */
308
309/* Write a register to the i2c device.
310   Expects claimed pdev. -1 on error */
311static int w9966_write_reg_i2c(struct w9966 *cam, int reg, int data)
312{
313	w9966_i2c_setsda(cam, 0);
314	w9966_i2c_setscl(cam, 0);
315
316	if (w9966_i2c_wbyte(cam, W9966_I2C_W_ID) == -1 ||
317			w9966_i2c_wbyte(cam, reg) == -1 ||
318			w9966_i2c_wbyte(cam, data) == -1)
319		return -1;
320
321	w9966_i2c_setsda(cam, 0);
322	if (w9966_i2c_setscl(cam, 1) == -1)
323		return -1;
324
325	w9966_i2c_setsda(cam, 1);
326
327	return 0;
328}
329
330/* Find a good length for capture window (used both for W and H)
331   A bit ugly but pretty functional. The capture length
332   have to match the downscale */
333static int w9966_findlen(int near, int size, int maxlen)
334{
335	int bestlen = size;
336	int besterr = abs(near - bestlen);
337	int len;
338
339	for (len = size + 1; len < maxlen; len++) {
340		int err;
341		if (((64 * size) % len) != 0)
342			continue;
343
344		err = abs(near - len);
345
346		/* Only continue as long as we keep getting better values */
347		if (err > besterr)
348			break;
349
350		besterr = err;
351		bestlen = len;
352	}
353
354	return bestlen;
355}
356
357/* Modify capture window (if necessary)
358   and calculate downscaling
359   Return -1 on error */
360static int w9966_calcscale(int size, int min, int max, int *beg, int *end, unsigned char *factor)
361{
362	int maxlen = max - min;
363	int len = *end - *beg + 1;
364	int newlen = w9966_findlen(len, size, maxlen);
365	int err = newlen - len;
366
367	/* Check for bad format */
368	if (newlen > maxlen || newlen < size)
369		return -1;
370
371	/* Set factor (6 bit fixed) */
372	*factor = (64 * size) / newlen;
373	if (*factor == 64)
374		*factor = 0x00;	/* downscale is disabled */
375	else
376		*factor |= 0x80; /* set downscale-enable bit */
377
378	/* Modify old beginning and end */
379	*beg -= err / 2;
380	*end += err - (err / 2);
381
382	/* Move window if outside borders */
383	if (*beg < min) {
384		*end += min - *beg;
385		*beg += min - *beg;
386	}
387	if (*end > max) {
388		*beg -= *end - max;
389		*end -= *end - max;
390	}
391
392	return 0;
393}
394
395/* Setup the cameras capture window etc.
396   Expects a claimed pdev
397   return -1 on error */
398static int w9966_setup(struct w9966 *cam, int x1, int y1, int x2, int y2, int w, int h)
399{
400	unsigned int i;
401	unsigned int enh_s, enh_e;
402	unsigned char scale_x, scale_y;
403	unsigned char regs[0x1c];
404	unsigned char saa7111_regs[] = {
405		0x21, 0x00, 0xd8, 0x23, 0x00, 0x80, 0x80, 0x00,
406		0x88, 0x10, 0x80, 0x40, 0x40, 0x00, 0x01, 0x00,
407		0x48, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
408		0x00, 0x00, 0x00, 0x71, 0xe7, 0x00, 0x00, 0xc0
409	};
410
411
412	if (w * h * 2 > W9966_SRAMSIZE) {
413		DPRINTF("capture window exceeds SRAM size!.\n");
414		w = 200; h = 160;	/* Pick default values */
415	}
416
417	w &= ~0x1;
418	if (w < 2)
419		w = 2;
420	if (h < 1)
421		h = 1;
422	if (w > W9966_WND_MAX_W)
423		w = W9966_WND_MAX_W;
424	if (h > W9966_WND_MAX_H)
425		h = W9966_WND_MAX_H;
426
427	cam->width = w;
428	cam->height = h;
429
430	enh_s = 0;
431	enh_e = w * h * 2;
432
433	/* Modify capture window if necessary and calculate downscaling */
434	if (w9966_calcscale(w, W9966_WND_MIN_X, W9966_WND_MAX_X, &x1, &x2, &scale_x) != 0 ||
435			w9966_calcscale(h, W9966_WND_MIN_Y, W9966_WND_MAX_Y, &y1, &y2, &scale_y) != 0)
436		return -1;
437
438	DPRINTF("%dx%d, x: %d<->%d, y: %d<->%d, sx: %d/64, sy: %d/64.\n",
439			w, h, x1, x2, y1, y2, scale_x & ~0x80, scale_y & ~0x80);
440
441	/* Setup registers */
442	regs[0x00] = 0x00;			/* Set normal operation */
443	regs[0x01] = 0x18;			/* Capture mode */
444	regs[0x02] = scale_y;			/* V-scaling */
445	regs[0x03] = scale_x;			/* H-scaling */
446
447	/* Capture window */
448	regs[0x04] = (x1 & 0x0ff);		/* X-start (8 low bits) */
449	regs[0x05] = (x1 & 0x300)>>8;		/* X-start (2 high bits) */
450	regs[0x06] = (y1 & 0x0ff);		/* Y-start (8 low bits) */
451	regs[0x07] = (y1 & 0x300)>>8;		/* Y-start (2 high bits) */
452	regs[0x08] = (x2 & 0x0ff);		/* X-end (8 low bits) */
453	regs[0x09] = (x2 & 0x300)>>8;		/* X-end (2 high bits) */
454	regs[0x0a] = (y2 & 0x0ff);		/* Y-end (8 low bits) */
455
456	regs[0x0c] = W9966_SRAMID;		/* SRAM-banks (1x 128kb) */
457
458	/* Enhancement layer */
459	regs[0x0d] = (enh_s & 0x000ff);		/* Enh. start (0-7) */
460	regs[0x0e] = (enh_s & 0x0ff00) >> 8;	/* Enh. start (8-15) */
461	regs[0x0f] = (enh_s & 0x70000) >> 16;	/* Enh. start (16-17/18??) */
462	regs[0x10] = (enh_e & 0x000ff);		/* Enh. end (0-7) */
463	regs[0x11] = (enh_e & 0x0ff00) >> 8;	/* Enh. end (8-15) */
464	regs[0x12] = (enh_e & 0x70000) >> 16;	/* Enh. end (16-17/18??) */
465
466	/* Misc */
467	regs[0x13] = 0x40;			/* VEE control (raw 4:2:2) */
468	regs[0x17] = 0x00;			/* ??? */
469	regs[0x18] = cam->i2c_state = 0x00;	/* Serial bus */
470	regs[0x19] = 0xff;			/* I/O port direction control */
471	regs[0x1a] = 0xff;			/* I/O port data register */
472	regs[0x1b] = 0x10;			/* ??? */
473
474	/* SAA7111 chip settings */
475	saa7111_regs[0x0a] = cam->brightness;
476	saa7111_regs[0x0b] = cam->contrast;
477	saa7111_regs[0x0c] = cam->color;
478	saa7111_regs[0x0d] = cam->hue;
479
480	/* Reset (ECP-fifo & serial-bus) */
481	if (w9966_write_reg(cam, 0x00, 0x03) == -1)
482		return -1;
483
484	/* Write regs to w9966cf chip */
485	for (i = 0; i < 0x1c; i++)
486		if (w9966_write_reg(cam, i, regs[i]) == -1)
487			return -1;
488
489	/* Write regs to saa7111 chip */
490	for (i = 0; i < 0x20; i++)
491		if (w9966_write_reg_i2c(cam, i, saa7111_regs[i]) == -1)
492			return -1;
493
494	return 0;
495}
496
497/*
498 *	Video4linux interfacing
499 */
500
501static int cam_querycap(struct file *file, void  *priv,
502					struct v4l2_capability *vcap)
503{
504	struct w9966 *cam = video_drvdata(file);
505
506	strlcpy(vcap->driver, cam->v4l2_dev.name, sizeof(vcap->driver));
507	strlcpy(vcap->card, W9966_DRIVERNAME, sizeof(vcap->card));
508	strlcpy(vcap->bus_info, "parport", sizeof(vcap->bus_info));
509	vcap->version = KERNEL_VERSION(0, 33, 0);
510	vcap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
511	return 0;
512}
513
514static int cam_enum_input(struct file *file, void *fh, struct v4l2_input *vin)
515{
516	if (vin->index > 0)
517		return -EINVAL;
518	strlcpy(vin->name, "Camera", sizeof(vin->name));
519	vin->type = V4L2_INPUT_TYPE_CAMERA;
520	vin->audioset = 0;
521	vin->tuner = 0;
522	vin->std = 0;
523	vin->status = 0;
524	return 0;
525}
526
527static int cam_g_input(struct file *file, void *fh, unsigned int *inp)
528{
529	*inp = 0;
530	return 0;
531}
532
533static int cam_s_input(struct file *file, void *fh, unsigned int inp)
534{
535	return (inp > 0) ? -EINVAL : 0;
536}
537
538static int cam_queryctrl(struct file *file, void *priv,
539					struct v4l2_queryctrl *qc)
540{
541	switch (qc->id) {
542	case V4L2_CID_BRIGHTNESS:
543		return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128);
544	case V4L2_CID_CONTRAST:
545		return v4l2_ctrl_query_fill(qc, -64, 64, 1, 64);
546	case V4L2_CID_SATURATION:
547		return v4l2_ctrl_query_fill(qc, -64, 64, 1, 64);
548	case V4L2_CID_HUE:
549		return v4l2_ctrl_query_fill(qc, -128, 127, 1, 0);
550	}
551	return -EINVAL;
552}
553
554static int cam_g_ctrl(struct file *file, void *priv,
555					struct v4l2_control *ctrl)
556{
557	struct w9966 *cam = video_drvdata(file);
558	int ret = 0;
559
560	switch (ctrl->id) {
561	case V4L2_CID_BRIGHTNESS:
562		ctrl->value = cam->brightness;
563		break;
564	case V4L2_CID_CONTRAST:
565		ctrl->value = cam->contrast;
566		break;
567	case V4L2_CID_SATURATION:
568		ctrl->value = cam->color;
569		break;
570	case V4L2_CID_HUE:
571		ctrl->value = cam->hue;
572		break;
573	default:
574		ret = -EINVAL;
575		break;
576	}
577	return ret;
578}
579
580static int cam_s_ctrl(struct file *file, void *priv,
581					struct v4l2_control *ctrl)
582{
583	struct w9966 *cam = video_drvdata(file);
584	int ret = 0;
585
586	mutex_lock(&cam->lock);
587	switch (ctrl->id) {
588	case V4L2_CID_BRIGHTNESS:
589		cam->brightness = ctrl->value;
590		break;
591	case V4L2_CID_CONTRAST:
592		cam->contrast = ctrl->value;
593		break;
594	case V4L2_CID_SATURATION:
595		cam->color = ctrl->value;
596		break;
597	case V4L2_CID_HUE:
598		cam->hue = ctrl->value;
599		break;
600	default:
601		ret = -EINVAL;
602		break;
603	}
604
605	if (ret == 0) {
606		w9966_pdev_claim(cam);
607
608		if (w9966_write_reg_i2c(cam, 0x0a, cam->brightness) == -1 ||
609		    w9966_write_reg_i2c(cam, 0x0b, cam->contrast) == -1 ||
610		    w9966_write_reg_i2c(cam, 0x0c, cam->color) == -1 ||
611		    w9966_write_reg_i2c(cam, 0x0d, cam->hue) == -1) {
612			ret = -EIO;
613		}
614
615		w9966_pdev_release(cam);
616	}
617	mutex_unlock(&cam->lock);
618	return ret;
619}
620
621static int cam_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
622{
623	struct w9966 *cam = video_drvdata(file);
624	struct v4l2_pix_format *pix = &fmt->fmt.pix;
625
626	pix->width = cam->width;
627	pix->height = cam->height;
628	pix->pixelformat = V4L2_PIX_FMT_YUYV;
629	pix->field = V4L2_FIELD_NONE;
630	pix->bytesperline = 2 * cam->width;
631	pix->sizeimage = 2 * cam->width * cam->height;
632	/* Just a guess */
633	pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
634	return 0;
635}
636
637static int cam_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
638{
639	struct v4l2_pix_format *pix = &fmt->fmt.pix;
640
641	if (pix->width < 2)
642		pix->width = 2;
643	if (pix->height < 1)
644		pix->height = 1;
645	if (pix->width > W9966_WND_MAX_W)
646		pix->width = W9966_WND_MAX_W;
647	if (pix->height > W9966_WND_MAX_H)
648		pix->height = W9966_WND_MAX_H;
649	pix->pixelformat = V4L2_PIX_FMT_YUYV;
650	pix->field = V4L2_FIELD_NONE;
651	pix->bytesperline = 2 * pix->width;
652	pix->sizeimage = 2 * pix->width * pix->height;
653	/* Just a guess */
654	pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
655	return 0;
656}
657
658static int cam_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
659{
660	struct w9966 *cam = video_drvdata(file);
661	struct v4l2_pix_format *pix = &fmt->fmt.pix;
662	int ret = cam_try_fmt_vid_cap(file, fh, fmt);
663
664	if (ret)
665		return ret;
666
667	mutex_lock(&cam->lock);
668	/* Update camera regs */
669	w9966_pdev_claim(cam);
670	ret = w9966_setup(cam, 0, 0, 1023, 1023, pix->width, pix->height);
671	w9966_pdev_release(cam);
672	mutex_unlock(&cam->lock);
673	return ret;
674}
675
676static int cam_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *fmt)
677{
678	static struct v4l2_fmtdesc formats[] = {
679		{ 0, 0, 0,
680		  "YUV 4:2:2", V4L2_PIX_FMT_YUYV,
681		  { 0, 0, 0, 0 }
682		},
683	};
684	enum v4l2_buf_type type = fmt->type;
685
686	if (fmt->index > 0)
687		return -EINVAL;
688
689	*fmt = formats[fmt->index];
690	fmt->type = type;
691	return 0;
692}
693
694/* Capture data */
695static ssize_t w9966_v4l_read(struct file *file, char  __user *buf,
696		size_t count, loff_t *ppos)
697{
698	struct w9966 *cam = video_drvdata(file);
699	unsigned char addr = 0xa0;	/* ECP, read, CCD-transfer, 00000 */
700	unsigned char __user *dest = (unsigned char __user *)buf;
701	unsigned long dleft = count;
702	unsigned char *tbuf;
703
704	/* Why would anyone want more than this?? */
705	if (count > cam->width * cam->height * 2)
706		return -EINVAL;
707
708	mutex_lock(&cam->lock);
709	w9966_pdev_claim(cam);
710	w9966_write_reg(cam, 0x00, 0x02);	/* Reset ECP-FIFO buffer */
711	w9966_write_reg(cam, 0x00, 0x00);	/* Return to normal operation */
712	w9966_write_reg(cam, 0x01, 0x98);	/* Enable capture */
713
714	/* write special capture-addr and negotiate into data transfer */
715	if ((parport_negotiate(cam->pport, cam->ppmode|IEEE1284_ADDR) != 0) ||
716			(parport_write(cam->pport, &addr, 1) != 1) ||
717			(parport_negotiate(cam->pport, cam->ppmode|IEEE1284_DATA) != 0)) {
718		w9966_pdev_release(cam);
719		mutex_unlock(&cam->lock);
720		return -EFAULT;
721	}
722
723	tbuf = kmalloc(W9966_RBUFFER, GFP_KERNEL);
724	if (tbuf == NULL) {
725		count = -ENOMEM;
726		goto out;
727	}
728
729	while (dleft > 0) {
730		unsigned long tsize = (dleft > W9966_RBUFFER) ? W9966_RBUFFER : dleft;
731
732		if (parport_read(cam->pport, tbuf, tsize) < tsize) {
733			count = -EFAULT;
734			goto out;
735		}
736		if (copy_to_user(dest, tbuf, tsize) != 0) {
737			count = -EFAULT;
738			goto out;
739		}
740		dest += tsize;
741		dleft -= tsize;
742	}
743
744	w9966_write_reg(cam, 0x01, 0x18);	/* Disable capture */
745
746out:
747	kfree(tbuf);
748	w9966_pdev_release(cam);
749	mutex_unlock(&cam->lock);
750
751	return count;
752}
753
754static const struct v4l2_file_operations w9966_fops = {
755	.owner		= THIS_MODULE,
756	.ioctl          = video_ioctl2,
757	.read           = w9966_v4l_read,
758};
759
760static const struct v4l2_ioctl_ops w9966_ioctl_ops = {
761	.vidioc_querycap    		    = cam_querycap,
762	.vidioc_g_input      		    = cam_g_input,
763	.vidioc_s_input      		    = cam_s_input,
764	.vidioc_enum_input   		    = cam_enum_input,
765	.vidioc_queryctrl 		    = cam_queryctrl,
766	.vidioc_g_ctrl  		    = cam_g_ctrl,
767	.vidioc_s_ctrl 			    = cam_s_ctrl,
768	.vidioc_enum_fmt_vid_cap 	    = cam_enum_fmt_vid_cap,
769	.vidioc_g_fmt_vid_cap 		    = cam_g_fmt_vid_cap,
770	.vidioc_s_fmt_vid_cap  		    = cam_s_fmt_vid_cap,
771	.vidioc_try_fmt_vid_cap  	    = cam_try_fmt_vid_cap,
772};
773
774
775/* Initialize camera device. Setup all internal flags, set a
776   default video mode, setup ccd-chip, register v4l device etc..
777   Also used for 'probing' of hardware.
778   -1 on error */
779static int w9966_init(struct w9966 *cam, struct parport *port)
780{
781	struct v4l2_device *v4l2_dev = &cam->v4l2_dev;
782
783	if (cam->dev_state != 0)
784		return -1;
785
786	strlcpy(v4l2_dev->name, "w9966", sizeof(v4l2_dev->name));
787
788	if (v4l2_device_register(NULL, v4l2_dev) < 0) {
789		v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
790		return -1;
791	}
792	cam->pport = port;
793	cam->brightness = 128;
794	cam->contrast = 64;
795	cam->color = 64;
796	cam->hue = 0;
797
798	/* Select requested transfer mode */
799	switch (parmode) {
800	default:	/* Auto-detect (priority: hw-ecp, hw-epp, sw-ecp) */
801	case 0:
802		if (port->modes & PARPORT_MODE_ECP)
803			cam->ppmode = IEEE1284_MODE_ECP;
804		else if (port->modes & PARPORT_MODE_EPP)
805			cam->ppmode = IEEE1284_MODE_EPP;
806		else
807			cam->ppmode = IEEE1284_MODE_ECP;
808		break;
809	case 1:		/* hw- or sw-ecp */
810		cam->ppmode = IEEE1284_MODE_ECP;
811		break;
812	case 2:		/* hw- or sw-epp */
813		cam->ppmode = IEEE1284_MODE_EPP;
814		break;
815	}
816
817	/* Tell the parport driver that we exists */
818	cam->pdev = parport_register_device(port, "w9966", NULL, NULL, NULL, 0, NULL);
819	if (cam->pdev == NULL) {
820		DPRINTF("parport_register_device() failed\n");
821		return -1;
822	}
823	w9966_set_state(cam, W9966_STATE_PDEV, W9966_STATE_PDEV);
824
825	w9966_pdev_claim(cam);
826
827	/* Setup a default capture mode */
828	if (w9966_setup(cam, 0, 0, 1023, 1023, 200, 160) != 0) {
829		DPRINTF("w9966_setup() failed.\n");
830		return -1;
831	}
832
833	w9966_pdev_release(cam);
834
835	/* Fill in the video_device struct and register us to v4l */
836	strlcpy(cam->vdev.name, W9966_DRIVERNAME, sizeof(cam->vdev.name));
837	cam->vdev.v4l2_dev = v4l2_dev;
838	cam->vdev.fops = &w9966_fops;
839	cam->vdev.ioctl_ops = &w9966_ioctl_ops;
840	cam->vdev.release = video_device_release_empty;
841	video_set_drvdata(&cam->vdev, cam);
842
843	mutex_init(&cam->lock);
844
845	if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, video_nr) < 0)
846		return -1;
847
848	w9966_set_state(cam, W9966_STATE_VDEV, W9966_STATE_VDEV);
849
850	/* All ok */
851	v4l2_info(v4l2_dev, "Found and initialized a webcam on %s.\n",
852			cam->pport->name);
853	return 0;
854}
855
856
857/* Terminate everything gracefully */
858static void w9966_term(struct w9966 *cam)
859{
860	/* Unregister from v4l */
861	if (w9966_get_state(cam, W9966_STATE_VDEV, W9966_STATE_VDEV)) {
862		video_unregister_device(&cam->vdev);
863		w9966_set_state(cam, W9966_STATE_VDEV, 0);
864	}
865
866	/* Terminate from IEEE1284 mode and release pdev block */
867	if (w9966_get_state(cam, W9966_STATE_PDEV, W9966_STATE_PDEV)) {
868		w9966_pdev_claim(cam);
869		parport_negotiate(cam->pport, IEEE1284_MODE_COMPAT);
870		w9966_pdev_release(cam);
871	}
872
873	/* Unregister from parport */
874	if (w9966_get_state(cam, W9966_STATE_PDEV, W9966_STATE_PDEV)) {
875		parport_unregister_device(cam->pdev);
876		w9966_set_state(cam, W9966_STATE_PDEV, 0);
877	}
878}
879
880
881/* Called once for every parport on init */
882static void w9966_attach(struct parport *port)
883{
884	int i;
885
886	for (i = 0; i < W9966_MAXCAMS; i++) {
887		if (w9966_cams[i].dev_state != 0)	/* Cam is already assigned */
888			continue;
889		if (strcmp(pardev[i], "aggressive") == 0 || strcmp(pardev[i], port->name) == 0) {
890			if (w9966_init(&w9966_cams[i], port) != 0)
891				w9966_term(&w9966_cams[i]);
892			break;	/* return */
893		}
894	}
895}
896
897/* Called once for every parport on termination */
898static void w9966_detach(struct parport *port)
899{
900	int i;
901
902	for (i = 0; i < W9966_MAXCAMS; i++)
903		if (w9966_cams[i].dev_state != 0 && w9966_cams[i].pport == port)
904			w9966_term(&w9966_cams[i]);
905}
906
907
908static struct parport_driver w9966_ppd = {
909	.name = W9966_DRIVERNAME,
910	.attach = w9966_attach,
911	.detach = w9966_detach,
912};
913
914/* Module entry point */
915static int __init w9966_mod_init(void)
916{
917	int i;
918
919	for (i = 0; i < W9966_MAXCAMS; i++)
920		w9966_cams[i].dev_state = 0;
921
922	return parport_register_driver(&w9966_ppd);
923}
924
925/* Module cleanup */
926static void __exit w9966_mod_term(void)
927{
928	parport_unregister_driver(&w9966_ppd);
929}
930
931module_init(w9966_mod_init);
932module_exit(w9966_mod_term);
933