aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/w9966.c
diff options
context:
space:
mode:
authorHans Verkuil <hverkuil@xs4all.nl>2010-04-06 10:36:39 -0400
committerMauro Carvalho Chehab <mchehab@redhat.com>2010-05-19 11:57:09 -0400
commit626e2acfdce76b5a6a1daa4bc8ef556d507f5941 (patch)
treea52501e3fbc67d7b66212e3598c4aec17898abc6 /drivers/media/video/w9966.c
parente426e8663f028272b99f91e57bbbab6fda603bf1 (diff)
V4L/DVB: w9966: convert to V4L2
Note that I have not been able to find anyone with this hardware. I tried contacting the author without success, searched on eBay and similar places without luck either. So this conversion is untested. That said, it was pretty straightforward so it is time to have this driver join the V4L2 world at last. Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/w9966.c')
-rw-r--r--drivers/media/video/w9966.c435
1 files changed, 242 insertions, 193 deletions
diff --git a/drivers/media/video/w9966.c b/drivers/media/video/w9966.c
index b0719976845e..635420d8d84a 100644
--- a/drivers/media/video/w9966.c
+++ b/drivers/media/video/w9966.c
@@ -1,7 +1,7 @@
1/* 1/*
2 Winbond w9966cf Webcam parport driver. 2 Winbond w9966cf Webcam parport driver.
3 3
4 Version 0.32 4 Version 0.33
5 5
6 Copyright (C) 2001 Jakob Kemi <jakob.kemi@post.utfors.se> 6 Copyright (C) 2001 Jakob Kemi <jakob.kemi@post.utfors.se>
7 7
@@ -57,10 +57,12 @@
57#include <linux/module.h> 57#include <linux/module.h>
58#include <linux/init.h> 58#include <linux/init.h>
59#include <linux/delay.h> 59#include <linux/delay.h>
60#include <linux/videodev.h> 60#include <linux/version.h>
61#include <linux/videodev2.h>
61#include <linux/slab.h> 62#include <linux/slab.h>
62#include <media/v4l2-common.h> 63#include <media/v4l2-common.h>
63#include <media/v4l2-ioctl.h> 64#include <media/v4l2-ioctl.h>
65#include <media/v4l2-device.h>
64#include <linux/parport.h> 66#include <linux/parport.h>
65 67
66/*#define DEBUG*/ /* Undef me for production */ 68/*#define DEBUG*/ /* Undef me for production */
@@ -101,7 +103,8 @@
101#define W9966_I2C_W_DATA 0x02 103#define W9966_I2C_W_DATA 0x02
102#define W9966_I2C_W_CLOCK 0x01 104#define W9966_I2C_W_CLOCK 0x01
103 105
104struct w9966_dev { 106struct w9966 {
107 struct v4l2_device v4l2_dev;
105 unsigned char dev_state; 108 unsigned char dev_state;
106 unsigned char i2c_state; 109 unsigned char i2c_state;
107 unsigned short ppmode; 110 unsigned short ppmode;
@@ -114,7 +117,7 @@ struct w9966_dev {
114 signed char contrast; 117 signed char contrast;
115 signed char color; 118 signed char color;
116 signed char hue; 119 signed char hue;
117 unsigned long in_use; 120 struct mutex lock;
118}; 121};
119 122
120/* 123/*
@@ -144,7 +147,7 @@ MODULE_PARM_DESC(parmode, "parmode: transfer mode (0=auto, 1=ecp, 2=epp");
144static int video_nr = -1; 147static int video_nr = -1;
145module_param(video_nr, int, 0); 148module_param(video_nr, int, 0);
146 149
147static struct w9966_dev w9966_cams[W9966_MAXCAMS]; 150static struct w9966 w9966_cams[W9966_MAXCAMS];
148 151
149/* 152/*
150 * Private function defines 153 * Private function defines
@@ -152,19 +155,19 @@ static struct w9966_dev w9966_cams[W9966_MAXCAMS];
152 155
153 156
154/* Set camera phase flags, so we know what to uninit when terminating */ 157/* Set camera phase flags, so we know what to uninit when terminating */
155static inline void w9966_set_state(struct w9966_dev *cam, int mask, int val) 158static inline void w9966_set_state(struct w9966 *cam, int mask, int val)
156{ 159{
157 cam->dev_state = (cam->dev_state & ~mask) ^ val; 160 cam->dev_state = (cam->dev_state & ~mask) ^ val;
158} 161}
159 162
160/* Get camera phase flags */ 163/* Get camera phase flags */
161static inline int w9966_get_state(struct w9966_dev *cam, int mask, int val) 164static inline int w9966_get_state(struct w9966 *cam, int mask, int val)
162{ 165{
163 return ((cam->dev_state & mask) == val); 166 return ((cam->dev_state & mask) == val);
164} 167}
165 168
166/* Claim parport for ourself */ 169/* Claim parport for ourself */
167static void w9966_pdev_claim(struct w9966_dev *cam) 170static void w9966_pdev_claim(struct w9966 *cam)
168{ 171{
169 if (w9966_get_state(cam, W9966_STATE_CLAIMED, W9966_STATE_CLAIMED)) 172 if (w9966_get_state(cam, W9966_STATE_CLAIMED, W9966_STATE_CLAIMED))
170 return; 173 return;
@@ -173,7 +176,7 @@ static void w9966_pdev_claim(struct w9966_dev *cam)
173} 176}
174 177
175/* Release parport for others to use */ 178/* Release parport for others to use */
176static void w9966_pdev_release(struct w9966_dev *cam) 179static void w9966_pdev_release(struct w9966 *cam)
177{ 180{
178 if (w9966_get_state(cam, W9966_STATE_CLAIMED, 0)) 181 if (w9966_get_state(cam, W9966_STATE_CLAIMED, 0))
179 return; 182 return;
@@ -184,7 +187,7 @@ static void w9966_pdev_release(struct w9966_dev *cam)
184/* Read register from W9966 interface-chip 187/* Read register from W9966 interface-chip
185 Expects a claimed pdev 188 Expects a claimed pdev
186 -1 on error, else register data (byte) */ 189 -1 on error, else register data (byte) */
187static int w9966_read_reg(struct w9966_dev *cam, int reg) 190static int w9966_read_reg(struct w9966 *cam, int reg)
188{ 191{
189 /* ECP, read, regtransfer, REG, REG, REG, REG, REG */ 192 /* ECP, read, regtransfer, REG, REG, REG, REG, REG */
190 const unsigned char addr = 0x80 | (reg & 0x1f); 193 const unsigned char addr = 0x80 | (reg & 0x1f);
@@ -205,7 +208,7 @@ static int w9966_read_reg(struct w9966_dev *cam, int reg)
205/* Write register to W9966 interface-chip 208/* Write register to W9966 interface-chip
206 Expects a claimed pdev 209 Expects a claimed pdev
207 -1 on error */ 210 -1 on error */
208static int w9966_write_reg(struct w9966_dev *cam, int reg, int data) 211static int w9966_write_reg(struct w9966 *cam, int reg, int data)
209{ 212{
210 /* ECP, write, regtransfer, REG, REG, REG, REG, REG */ 213 /* ECP, write, regtransfer, REG, REG, REG, REG, REG */
211 const unsigned char addr = 0xc0 | (reg & 0x1f); 214 const unsigned char addr = 0xc0 | (reg & 0x1f);
@@ -229,7 +232,7 @@ static int w9966_write_reg(struct w9966_dev *cam, int reg, int data)
229 232
230/* Sets the data line on the i2c bus. 233/* Sets the data line on the i2c bus.
231 Expects a claimed pdev. */ 234 Expects a claimed pdev. */
232static void w9966_i2c_setsda(struct w9966_dev *cam, int state) 235static void w9966_i2c_setsda(struct w9966 *cam, int state)
233{ 236{
234 if (state) 237 if (state)
235 cam->i2c_state |= W9966_I2C_W_DATA; 238 cam->i2c_state |= W9966_I2C_W_DATA;
@@ -242,7 +245,7 @@ static void w9966_i2c_setsda(struct w9966_dev *cam, int state)
242 245
243/* Get peripheral clock line 246/* Get peripheral clock line
244 Expects a claimed pdev. */ 247 Expects a claimed pdev. */
245static int w9966_i2c_getscl(struct w9966_dev *cam) 248static int w9966_i2c_getscl(struct w9966 *cam)
246{ 249{
247 const unsigned char state = w9966_read_reg(cam, 0x18); 250 const unsigned char state = w9966_read_reg(cam, 0x18);
248 return ((state & W9966_I2C_R_CLOCK) > 0); 251 return ((state & W9966_I2C_R_CLOCK) > 0);
@@ -250,7 +253,7 @@ static int w9966_i2c_getscl(struct w9966_dev *cam)
250 253
251/* Sets the clock line on the i2c bus. 254/* Sets the clock line on the i2c bus.
252 Expects a claimed pdev. -1 on error */ 255 Expects a claimed pdev. -1 on error */
253static int w9966_i2c_setscl(struct w9966_dev *cam, int state) 256static int w9966_i2c_setscl(struct w9966 *cam, int state)
254{ 257{
255 unsigned long timeout; 258 unsigned long timeout;
256 259
@@ -276,7 +279,7 @@ static int w9966_i2c_setscl(struct w9966_dev *cam, int state)
276#if 0 279#if 0
277/* Get peripheral data line 280/* Get peripheral data line
278 Expects a claimed pdev. */ 281 Expects a claimed pdev. */
279static int w9966_i2c_getsda(struct w9966_dev *cam) 282static int w9966_i2c_getsda(struct w9966 *cam)
280{ 283{
281 const unsigned char state = w9966_read_reg(cam, 0x18); 284 const unsigned char state = w9966_read_reg(cam, 0x18);
282 return ((state & W9966_I2C_R_DATA) > 0); 285 return ((state & W9966_I2C_R_DATA) > 0);
@@ -285,7 +288,7 @@ static int w9966_i2c_getsda(struct w9966_dev *cam)
285 288
286/* Write a byte with ack to the i2c bus. 289/* Write a byte with ack to the i2c bus.
287 Expects a claimed pdev. -1 on error */ 290 Expects a claimed pdev. -1 on error */
288static int w9966_i2c_wbyte(struct w9966_dev *cam, int data) 291static int w9966_i2c_wbyte(struct w9966 *cam, int data)
289{ 292{
290 int i; 293 int i;
291 294
@@ -309,7 +312,7 @@ static int w9966_i2c_wbyte(struct w9966_dev *cam, int data)
309/* Read a data byte with ack from the i2c-bus 312/* Read a data byte with ack from the i2c-bus
310 Expects a claimed pdev. -1 on error */ 313 Expects a claimed pdev. -1 on error */
311#if 0 314#if 0
312static int w9966_i2c_rbyte(struct w9966_dev *cam) 315static int w9966_i2c_rbyte(struct w9966 *cam)
313{ 316{
314 unsigned char data = 0x00; 317 unsigned char data = 0x00;
315 int i; 318 int i;
@@ -332,7 +335,7 @@ static int w9966_i2c_rbyte(struct w9966_dev *cam)
332/* Read a register from the i2c device. 335/* Read a register from the i2c device.
333 Expects claimed pdev. -1 on error */ 336 Expects claimed pdev. -1 on error */
334#if 0 337#if 0
335static int w9966_read_reg_i2c(struct w9966_dev *cam, int reg) 338static int w9966_read_reg_i2c(struct w9966 *cam, int reg)
336{ 339{
337 int data; 340 int data;
338 341
@@ -367,7 +370,7 @@ static int w9966_read_reg_i2c(struct w9966_dev *cam, int reg)
367 370
368/* Write a register to the i2c device. 371/* Write a register to the i2c device.
369 Expects claimed pdev. -1 on error */ 372 Expects claimed pdev. -1 on error */
370static int w9966_write_reg_i2c(struct w9966_dev *cam, int reg, int data) 373static int w9966_write_reg_i2c(struct w9966 *cam, int reg, int data)
371{ 374{
372 w9966_i2c_setsda(cam, 0); 375 w9966_i2c_setsda(cam, 0);
373 w9966_i2c_setscl(cam, 0); 376 w9966_i2c_setscl(cam, 0);
@@ -454,7 +457,7 @@ static int w9966_calcscale(int size, int min, int max, int *beg, int *end, unsig
454/* Setup the cameras capture window etc. 457/* Setup the cameras capture window etc.
455 Expects a claimed pdev 458 Expects a claimed pdev
456 return -1 on error */ 459 return -1 on error */
457static int w9966_setup(struct w9966_dev *cam, int x1, int y1, int x2, int y2, int w, int h) 460static int w9966_setup(struct w9966 *cam, int x1, int y1, int x2, int y2, int w, int h)
458{ 461{
459 unsigned int i; 462 unsigned int i;
460 unsigned int enh_s, enh_e; 463 unsigned int enh_s, enh_e;
@@ -557,166 +560,204 @@ static int w9966_setup(struct w9966_dev *cam, int x1, int y1, int x2, int y2, in
557 * Video4linux interfacing 560 * Video4linux interfacing
558 */ 561 */
559 562
560static long w9966_v4l_do_ioctl(struct file *file, unsigned int cmd, void *arg) 563static int cam_querycap(struct file *file, void *priv,
561{ 564 struct v4l2_capability *vcap)
562 struct w9966_dev *cam = video_drvdata(file); 565{
563 566 struct w9966 *cam = video_drvdata(file);
564 switch (cmd) { 567
565 case VIDIOCGCAP: 568 strlcpy(vcap->driver, cam->v4l2_dev.name, sizeof(vcap->driver));
566 { 569 strlcpy(vcap->card, W9966_DRIVERNAME, sizeof(vcap->card));
567 static struct video_capability vcap = { 570 strlcpy(vcap->bus_info, "parport", sizeof(vcap->bus_info));
568 .name = W9966_DRIVERNAME, 571 vcap->version = KERNEL_VERSION(0, 33, 0);
569 .type = VID_TYPE_CAPTURE | VID_TYPE_SCALES, 572 vcap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
570 .channels = 1, 573 return 0;
571 .maxwidth = W9966_WND_MAX_W, 574}
572 .maxheight = W9966_WND_MAX_H, 575
573 .minwidth = 2, 576static int cam_enum_input(struct file *file, void *fh, struct v4l2_input *vin)
574 .minheight = 1, 577{
575 }; 578 if (vin->index > 0)
576 struct video_capability *cap = arg;
577 *cap = vcap;
578 return 0;
579 }
580 case VIDIOCGCHAN:
581 {
582 struct video_channel *vch = arg;
583 if (vch->channel != 0) /* We only support one channel (#0) */
584 return -EINVAL;
585 memset(vch, 0, sizeof(*vch));
586 strcpy(vch->name, "CCD-input");
587 vch->type = VIDEO_TYPE_CAMERA;
588 return 0;
589 }
590 case VIDIOCSCHAN:
591 {
592 struct video_channel *vch = arg;
593 if (vch->channel != 0)
594 return -EINVAL;
595 return 0;
596 }
597 case VIDIOCGTUNER:
598 {
599 struct video_tuner *vtune = arg;
600 if (vtune->tuner != 0)
601 return -EINVAL;
602 strcpy(vtune->name, "no tuner");
603 vtune->rangelow = 0;
604 vtune->rangehigh = 0;
605 vtune->flags = VIDEO_TUNER_NORM;
606 vtune->mode = VIDEO_MODE_AUTO;
607 vtune->signal = 0xffff;
608 return 0;
609 }
610 case VIDIOCSTUNER:
611 {
612 struct video_tuner *vtune = arg;
613 if (vtune->tuner != 0)
614 return -EINVAL;
615 if (vtune->mode != VIDEO_MODE_AUTO)
616 return -EINVAL;
617 return 0;
618 }
619 case VIDIOCGPICT:
620 {
621 struct video_picture vpic = {
622 cam->brightness << 8, /* brightness */
623 (cam->hue + 128) << 8, /* hue */
624 cam->color << 9, /* color */
625 cam->contrast << 9, /* contrast */
626 0x8000, /* whiteness */
627 16, VIDEO_PALETTE_YUV422/* bpp, palette format */
628 };
629 struct video_picture *pic = arg;
630 *pic = vpic;
631 return 0;
632 }
633 case VIDIOCSPICT:
634 {
635 struct video_picture *vpic = arg;
636 if (vpic->depth != 16 || (vpic->palette != VIDEO_PALETTE_YUV422 && vpic->palette != VIDEO_PALETTE_YUYV))
637 return -EINVAL;
638
639 cam->brightness = vpic->brightness >> 8;
640 cam->hue = (vpic->hue >> 8) - 128;
641 cam->color = vpic->colour >> 9;
642 cam->contrast = vpic->contrast >> 9;
643
644 w9966_pdev_claim(cam);
645
646 if (
647 w9966_write_reg_i2c(cam, 0x0a, cam->brightness) == -1 ||
648 w9966_write_reg_i2c(cam, 0x0b, cam->contrast) == -1 ||
649 w9966_write_reg_i2c(cam, 0x0c, cam->color) == -1 ||
650 w9966_write_reg_i2c(cam, 0x0d, cam->hue) == -1
651 ) {
652 w9966_pdev_release(cam);
653 return -EIO;
654 }
655
656 w9966_pdev_release(cam);
657 return 0;
658 }
659 case VIDIOCSWIN:
660 {
661 int ret;
662 struct video_window *vwin = arg;
663
664 if (vwin->flags != 0)
665 return -EINVAL;
666 if (vwin->clipcount != 0)
667 return -EINVAL;
668 if (vwin->width < 2 || vwin->width > W9966_WND_MAX_W)
669 return -EINVAL;
670 if (vwin->height < 1 || vwin->height > W9966_WND_MAX_H)
671 return -EINVAL;
672
673 /* Update camera regs */
674 w9966_pdev_claim(cam);
675 ret = w9966_setup(cam, 0, 0, 1023, 1023, vwin->width, vwin->height);
676 w9966_pdev_release(cam);
677
678 if (ret != 0) {
679 DPRINTF("VIDIOCSWIN: w9966_setup() failed.\n");
680 return -EIO;
681 }
682
683 return 0;
684 }
685 case VIDIOCGWIN:
686 {
687 struct video_window *vwin = arg;
688 memset(vwin, 0, sizeof(*vwin));
689 vwin->width = cam->width;
690 vwin->height = cam->height;
691 return 0;
692 }
693 /* Unimplemented */
694 case VIDIOCCAPTURE:
695 case VIDIOCGFBUF:
696 case VIDIOCSFBUF:
697 case VIDIOCKEY:
698 case VIDIOCGFREQ:
699 case VIDIOCSFREQ:
700 case VIDIOCGAUDIO:
701 case VIDIOCSAUDIO:
702 return -EINVAL; 579 return -EINVAL;
580 strlcpy(vin->name, "Camera", sizeof(vin->name));
581 vin->type = V4L2_INPUT_TYPE_CAMERA;
582 vin->audioset = 0;
583 vin->tuner = 0;
584 vin->std = 0;
585 vin->status = 0;
586 return 0;
587}
588
589static int cam_g_input(struct file *file, void *fh, unsigned int *inp)
590{
591 *inp = 0;
592 return 0;
593}
594
595static int cam_s_input(struct file *file, void *fh, unsigned int inp)
596{
597 return (inp > 0) ? -EINVAL : 0;
598}
599
600static int cam_queryctrl(struct file *file, void *priv,
601 struct v4l2_queryctrl *qc)
602{
603 switch (qc->id) {
604 case V4L2_CID_BRIGHTNESS:
605 return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128);
606 case V4L2_CID_CONTRAST:
607 return v4l2_ctrl_query_fill(qc, -64, 64, 1, 64);
608 case V4L2_CID_SATURATION:
609 return v4l2_ctrl_query_fill(qc, -64, 64, 1, 64);
610 case V4L2_CID_HUE:
611 return v4l2_ctrl_query_fill(qc, -128, 127, 1, 0);
612 }
613 return -EINVAL;
614}
615
616static int cam_g_ctrl(struct file *file, void *priv,
617 struct v4l2_control *ctrl)
618{
619 struct w9966 *cam = video_drvdata(file);
620 int ret = 0;
621
622 switch (ctrl->id) {
623 case V4L2_CID_BRIGHTNESS:
624 ctrl->value = cam->brightness;
625 break;
626 case V4L2_CID_CONTRAST:
627 ctrl->value = cam->contrast;
628 break;
629 case V4L2_CID_SATURATION:
630 ctrl->value = cam->color;
631 break;
632 case V4L2_CID_HUE:
633 ctrl->value = cam->hue;
634 break;
703 default: 635 default:
704 return -ENOIOCTLCMD; 636 ret = -EINVAL;
637 break;
705 } 638 }
639 return ret;
640}
641
642static int cam_s_ctrl(struct file *file, void *priv,
643 struct v4l2_control *ctrl)
644{
645 struct w9966 *cam = video_drvdata(file);
646 int ret = 0;
647
648 mutex_lock(&cam->lock);
649 switch (ctrl->id) {
650 case V4L2_CID_BRIGHTNESS:
651 cam->brightness = ctrl->value;
652 break;
653 case V4L2_CID_CONTRAST:
654 cam->contrast = ctrl->value;
655 break;
656 case V4L2_CID_SATURATION:
657 cam->color = ctrl->value;
658 break;
659 case V4L2_CID_HUE:
660 cam->hue = ctrl->value;
661 break;
662 default:
663 ret = -EINVAL;
664 break;
665 }
666
667 if (ret == 0) {
668 w9966_pdev_claim(cam);
669
670 if (w9966_write_reg_i2c(cam, 0x0a, cam->brightness) == -1 ||
671 w9966_write_reg_i2c(cam, 0x0b, cam->contrast) == -1 ||
672 w9966_write_reg_i2c(cam, 0x0c, cam->color) == -1 ||
673 w9966_write_reg_i2c(cam, 0x0d, cam->hue) == -1) {
674 ret = -EIO;
675 }
676
677 w9966_pdev_release(cam);
678 }
679 mutex_unlock(&cam->lock);
680 return ret;
681}
682
683static int cam_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
684{
685 struct w9966 *cam = video_drvdata(file);
686 struct v4l2_pix_format *pix = &fmt->fmt.pix;
687
688 pix->width = cam->width;
689 pix->height = cam->height;
690 pix->pixelformat = V4L2_PIX_FMT_YUYV;
691 pix->field = V4L2_FIELD_NONE;
692 pix->bytesperline = 2 * cam->width;
693 pix->sizeimage = 2 * cam->width * cam->height;
694 /* Just a guess */
695 pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
706 return 0; 696 return 0;
707} 697}
708 698
709static long w9966_v4l_ioctl(struct file *file, 699static int cam_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
710 unsigned int cmd, unsigned long arg)
711{ 700{
712 return video_usercopy(file, cmd, arg, w9966_v4l_do_ioctl); 701 struct v4l2_pix_format *pix = &fmt->fmt.pix;
702
703 if (pix->width < 2)
704 pix->width = 2;
705 if (pix->height < 1)
706 pix->height = 1;
707 if (pix->width > W9966_WND_MAX_W)
708 pix->width = W9966_WND_MAX_W;
709 if (pix->height > W9966_WND_MAX_H)
710 pix->height = W9966_WND_MAX_H;
711 pix->pixelformat = V4L2_PIX_FMT_YUYV;
712 pix->field = V4L2_FIELD_NONE;
713 pix->bytesperline = 2 * pix->width;
714 pix->sizeimage = 2 * pix->width * pix->height;
715 /* Just a guess */
716 pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
717 return 0;
718}
719
720static int cam_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
721{
722 struct w9966 *cam = video_drvdata(file);
723 struct v4l2_pix_format *pix = &fmt->fmt.pix;
724 int ret = cam_try_fmt_vid_cap(file, fh, fmt);
725
726 if (ret)
727 return ret;
728
729 mutex_lock(&cam->lock);
730 /* Update camera regs */
731 w9966_pdev_claim(cam);
732 ret = w9966_setup(cam, 0, 0, 1023, 1023, pix->width, pix->height);
733 w9966_pdev_release(cam);
734 mutex_unlock(&cam->lock);
735 return ret;
736}
737
738static int cam_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *fmt)
739{
740 static struct v4l2_fmtdesc formats[] = {
741 { 0, 0, 0,
742 "YUV 4:2:2", V4L2_PIX_FMT_YUYV,
743 { 0, 0, 0, 0 }
744 },
745 };
746 enum v4l2_buf_type type = fmt->type;
747
748 if (fmt->index > 0)
749 return -EINVAL;
750
751 *fmt = formats[fmt->index];
752 fmt->type = type;
753 return 0;
713} 754}
714 755
715/* Capture data */ 756/* Capture data */
716static ssize_t w9966_v4l_read(struct file *file, char __user *buf, 757static ssize_t w9966_v4l_read(struct file *file, char __user *buf,
717 size_t count, loff_t *ppos) 758 size_t count, loff_t *ppos)
718{ 759{
719 struct w9966_dev *cam = video_drvdata(file); 760 struct w9966 *cam = video_drvdata(file);
720 unsigned char addr = 0xa0; /* ECP, read, CCD-transfer, 00000 */ 761 unsigned char addr = 0xa0; /* ECP, read, CCD-transfer, 00000 */
721 unsigned char __user *dest = (unsigned char __user *)buf; 762 unsigned char __user *dest = (unsigned char __user *)buf;
722 unsigned long dleft = count; 763 unsigned long dleft = count;
@@ -726,6 +767,7 @@ static ssize_t w9966_v4l_read(struct file *file, char __user *buf,
726 if (count > cam->width * cam->height * 2) 767 if (count > cam->width * cam->height * 2)
727 return -EINVAL; 768 return -EINVAL;
728 769
770 mutex_lock(&cam->lock);
729 w9966_pdev_claim(cam); 771 w9966_pdev_claim(cam);
730 w9966_write_reg(cam, 0x00, 0x02); /* Reset ECP-FIFO buffer */ 772 w9966_write_reg(cam, 0x00, 0x02); /* Reset ECP-FIFO buffer */
731 w9966_write_reg(cam, 0x00, 0x00); /* Return to normal operation */ 773 w9966_write_reg(cam, 0x00, 0x00); /* Return to normal operation */
@@ -736,6 +778,7 @@ static ssize_t w9966_v4l_read(struct file *file, char __user *buf,
736 (parport_write(cam->pport, &addr, 1) != 1) || 778 (parport_write(cam->pport, &addr, 1) != 1) ||
737 (parport_negotiate(cam->pport, cam->ppmode|IEEE1284_DATA) != 0)) { 779 (parport_negotiate(cam->pport, cam->ppmode|IEEE1284_DATA) != 0)) {
738 w9966_pdev_release(cam); 780 w9966_pdev_release(cam);
781 mutex_unlock(&cam->lock);
739 return -EFAULT; 782 return -EFAULT;
740 } 783 }
741 784
@@ -765,37 +808,29 @@ static ssize_t w9966_v4l_read(struct file *file, char __user *buf,
765out: 808out:
766 kfree(tbuf); 809 kfree(tbuf);
767 w9966_pdev_release(cam); 810 w9966_pdev_release(cam);
811 mutex_unlock(&cam->lock);
768 812
769 return count; 813 return count;
770} 814}
771 815
772static int w9966_exclusive_open(struct file *file)
773{
774 struct w9966_dev *cam = video_drvdata(file);
775
776 return test_and_set_bit(0, &cam->in_use) ? -EBUSY : 0;
777}
778
779static int w9966_exclusive_release(struct file *file)
780{
781 struct w9966_dev *cam = video_drvdata(file);
782
783 clear_bit(0, &cam->in_use);
784 return 0;
785}
786
787static const struct v4l2_file_operations w9966_fops = { 816static const struct v4l2_file_operations w9966_fops = {
788 .owner = THIS_MODULE, 817 .owner = THIS_MODULE,
789 .open = w9966_exclusive_open, 818 .ioctl = video_ioctl2,
790 .release = w9966_exclusive_release,
791 .ioctl = w9966_v4l_ioctl,
792 .read = w9966_v4l_read, 819 .read = w9966_v4l_read,
793}; 820};
794 821
795static struct video_device w9966_template = { 822static const struct v4l2_ioctl_ops w9966_ioctl_ops = {
796 .name = W9966_DRIVERNAME, 823 .vidioc_querycap = cam_querycap,
797 .fops = &w9966_fops, 824 .vidioc_g_input = cam_g_input,
798 .release = video_device_release_empty, 825 .vidioc_s_input = cam_s_input,
826 .vidioc_enum_input = cam_enum_input,
827 .vidioc_queryctrl = cam_queryctrl,
828 .vidioc_g_ctrl = cam_g_ctrl,
829 .vidioc_s_ctrl = cam_s_ctrl,
830 .vidioc_enum_fmt_vid_cap = cam_enum_fmt_vid_cap,
831 .vidioc_g_fmt_vid_cap = cam_g_fmt_vid_cap,
832 .vidioc_s_fmt_vid_cap = cam_s_fmt_vid_cap,
833 .vidioc_try_fmt_vid_cap = cam_try_fmt_vid_cap,
799}; 834};
800 835
801 836
@@ -803,11 +838,19 @@ static struct video_device w9966_template = {
803 default video mode, setup ccd-chip, register v4l device etc.. 838 default video mode, setup ccd-chip, register v4l device etc..
804 Also used for 'probing' of hardware. 839 Also used for 'probing' of hardware.
805 -1 on error */ 840 -1 on error */
806static int w9966_init(struct w9966_dev *cam, struct parport* port) 841static int w9966_init(struct w9966 *cam, struct parport *port)
807{ 842{
843 struct v4l2_device *v4l2_dev = &cam->v4l2_dev;
844
808 if (cam->dev_state != 0) 845 if (cam->dev_state != 0)
809 return -1; 846 return -1;
810 847
848 strlcpy(v4l2_dev->name, "w9966", sizeof(v4l2_dev->name));
849
850 if (v4l2_device_register(NULL, v4l2_dev) < 0) {
851 v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
852 return -1;
853 }
811 cam->pport = port; 854 cam->pport = port;
812 cam->brightness = 128; 855 cam->brightness = 128;
813 cam->contrast = 64; 856 cam->contrast = 64;
@@ -852,23 +895,29 @@ static int w9966_init(struct w9966_dev *cam, struct parport* port)
852 w9966_pdev_release(cam); 895 w9966_pdev_release(cam);
853 896
854 /* Fill in the video_device struct and register us to v4l */ 897 /* Fill in the video_device struct and register us to v4l */
855 memcpy(&cam->vdev, &w9966_template, sizeof(struct video_device)); 898 strlcpy(cam->vdev.name, W9966_DRIVERNAME, sizeof(cam->vdev.name));
899 cam->vdev.v4l2_dev = v4l2_dev;
900 cam->vdev.fops = &w9966_fops;
901 cam->vdev.ioctl_ops = &w9966_ioctl_ops;
902 cam->vdev.release = video_device_release_empty;
856 video_set_drvdata(&cam->vdev, cam); 903 video_set_drvdata(&cam->vdev, cam);
857 904
905 mutex_init(&cam->lock);
906
858 if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) 907 if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, video_nr) < 0)
859 return -1; 908 return -1;
860 909
861 w9966_set_state(cam, W9966_STATE_VDEV, W9966_STATE_VDEV); 910 w9966_set_state(cam, W9966_STATE_VDEV, W9966_STATE_VDEV);
862 911
863 /* All ok */ 912 /* All ok */
864 printk(KERN_INFO "w9966cf: Found and initialized a webcam on %s.\n", 913 v4l2_info(v4l2_dev, "Found and initialized a webcam on %s.\n",
865 cam->pport->name); 914 cam->pport->name);
866 return 0; 915 return 0;
867} 916}
868 917
869 918
870/* Terminate everything gracefully */ 919/* Terminate everything gracefully */
871static void w9966_term(struct w9966_dev *cam) 920static void w9966_term(struct w9966 *cam)
872{ 921{
873 /* Unregister from v4l */ 922 /* Unregister from v4l */
874 if (w9966_get_state(cam, W9966_STATE_VDEV, W9966_STATE_VDEV)) { 923 if (w9966_get_state(cam, W9966_STATE_VDEV, W9966_STATE_VDEV)) {