diff options
-rw-r--r-- | drivers/media/video/Kconfig | 2 | ||||
-rw-r--r-- | drivers/media/video/w9966.c | 435 |
2 files changed, 243 insertions, 194 deletions
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig index fe6771271b2d..67d31f6cc607 100644 --- a/drivers/media/video/Kconfig +++ b/drivers/media/video/Kconfig | |||
@@ -647,7 +647,7 @@ config VIDEO_CQCAM | |||
647 | 647 | ||
648 | config VIDEO_W9966 | 648 | config VIDEO_W9966 |
649 | tristate "W9966CF Webcam (FlyCam Supra and others) Video For Linux" | 649 | tristate "W9966CF Webcam (FlyCam Supra and others) Video For Linux" |
650 | depends on PARPORT_1284 && PARPORT && VIDEO_V4L1 | 650 | depends on PARPORT_1284 && PARPORT && VIDEO_V4L2 |
651 | help | 651 | help |
652 | Video4linux driver for Winbond's w9966 based Webcams. | 652 | Video4linux driver for Winbond's w9966 based Webcams. |
653 | Currently tested with the LifeView FlyCam Supra. | 653 | Currently tested with the LifeView FlyCam Supra. |
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 | ||
104 | struct w9966_dev { | 106 | struct 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"); | |||
144 | static int video_nr = -1; | 147 | static int video_nr = -1; |
145 | module_param(video_nr, int, 0); | 148 | module_param(video_nr, int, 0); |
146 | 149 | ||
147 | static struct w9966_dev w9966_cams[W9966_MAXCAMS]; | 150 | static 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 */ |
155 | static inline void w9966_set_state(struct w9966_dev *cam, int mask, int val) | 158 | static 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 */ |
161 | static inline int w9966_get_state(struct w9966_dev *cam, int mask, int val) | 164 | static 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 */ |
167 | static void w9966_pdev_claim(struct w9966_dev *cam) | 170 | static 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 */ |
176 | static void w9966_pdev_release(struct w9966_dev *cam) | 179 | static 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) */ |
187 | static int w9966_read_reg(struct w9966_dev *cam, int reg) | 190 | static 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 */ |
208 | static int w9966_write_reg(struct w9966_dev *cam, int reg, int data) | 211 | static 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. */ |
232 | static void w9966_i2c_setsda(struct w9966_dev *cam, int state) | 235 | static 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. */ |
245 | static int w9966_i2c_getscl(struct w9966_dev *cam) | 248 | static 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 */ |
253 | static int w9966_i2c_setscl(struct w9966_dev *cam, int state) | 256 | static 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. */ |
279 | static int w9966_i2c_getsda(struct w9966_dev *cam) | 282 | static 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 */ |
288 | static int w9966_i2c_wbyte(struct w9966_dev *cam, int data) | 291 | static 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 |
312 | static int w9966_i2c_rbyte(struct w9966_dev *cam) | 315 | static 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 |
335 | static int w9966_read_reg_i2c(struct w9966_dev *cam, int reg) | 338 | static 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 */ |
370 | static int w9966_write_reg_i2c(struct w9966_dev *cam, int reg, int data) | 373 | static 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 */ |
457 | static int w9966_setup(struct w9966_dev *cam, int x1, int y1, int x2, int y2, int w, int h) | 460 | static 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 | ||
560 | static long w9966_v4l_do_ioctl(struct file *file, unsigned int cmd, void *arg) | 563 | static 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, | 576 | static 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 | |||
589 | static int cam_g_input(struct file *file, void *fh, unsigned int *inp) | ||
590 | { | ||
591 | *inp = 0; | ||
592 | return 0; | ||
593 | } | ||
594 | |||
595 | static int cam_s_input(struct file *file, void *fh, unsigned int inp) | ||
596 | { | ||
597 | return (inp > 0) ? -EINVAL : 0; | ||
598 | } | ||
599 | |||
600 | static 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 | |||
616 | static 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 | |||
642 | static 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 | |||
683 | static 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 | ||
709 | static long w9966_v4l_ioctl(struct file *file, | 699 | static 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 | |||
720 | static 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 | |||
738 | static 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 */ |
716 | static ssize_t w9966_v4l_read(struct file *file, char __user *buf, | 757 | static 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, | |||
765 | out: | 808 | out: |
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 | ||
772 | static 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 | |||
779 | static 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 | |||
787 | static const struct v4l2_file_operations w9966_fops = { | 816 | static 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 | ||
795 | static struct video_device w9966_template = { | 822 | static 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 */ |
806 | static int w9966_init(struct w9966_dev *cam, struct parport* port) | 841 | static 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 */ |
871 | static void w9966_term(struct w9966_dev *cam) | 920 | static 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)) { |