GUI: Fix Tomato RAF theme for all builds. Compilation typo.
[tomato.git] / release / src-rt-6.x.4708 / linux / linux-2.6.36 / drivers / media / video / pwc / pwc-v4l.c
blobd8c7c5adfe5d5cae352f5ad83885b1df1ae23a63
1 /* Linux driver for Philips webcam
2 USB and Video4Linux interface part.
3 (C) 1999-2004 Nemosoft Unv.
4 (C) 2004-2006 Luc Saillard (luc@saillard.org)
6 NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
7 driver and thus may have bugs that are not present in the original version.
8 Please send bug reports and support requests to <luc@saillard.org>.
9 The decompression routines have been implemented by reverse-engineering the
10 Nemosoft binary pwcx module. Caveat emptor.
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 2 of the License, or
15 (at your option) any later version.
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to the Free Software
24 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 #include <linux/errno.h>
29 #include <linux/init.h>
30 #include <linux/mm.h>
31 #include <linux/module.h>
32 #include <linux/poll.h>
33 #include <linux/vmalloc.h>
34 #include <asm/io.h>
36 #include "pwc.h"
38 static struct v4l2_queryctrl pwc_controls[] = {
40 .id = V4L2_CID_BRIGHTNESS,
41 .type = V4L2_CTRL_TYPE_INTEGER,
42 .name = "Brightness",
43 .minimum = 0,
44 .maximum = 128,
45 .step = 1,
46 .default_value = 64,
49 .id = V4L2_CID_CONTRAST,
50 .type = V4L2_CTRL_TYPE_INTEGER,
51 .name = "Contrast",
52 .minimum = 0,
53 .maximum = 64,
54 .step = 1,
55 .default_value = 0,
58 .id = V4L2_CID_SATURATION,
59 .type = V4L2_CTRL_TYPE_INTEGER,
60 .name = "Saturation",
61 .minimum = -100,
62 .maximum = 100,
63 .step = 1,
64 .default_value = 0,
67 .id = V4L2_CID_GAMMA,
68 .type = V4L2_CTRL_TYPE_INTEGER,
69 .name = "Gamma",
70 .minimum = 0,
71 .maximum = 32,
72 .step = 1,
73 .default_value = 0,
76 .id = V4L2_CID_RED_BALANCE,
77 .type = V4L2_CTRL_TYPE_INTEGER,
78 .name = "Red Gain",
79 .minimum = 0,
80 .maximum = 256,
81 .step = 1,
82 .default_value = 0,
85 .id = V4L2_CID_BLUE_BALANCE,
86 .type = V4L2_CTRL_TYPE_INTEGER,
87 .name = "Blue Gain",
88 .minimum = 0,
89 .maximum = 256,
90 .step = 1,
91 .default_value = 0,
94 .id = V4L2_CID_AUTO_WHITE_BALANCE,
95 .type = V4L2_CTRL_TYPE_BOOLEAN,
96 .name = "Auto White Balance",
97 .minimum = 0,
98 .maximum = 1,
99 .step = 1,
100 .default_value = 0,
103 .id = V4L2_CID_EXPOSURE,
104 .type = V4L2_CTRL_TYPE_INTEGER,
105 .name = "Shutter Speed (Exposure)",
106 .minimum = 0,
107 .maximum = 256,
108 .step = 1,
109 .default_value = 200,
112 .id = V4L2_CID_AUTOGAIN,
113 .type = V4L2_CTRL_TYPE_BOOLEAN,
114 .name = "Auto Gain Enabled",
115 .minimum = 0,
116 .maximum = 1,
117 .step = 1,
118 .default_value = 1,
121 .id = V4L2_CID_GAIN,
122 .type = V4L2_CTRL_TYPE_INTEGER,
123 .name = "Gain Level",
124 .minimum = 0,
125 .maximum = 256,
126 .step = 1,
127 .default_value = 0,
130 .id = V4L2_CID_PRIVATE_SAVE_USER,
131 .type = V4L2_CTRL_TYPE_BUTTON,
132 .name = "Save User Settings",
133 .minimum = 0,
134 .maximum = 0,
135 .step = 0,
136 .default_value = 0,
139 .id = V4L2_CID_PRIVATE_RESTORE_USER,
140 .type = V4L2_CTRL_TYPE_BUTTON,
141 .name = "Restore User Settings",
142 .minimum = 0,
143 .maximum = 0,
144 .step = 0,
145 .default_value = 0,
148 .id = V4L2_CID_PRIVATE_RESTORE_FACTORY,
149 .type = V4L2_CTRL_TYPE_BUTTON,
150 .name = "Restore Factory Settings",
151 .minimum = 0,
152 .maximum = 0,
153 .step = 0,
154 .default_value = 0,
157 .id = V4L2_CID_PRIVATE_COLOUR_MODE,
158 .type = V4L2_CTRL_TYPE_BOOLEAN,
159 .name = "Colour mode",
160 .minimum = 0,
161 .maximum = 1,
162 .step = 1,
163 .default_value = 0,
166 .id = V4L2_CID_PRIVATE_AUTOCONTOUR,
167 .type = V4L2_CTRL_TYPE_BOOLEAN,
168 .name = "Auto contour",
169 .minimum = 0,
170 .maximum = 1,
171 .step = 1,
172 .default_value = 0,
175 .id = V4L2_CID_PRIVATE_CONTOUR,
176 .type = V4L2_CTRL_TYPE_INTEGER,
177 .name = "Contour",
178 .minimum = 0,
179 .maximum = 63,
180 .step = 1,
181 .default_value = 0,
184 .id = V4L2_CID_PRIVATE_BACKLIGHT,
185 .type = V4L2_CTRL_TYPE_BOOLEAN,
186 .name = "Backlight compensation",
187 .minimum = 0,
188 .maximum = 1,
189 .step = 1,
190 .default_value = 0,
193 .id = V4L2_CID_PRIVATE_FLICKERLESS,
194 .type = V4L2_CTRL_TYPE_BOOLEAN,
195 .name = "Flickerless",
196 .minimum = 0,
197 .maximum = 1,
198 .step = 1,
199 .default_value = 0,
202 .id = V4L2_CID_PRIVATE_NOISE_REDUCTION,
203 .type = V4L2_CTRL_TYPE_INTEGER,
204 .name = "Noise reduction",
205 .minimum = 0,
206 .maximum = 3,
207 .step = 1,
208 .default_value = 0,
213 static void pwc_vidioc_fill_fmt(const struct pwc_device *pdev, struct v4l2_format *f)
215 memset(&f->fmt.pix, 0, sizeof(struct v4l2_pix_format));
216 f->fmt.pix.width = pdev->view.x;
217 f->fmt.pix.height = pdev->view.y;
218 f->fmt.pix.field = V4L2_FIELD_NONE;
219 if (pdev->vpalette == VIDEO_PALETTE_YUV420P) {
220 f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420;
221 f->fmt.pix.bytesperline = (f->fmt.pix.width * 3)/2;
222 f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
223 } else {
224 /* vbandlength contains 4 lines ... */
225 f->fmt.pix.bytesperline = pdev->vbandlength/4;
226 f->fmt.pix.sizeimage = pdev->frame_size + sizeof(struct pwc_raw_frame);
227 if (DEVICE_USE_CODEC1(pdev->type))
228 f->fmt.pix.pixelformat = V4L2_PIX_FMT_PWC1;
229 else
230 f->fmt.pix.pixelformat = V4L2_PIX_FMT_PWC2;
232 PWC_DEBUG_IOCTL("pwc_vidioc_fill_fmt() "
233 "width=%d, height=%d, bytesperline=%d, sizeimage=%d, pixelformat=%c%c%c%c\n",
234 f->fmt.pix.width,
235 f->fmt.pix.height,
236 f->fmt.pix.bytesperline,
237 f->fmt.pix.sizeimage,
238 (f->fmt.pix.pixelformat)&255,
239 (f->fmt.pix.pixelformat>>8)&255,
240 (f->fmt.pix.pixelformat>>16)&255,
241 (f->fmt.pix.pixelformat>>24)&255);
244 /* ioctl(VIDIOC_TRY_FMT) */
245 static int pwc_vidioc_try_fmt(struct pwc_device *pdev, struct v4l2_format *f)
247 if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
248 PWC_DEBUG_IOCTL("Bad video type must be V4L2_BUF_TYPE_VIDEO_CAPTURE\n");
249 return -EINVAL;
252 switch (f->fmt.pix.pixelformat) {
253 case V4L2_PIX_FMT_YUV420:
254 break;
255 case V4L2_PIX_FMT_PWC1:
256 if (DEVICE_USE_CODEC23(pdev->type)) {
257 PWC_DEBUG_IOCTL("codec1 is only supported for old pwc webcam\n");
258 return -EINVAL;
260 break;
261 case V4L2_PIX_FMT_PWC2:
262 if (DEVICE_USE_CODEC1(pdev->type)) {
263 PWC_DEBUG_IOCTL("codec23 is only supported for new pwc webcam\n");
264 return -EINVAL;
266 break;
267 default:
268 PWC_DEBUG_IOCTL("Unsupported pixel format\n");
269 return -EINVAL;
273 if (f->fmt.pix.width > pdev->view_max.x)
274 f->fmt.pix.width = pdev->view_max.x;
275 else if (f->fmt.pix.width < pdev->view_min.x)
276 f->fmt.pix.width = pdev->view_min.x;
278 if (f->fmt.pix.height > pdev->view_max.y)
279 f->fmt.pix.height = pdev->view_max.y;
280 else if (f->fmt.pix.height < pdev->view_min.y)
281 f->fmt.pix.height = pdev->view_min.y;
283 return 0;
286 /* ioctl(VIDIOC_SET_FMT) */
287 static int pwc_vidioc_set_fmt(struct pwc_device *pdev, struct v4l2_format *f)
289 int ret, fps, snapshot, compression, pixelformat;
291 ret = pwc_vidioc_try_fmt(pdev, f);
292 if (ret<0)
293 return ret;
295 pixelformat = f->fmt.pix.pixelformat;
296 compression = pdev->vcompression;
297 snapshot = 0;
298 fps = pdev->vframes;
299 if (f->fmt.pix.priv) {
300 compression = (f->fmt.pix.priv & PWC_QLT_MASK) >> PWC_QLT_SHIFT;
301 snapshot = !!(f->fmt.pix.priv & PWC_FPS_SNAPSHOT);
302 fps = (f->fmt.pix.priv & PWC_FPS_FRMASK) >> PWC_FPS_SHIFT;
303 if (fps == 0)
304 fps = pdev->vframes;
307 if (pixelformat == V4L2_PIX_FMT_YUV420)
308 pdev->vpalette = VIDEO_PALETTE_YUV420P;
309 else
310 pdev->vpalette = VIDEO_PALETTE_RAW;
312 PWC_DEBUG_IOCTL("Try to change format to: width=%d height=%d fps=%d "
313 "compression=%d snapshot=%d format=%c%c%c%c\n",
314 f->fmt.pix.width, f->fmt.pix.height, fps,
315 compression, snapshot,
316 (pixelformat)&255,
317 (pixelformat>>8)&255,
318 (pixelformat>>16)&255,
319 (pixelformat>>24)&255);
321 ret = pwc_try_video_mode(pdev,
322 f->fmt.pix.width,
323 f->fmt.pix.height,
324 fps,
325 compression,
326 snapshot);
328 PWC_DEBUG_IOCTL("pwc_try_video_mode(), return=%d\n", ret);
330 if (ret)
331 return ret;
333 pwc_vidioc_fill_fmt(pdev, f);
335 return 0;
339 long pwc_video_do_ioctl(struct file *file, unsigned int cmd, void *arg)
341 struct video_device *vdev = video_devdata(file);
342 struct pwc_device *pdev;
343 DECLARE_WAITQUEUE(wait, current);
345 if (vdev == NULL)
346 return -EFAULT;
347 pdev = video_get_drvdata(vdev);
348 if (pdev == NULL)
349 return -EFAULT;
351 #ifdef CONFIG_USB_PWC_DEBUG
352 if (PWC_DEBUG_LEVEL_IOCTL & pwc_trace) {
353 v4l_printk_ioctl(cmd);
354 printk("\n");
356 #endif
359 switch (cmd) {
360 /* Query cabapilities */
361 case VIDIOCGCAP:
363 struct video_capability *caps = arg;
365 strcpy(caps->name, vdev->name);
366 caps->type = VID_TYPE_CAPTURE;
367 caps->channels = 1;
368 caps->audios = 1;
369 caps->minwidth = pdev->view_min.x;
370 caps->minheight = pdev->view_min.y;
371 caps->maxwidth = pdev->view_max.x;
372 caps->maxheight = pdev->view_max.y;
373 break;
376 /* Channel functions (simulate 1 channel) */
377 case VIDIOCGCHAN:
379 struct video_channel *v = arg;
381 if (v->channel != 0)
382 return -EINVAL;
383 v->flags = 0;
384 v->tuners = 0;
385 v->type = VIDEO_TYPE_CAMERA;
386 strcpy(v->name, "Webcam");
387 return 0;
390 case VIDIOCSCHAN:
392 /* The spec says the argument is an integer, but
393 the bttv driver uses a video_channel arg, which
394 makes sense becasue it also has the norm flag.
396 struct video_channel *v = arg;
397 if (v->channel != 0)
398 return -EINVAL;
399 return 0;
403 /* Picture functions; contrast etc. */
404 case VIDIOCGPICT:
406 struct video_picture *p = arg;
407 int val;
409 val = pwc_get_brightness(pdev);
410 if (val >= 0)
411 p->brightness = (val<<9);
412 else
413 p->brightness = 0xffff;
414 val = pwc_get_contrast(pdev);
415 if (val >= 0)
416 p->contrast = (val<<10);
417 else
418 p->contrast = 0xffff;
419 /* Gamma, Whiteness, what's the difference? :) */
420 val = pwc_get_gamma(pdev);
421 if (val >= 0)
422 p->whiteness = (val<<11);
423 else
424 p->whiteness = 0xffff;
425 if (pwc_get_saturation(pdev, &val)<0)
426 p->colour = 0xffff;
427 else
428 p->colour = 32768 + val * 327;
429 p->depth = 24;
430 p->palette = pdev->vpalette;
431 p->hue = 0xFFFF; /* N/A */
432 break;
435 case VIDIOCSPICT:
437 struct video_picture *p = arg;
438 pwc_set_brightness(pdev, p->brightness);
439 pwc_set_contrast(pdev, p->contrast);
440 pwc_set_gamma(pdev, p->whiteness);
441 pwc_set_saturation(pdev, (p->colour-32768)/327);
442 if (p->palette && p->palette != pdev->vpalette) {
443 switch (p->palette) {
444 case VIDEO_PALETTE_YUV420P:
445 case VIDEO_PALETTE_RAW:
446 pdev->vpalette = p->palette;
447 return pwc_try_video_mode(pdev, pdev->image.x, pdev->image.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
448 break;
449 default:
450 return -EINVAL;
451 break;
454 break;
457 /* Window/size parameters */
458 case VIDIOCGWIN:
460 struct video_window *vw = arg;
462 vw->x = 0;
463 vw->y = 0;
464 vw->width = pdev->view.x;
465 vw->height = pdev->view.y;
466 vw->chromakey = 0;
467 vw->flags = (pdev->vframes << PWC_FPS_SHIFT) |
468 (pdev->vsnapshot ? PWC_FPS_SNAPSHOT : 0);
469 break;
472 case VIDIOCSWIN:
474 struct video_window *vw = arg;
475 int fps, snapshot, ret;
477 fps = (vw->flags & PWC_FPS_FRMASK) >> PWC_FPS_SHIFT;
478 snapshot = vw->flags & PWC_FPS_SNAPSHOT;
479 if (fps == 0)
480 fps = pdev->vframes;
481 if (pdev->view.x == vw->width && pdev->view.y && fps == pdev->vframes && snapshot == pdev->vsnapshot)
482 return 0;
483 ret = pwc_try_video_mode(pdev, vw->width, vw->height, fps, pdev->vcompression, snapshot);
484 if (ret)
485 return ret;
486 break;
489 /* We don't have overlay support (yet) */
490 case VIDIOCGFBUF:
492 struct video_buffer *vb = arg;
494 memset(vb,0,sizeof(*vb));
495 break;
498 /* mmap() functions */
499 case VIDIOCGMBUF:
501 /* Tell the user program how much memory is needed for a mmap() */
502 struct video_mbuf *vm = arg;
503 int i;
505 memset(vm, 0, sizeof(*vm));
506 vm->size = pwc_mbufs * pdev->len_per_image;
507 vm->frames = pwc_mbufs; /* double buffering should be enough for most applications */
508 for (i = 0; i < pwc_mbufs; i++)
509 vm->offsets[i] = i * pdev->len_per_image;
510 break;
513 case VIDIOCMCAPTURE:
515 /* Start capture into a given image buffer (called 'frame' in video_mmap structure) */
516 struct video_mmap *vm = arg;
518 PWC_DEBUG_READ("VIDIOCMCAPTURE: %dx%d, frame %d, format %d\n", vm->width, vm->height, vm->frame, vm->format);
519 if (vm->frame < 0 || vm->frame >= pwc_mbufs)
520 return -EINVAL;
522 /* xawtv is nasty. It probes the available palettes
523 by setting a very small image size and trying
524 various palettes... The driver doesn't support
525 such small images, so I'm working around it.
527 if (vm->format)
529 switch (vm->format)
531 case VIDEO_PALETTE_YUV420P:
532 case VIDEO_PALETTE_RAW:
533 break;
534 default:
535 return -EINVAL;
536 break;
540 if ((vm->width != pdev->view.x || vm->height != pdev->view.y) &&
541 (vm->width >= pdev->view_min.x && vm->height >= pdev->view_min.y)) {
542 int ret;
544 PWC_DEBUG_OPEN("VIDIOCMCAPTURE: changing size to please xawtv :-(.\n");
545 ret = pwc_try_video_mode(pdev, vm->width, vm->height, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
546 if (ret)
547 return ret;
548 } /* ... size mismatch */
550 if (pdev->image_used[vm->frame])
551 return -EBUSY; /* buffer wasn't available. Bummer */
552 pdev->image_used[vm->frame] = 1;
554 /* Okay, we're done here. In the SYNC call we wait until a
555 frame comes available, then expand image into the given
556 buffer.
557 In contrast to the CPiA cam the Philips cams deliver a
558 constant stream, almost like a grabber card. Also,
559 we have separate buffers for the rawdata and the image,
560 meaning we can nearly always expand into the requested buffer.
562 PWC_DEBUG_READ("VIDIOCMCAPTURE done.\n");
563 break;
566 case VIDIOCSYNC:
568 /* The doc says: "Whenever a buffer is used it should
569 call VIDIOCSYNC to free this frame up and continue."
571 The only odd thing about this whole procedure is
572 that MCAPTURE flags the buffer as "in use", and
573 SYNC immediately unmarks it, while it isn't
574 after SYNC that you know that the buffer actually
575 got filled! So you better not start a CAPTURE in
576 the same frame immediately (use double buffering).
577 This is not a problem for this cam, since it has
578 extra intermediate buffers, but a hardware
579 grabber card will then overwrite the buffer
580 you're working on.
582 int *mbuf = arg;
583 int ret;
585 PWC_DEBUG_READ("VIDIOCSYNC called (%d).\n", *mbuf);
587 /* bounds check */
588 if (*mbuf < 0 || *mbuf >= pwc_mbufs)
589 return -EINVAL;
590 /* check if this buffer was requested anyway */
591 if (pdev->image_used[*mbuf] == 0)
592 return -EINVAL;
594 add_wait_queue(&pdev->frameq, &wait);
595 while (pdev->full_frames == NULL) {
596 /* Check for unplugged/etc. here */
597 if (pdev->error_status) {
598 remove_wait_queue(&pdev->frameq, &wait);
599 set_current_state(TASK_RUNNING);
600 return -pdev->error_status;
603 if (signal_pending(current)) {
604 remove_wait_queue(&pdev->frameq, &wait);
605 set_current_state(TASK_RUNNING);
606 return -ERESTARTSYS;
608 schedule();
609 set_current_state(TASK_INTERRUPTIBLE);
611 remove_wait_queue(&pdev->frameq, &wait);
612 set_current_state(TASK_RUNNING);
614 /* The frame is ready. Expand in the image buffer
615 requested by the user. I don't care if you
616 mmap() 5 buffers and request data in this order:
617 buffer 4 2 3 0 1 2 3 0 4 3 1 . . .
618 Grabber hardware may not be so forgiving.
620 PWC_DEBUG_READ("VIDIOCSYNC: frame ready.\n");
621 pdev->fill_image = *mbuf; /* tell in which buffer we want the image to be expanded */
622 /* Decompress, etc */
623 ret = pwc_handle_frame(pdev);
624 pdev->image_used[*mbuf] = 0;
625 if (ret)
626 return -EFAULT;
627 break;
630 case VIDIOCGAUDIO:
632 struct video_audio *v = arg;
634 strcpy(v->name, "Microphone");
635 v->audio = -1; /* unknown audio minor */
636 v->flags = 0;
637 v->mode = VIDEO_SOUND_MONO;
638 v->volume = 0;
639 v->bass = 0;
640 v->treble = 0;
641 v->balance = 0x8000;
642 v->step = 1;
643 break;
646 case VIDIOCSAUDIO:
648 /* Dummy: nothing can be set */
649 break;
652 case VIDIOCGUNIT:
654 struct video_unit *vu = arg;
656 vu->video = pdev->vdev->minor & 0x3F;
657 vu->audio = -1; /* not known yet */
658 vu->vbi = -1;
659 vu->radio = -1;
660 vu->teletext = -1;
661 break;
664 /* V4L2 Layer */
665 case VIDIOC_QUERYCAP:
667 struct v4l2_capability *cap = arg;
669 PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCAP) This application "\
670 "try to use the v4l2 layer\n");
671 strcpy(cap->driver,PWC_NAME);
672 strlcpy(cap->card, vdev->name, sizeof(cap->card));
673 usb_make_path(pdev->udev,cap->bus_info,sizeof(cap->bus_info));
674 cap->version = PWC_VERSION_CODE;
675 cap->capabilities =
676 V4L2_CAP_VIDEO_CAPTURE |
677 V4L2_CAP_STREAMING |
678 V4L2_CAP_READWRITE;
679 return 0;
682 case VIDIOC_ENUMINPUT:
684 struct v4l2_input *i = arg;
686 if ( i->index ) /* Only one INPUT is supported */
687 return -EINVAL;
689 memset(i, 0, sizeof(struct v4l2_input));
690 strcpy(i->name, "usb");
691 return 0;
694 case VIDIOC_G_INPUT:
696 int *i = arg;
697 *i = 0; /* Only one INPUT is supported */
698 return 0;
700 case VIDIOC_S_INPUT:
702 int *i = arg;
704 if ( *i ) { /* Only one INPUT is supported */
705 PWC_DEBUG_IOCTL("Only one input source is"\
706 " supported with this webcam.\n");
707 return -EINVAL;
709 return 0;
712 /* TODO: */
713 case VIDIOC_QUERYCTRL:
715 struct v4l2_queryctrl *c = arg;
716 int i;
718 PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) query id=%d\n", c->id);
719 for (i=0; i<sizeof(pwc_controls)/sizeof(struct v4l2_queryctrl); i++) {
720 if (pwc_controls[i].id == c->id) {
721 PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) found\n");
722 memcpy(c,&pwc_controls[i],sizeof(struct v4l2_queryctrl));
723 return 0;
726 PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) not found\n");
728 return -EINVAL;
730 case VIDIOC_G_CTRL:
732 struct v4l2_control *c = arg;
733 int ret;
735 switch (c->id)
737 case V4L2_CID_BRIGHTNESS:
738 c->value = pwc_get_brightness(pdev);
739 if (c->value<0)
740 return -EINVAL;
741 return 0;
742 case V4L2_CID_CONTRAST:
743 c->value = pwc_get_contrast(pdev);
744 if (c->value<0)
745 return -EINVAL;
746 return 0;
747 case V4L2_CID_SATURATION:
748 ret = pwc_get_saturation(pdev, &c->value);
749 if (ret<0)
750 return -EINVAL;
751 return 0;
752 case V4L2_CID_GAMMA:
753 c->value = pwc_get_gamma(pdev);
754 if (c->value<0)
755 return -EINVAL;
756 return 0;
757 case V4L2_CID_RED_BALANCE:
758 ret = pwc_get_red_gain(pdev, &c->value);
759 if (ret<0)
760 return -EINVAL;
761 c->value >>= 8;
762 return 0;
763 case V4L2_CID_BLUE_BALANCE:
764 ret = pwc_get_blue_gain(pdev, &c->value);
765 if (ret<0)
766 return -EINVAL;
767 c->value >>= 8;
768 return 0;
769 case V4L2_CID_AUTO_WHITE_BALANCE:
770 ret = pwc_get_awb(pdev);
771 if (ret<0)
772 return -EINVAL;
773 c->value = (ret == PWC_WB_MANUAL)?0:1;
774 return 0;
775 case V4L2_CID_GAIN:
776 ret = pwc_get_agc(pdev, &c->value);
777 if (ret<0)
778 return -EINVAL;
779 c->value >>= 8;
780 return 0;
781 case V4L2_CID_AUTOGAIN:
782 ret = pwc_get_agc(pdev, &c->value);
783 if (ret<0)
784 return -EINVAL;
785 c->value = (c->value < 0)?1:0;
786 return 0;
787 case V4L2_CID_EXPOSURE:
788 ret = pwc_get_shutter_speed(pdev, &c->value);
789 if (ret<0)
790 return -EINVAL;
791 return 0;
792 case V4L2_CID_PRIVATE_COLOUR_MODE:
793 ret = pwc_get_colour_mode(pdev, &c->value);
794 if (ret < 0)
795 return -EINVAL;
796 return 0;
797 case V4L2_CID_PRIVATE_AUTOCONTOUR:
798 ret = pwc_get_contour(pdev, &c->value);
799 if (ret < 0)
800 return -EINVAL;
801 c->value=(c->value == -1?1:0);
802 return 0;
803 case V4L2_CID_PRIVATE_CONTOUR:
804 ret = pwc_get_contour(pdev, &c->value);
805 if (ret < 0)
806 return -EINVAL;
807 c->value >>= 10;
808 return 0;
809 case V4L2_CID_PRIVATE_BACKLIGHT:
810 ret = pwc_get_backlight(pdev, &c->value);
811 if (ret < 0)
812 return -EINVAL;
813 return 0;
814 case V4L2_CID_PRIVATE_FLICKERLESS:
815 ret = pwc_get_flicker(pdev, &c->value);
816 if (ret < 0)
817 return -EINVAL;
818 c->value=(c->value?1:0);
819 return 0;
820 case V4L2_CID_PRIVATE_NOISE_REDUCTION:
821 ret = pwc_get_dynamic_noise(pdev, &c->value);
822 if (ret < 0)
823 return -EINVAL;
824 return 0;
826 case V4L2_CID_PRIVATE_SAVE_USER:
827 case V4L2_CID_PRIVATE_RESTORE_USER:
828 case V4L2_CID_PRIVATE_RESTORE_FACTORY:
829 return -EINVAL;
831 return -EINVAL;
833 case VIDIOC_S_CTRL:
835 struct v4l2_control *c = arg;
836 int ret;
838 switch (c->id)
840 case V4L2_CID_BRIGHTNESS:
841 c->value <<= 9;
842 ret = pwc_set_brightness(pdev, c->value);
843 if (ret<0)
844 return -EINVAL;
845 return 0;
846 case V4L2_CID_CONTRAST:
847 c->value <<= 10;
848 ret = pwc_set_contrast(pdev, c->value);
849 if (ret<0)
850 return -EINVAL;
851 return 0;
852 case V4L2_CID_SATURATION:
853 ret = pwc_set_saturation(pdev, c->value);
854 if (ret<0)
855 return -EINVAL;
856 return 0;
857 case V4L2_CID_GAMMA:
858 c->value <<= 11;
859 ret = pwc_set_gamma(pdev, c->value);
860 if (ret<0)
861 return -EINVAL;
862 return 0;
863 case V4L2_CID_RED_BALANCE:
864 c->value <<= 8;
865 ret = pwc_set_red_gain(pdev, c->value);
866 if (ret<0)
867 return -EINVAL;
868 return 0;
869 case V4L2_CID_BLUE_BALANCE:
870 c->value <<= 8;
871 ret = pwc_set_blue_gain(pdev, c->value);
872 if (ret<0)
873 return -EINVAL;
874 return 0;
875 case V4L2_CID_AUTO_WHITE_BALANCE:
876 c->value = (c->value == 0)?PWC_WB_MANUAL:PWC_WB_AUTO;
877 ret = pwc_set_awb(pdev, c->value);
878 if (ret<0)
879 return -EINVAL;
880 return 0;
881 case V4L2_CID_EXPOSURE:
882 c->value <<= 8;
883 ret = pwc_set_shutter_speed(pdev, c->value?0:1, c->value);
884 if (ret<0)
885 return -EINVAL;
886 return 0;
887 case V4L2_CID_AUTOGAIN:
888 /* autogain off means nothing without a gain */
889 if (c->value == 0)
890 return 0;
891 ret = pwc_set_agc(pdev, c->value, 0);
892 if (ret<0)
893 return -EINVAL;
894 return 0;
895 case V4L2_CID_GAIN:
896 c->value <<= 8;
897 ret = pwc_set_agc(pdev, 0, c->value);
898 if (ret<0)
899 return -EINVAL;
900 return 0;
901 case V4L2_CID_PRIVATE_SAVE_USER:
902 if (pwc_save_user(pdev))
903 return -EINVAL;
904 return 0;
905 case V4L2_CID_PRIVATE_RESTORE_USER:
906 if (pwc_restore_user(pdev))
907 return -EINVAL;
908 return 0;
909 case V4L2_CID_PRIVATE_RESTORE_FACTORY:
910 if (pwc_restore_factory(pdev))
911 return -EINVAL;
912 return 0;
913 case V4L2_CID_PRIVATE_COLOUR_MODE:
914 ret = pwc_set_colour_mode(pdev, c->value);
915 if (ret < 0)
916 return -EINVAL;
917 return 0;
918 case V4L2_CID_PRIVATE_AUTOCONTOUR:
919 c->value=(c->value == 1)?-1:0;
920 ret = pwc_set_contour(pdev, c->value);
921 if (ret < 0)
922 return -EINVAL;
923 return 0;
924 case V4L2_CID_PRIVATE_CONTOUR:
925 c->value <<= 10;
926 ret = pwc_set_contour(pdev, c->value);
927 if (ret < 0)
928 return -EINVAL;
929 return 0;
930 case V4L2_CID_PRIVATE_BACKLIGHT:
931 ret = pwc_set_backlight(pdev, c->value);
932 if (ret < 0)
933 return -EINVAL;
934 return 0;
935 case V4L2_CID_PRIVATE_FLICKERLESS:
936 ret = pwc_set_flicker(pdev, c->value);
937 if (ret < 0)
938 return -EINVAL;
939 case V4L2_CID_PRIVATE_NOISE_REDUCTION:
940 ret = pwc_set_dynamic_noise(pdev, c->value);
941 if (ret < 0)
942 return -EINVAL;
943 return 0;
946 return -EINVAL;
949 case VIDIOC_ENUM_FMT:
951 struct v4l2_fmtdesc *f = arg;
952 int index;
954 if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
955 return -EINVAL;
957 /* We only support two format: the raw format, and YUV */
958 index = f->index;
959 memset(f,0,sizeof(struct v4l2_fmtdesc));
960 f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
961 f->index = index;
962 switch(index)
964 case 0:
965 /* RAW format */
966 f->pixelformat = pdev->type<=646?V4L2_PIX_FMT_PWC1:V4L2_PIX_FMT_PWC2;
967 f->flags = V4L2_FMT_FLAG_COMPRESSED;
968 strlcpy(f->description,"Raw Philips Webcam",sizeof(f->description));
969 break;
970 case 1:
971 f->pixelformat = V4L2_PIX_FMT_YUV420;
972 strlcpy(f->description,"4:2:0, planar, Y-Cb-Cr",sizeof(f->description));
973 break;
974 default:
975 return -EINVAL;
977 return 0;
980 case VIDIOC_G_FMT:
982 struct v4l2_format *f = arg;
984 PWC_DEBUG_IOCTL("ioctl(VIDIOC_G_FMT) return size %dx%d\n",pdev->image.x,pdev->image.y);
985 if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
986 return -EINVAL;
988 pwc_vidioc_fill_fmt(pdev, f);
990 return 0;
993 case VIDIOC_TRY_FMT:
994 return pwc_vidioc_try_fmt(pdev, arg);
996 case VIDIOC_S_FMT:
997 return pwc_vidioc_set_fmt(pdev, arg);
999 case VIDIOC_G_STD:
1001 v4l2_std_id *std = arg;
1002 *std = V4L2_STD_UNKNOWN;
1003 return 0;
1006 case VIDIOC_S_STD:
1008 v4l2_std_id *std = arg;
1009 if (*std != V4L2_STD_UNKNOWN)
1010 return -EINVAL;
1011 return 0;
1014 case VIDIOC_ENUMSTD:
1016 struct v4l2_standard *std = arg;
1017 if (std->index != 0)
1018 return -EINVAL;
1019 std->id = V4L2_STD_UNKNOWN;
1020 strlcpy(std->name, "webcam", sizeof(std->name));
1021 return 0;
1024 case VIDIOC_REQBUFS:
1026 struct v4l2_requestbuffers *rb = arg;
1027 int nbuffers;
1029 PWC_DEBUG_IOCTL("ioctl(VIDIOC_REQBUFS) count=%d\n",rb->count);
1030 if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1031 return -EINVAL;
1032 if (rb->memory != V4L2_MEMORY_MMAP)
1033 return -EINVAL;
1035 nbuffers = rb->count;
1036 if (nbuffers < 2)
1037 nbuffers = 2;
1038 else if (nbuffers > pwc_mbufs)
1039 nbuffers = pwc_mbufs;
1040 /* Force to use our # of buffers */
1041 rb->count = pwc_mbufs;
1042 return 0;
1045 case VIDIOC_QUERYBUF:
1047 struct v4l2_buffer *buf = arg;
1048 int index;
1050 PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) index=%d\n",buf->index);
1051 if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
1052 PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad type\n");
1053 return -EINVAL;
1055 if (buf->memory != V4L2_MEMORY_MMAP) {
1056 PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad memory type\n");
1057 return -EINVAL;
1059 index = buf->index;
1060 if (index < 0 || index >= pwc_mbufs) {
1061 PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad index %d\n", buf->index);
1062 return -EINVAL;
1065 memset(buf, 0, sizeof(struct v4l2_buffer));
1066 buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1067 buf->index = index;
1068 buf->m.offset = index * pdev->len_per_image;
1069 if (pdev->vpalette == VIDEO_PALETTE_RAW)
1070 buf->bytesused = pdev->frame_size + sizeof(struct pwc_raw_frame);
1071 else
1072 buf->bytesused = pdev->view.size;
1073 buf->field = V4L2_FIELD_NONE;
1074 buf->memory = V4L2_MEMORY_MMAP;
1075 //buf->flags = V4L2_BUF_FLAG_MAPPED;
1076 buf->length = pdev->len_per_image;
1078 PWC_DEBUG_READ("VIDIOC_QUERYBUF: index=%d\n",buf->index);
1079 PWC_DEBUG_READ("VIDIOC_QUERYBUF: m.offset=%d\n",buf->m.offset);
1080 PWC_DEBUG_READ("VIDIOC_QUERYBUF: bytesused=%d\n",buf->bytesused);
1082 return 0;
1085 case VIDIOC_QBUF:
1087 struct v4l2_buffer *buf = arg;
1089 PWC_DEBUG_IOCTL("ioctl(VIDIOC_QBUF) index=%d\n",buf->index);
1090 if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1091 return -EINVAL;
1092 if (buf->memory != V4L2_MEMORY_MMAP)
1093 return -EINVAL;
1094 if (buf->index >= pwc_mbufs)
1095 return -EINVAL;
1097 buf->flags |= V4L2_BUF_FLAG_QUEUED;
1098 buf->flags &= ~V4L2_BUF_FLAG_DONE;
1100 return 0;
1103 case VIDIOC_DQBUF:
1105 struct v4l2_buffer *buf = arg;
1106 int ret;
1108 PWC_DEBUG_IOCTL("ioctl(VIDIOC_DQBUF)\n");
1110 if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1111 return -EINVAL;
1113 add_wait_queue(&pdev->frameq, &wait);
1114 while (pdev->full_frames == NULL) {
1115 if (pdev->error_status) {
1116 remove_wait_queue(&pdev->frameq, &wait);
1117 set_current_state(TASK_RUNNING);
1118 return -pdev->error_status;
1121 if (signal_pending(current)) {
1122 remove_wait_queue(&pdev->frameq, &wait);
1123 set_current_state(TASK_RUNNING);
1124 return -ERESTARTSYS;
1126 schedule();
1127 set_current_state(TASK_INTERRUPTIBLE);
1129 remove_wait_queue(&pdev->frameq, &wait);
1130 set_current_state(TASK_RUNNING);
1132 PWC_DEBUG_IOCTL("VIDIOC_DQBUF: frame ready.\n");
1133 /* Decompress data in pdev->images[pdev->fill_image] */
1134 ret = pwc_handle_frame(pdev);
1135 if (ret)
1136 return -EFAULT;
1137 PWC_DEBUG_IOCTL("VIDIOC_DQBUF: after pwc_handle_frame\n");
1139 buf->index = pdev->fill_image;
1140 if (pdev->vpalette == VIDEO_PALETTE_RAW)
1141 buf->bytesused = pdev->frame_size + sizeof(struct pwc_raw_frame);
1142 else
1143 buf->bytesused = pdev->view.size;
1144 buf->flags = V4L2_BUF_FLAG_MAPPED;
1145 buf->field = V4L2_FIELD_NONE;
1146 do_gettimeofday(&buf->timestamp);
1147 buf->sequence = 0;
1148 buf->memory = V4L2_MEMORY_MMAP;
1149 buf->m.offset = pdev->fill_image * pdev->len_per_image;
1150 buf->length = pdev->len_per_image;
1151 pwc_next_image(pdev);
1153 PWC_DEBUG_IOCTL("VIDIOC_DQBUF: buf->index=%d\n",buf->index);
1154 PWC_DEBUG_IOCTL("VIDIOC_DQBUF: buf->length=%d\n",buf->length);
1155 PWC_DEBUG_IOCTL("VIDIOC_DQBUF: m.offset=%d\n",buf->m.offset);
1156 PWC_DEBUG_IOCTL("VIDIOC_DQBUF: bytesused=%d\n",buf->bytesused);
1157 PWC_DEBUG_IOCTL("VIDIOC_DQBUF: leaving\n");
1158 return 0;
1162 case VIDIOC_STREAMON:
1164 /* WARNING: pwc_try_video_mode() called pwc_isoc_init */
1165 pwc_isoc_init(pdev);
1166 return 0;
1169 case VIDIOC_STREAMOFF:
1171 pwc_isoc_cleanup(pdev);
1172 return 0;
1175 case VIDIOC_ENUM_FRAMESIZES:
1177 struct v4l2_frmsizeenum *fsize = arg;
1178 unsigned int i = 0, index = fsize->index;
1180 if (fsize->pixel_format == V4L2_PIX_FMT_YUV420) {
1181 for (i = 0; i < PSZ_MAX; i++) {
1182 if (pdev->image_mask & (1UL << i)) {
1183 if (!index--) {
1184 fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
1185 fsize->discrete.width = pwc_image_sizes[i].x;
1186 fsize->discrete.height = pwc_image_sizes[i].y;
1187 return 0;
1191 } else if (fsize->index == 0 &&
1192 ((fsize->pixel_format == V4L2_PIX_FMT_PWC1 && DEVICE_USE_CODEC1(pdev->type)) ||
1193 (fsize->pixel_format == V4L2_PIX_FMT_PWC2 && DEVICE_USE_CODEC23(pdev->type)))) {
1195 fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
1196 fsize->discrete.width = pdev->abs_max.x;
1197 fsize->discrete.height = pdev->abs_max.y;
1198 return 0;
1200 return -EINVAL;
1203 case VIDIOC_ENUM_FRAMEINTERVALS:
1205 struct v4l2_frmivalenum *fival = arg;
1206 int size = -1;
1207 unsigned int i;
1209 for (i = 0; i < PSZ_MAX; i++) {
1210 if (pwc_image_sizes[i].x == fival->width &&
1211 pwc_image_sizes[i].y == fival->height) {
1212 size = i;
1213 break;
1217 /* TODO: Support raw format */
1218 if (size < 0 || fival->pixel_format != V4L2_PIX_FMT_YUV420) {
1219 return -EINVAL;
1222 i = pwc_get_fps(pdev, fival->index, size);
1223 if (!i)
1224 return -EINVAL;
1226 fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
1227 fival->discrete.numerator = 1;
1228 fival->discrete.denominator = i;
1230 return 0;
1233 default:
1234 return pwc_ioctl(pdev, cmd, arg);
1235 } /* ..switch */
1236 return 0;
1239 /* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */