PRCM: 34XX: Fix wrong shift value used in dpll4_m4x2_ck enable bit
[linux-ginger.git] / drivers / media / video / pwc / pwc-v4l.c
blob1742889874df08c6f944b4b066fa1111fcff2e4a
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/slab.h>
34 #include <linux/vmalloc.h>
35 #include <asm/io.h>
37 #include "pwc.h"
39 static struct v4l2_queryctrl pwc_controls[] = {
41 .id = V4L2_CID_BRIGHTNESS,
42 .type = V4L2_CTRL_TYPE_INTEGER,
43 .name = "Brightness",
44 .minimum = 0,
45 .maximum = 128,
46 .step = 1,
47 .default_value = 64,
50 .id = V4L2_CID_CONTRAST,
51 .type = V4L2_CTRL_TYPE_INTEGER,
52 .name = "Contrast",
53 .minimum = 0,
54 .maximum = 64,
55 .step = 1,
56 .default_value = 0,
59 .id = V4L2_CID_SATURATION,
60 .type = V4L2_CTRL_TYPE_INTEGER,
61 .name = "Saturation",
62 .minimum = -100,
63 .maximum = 100,
64 .step = 1,
65 .default_value = 0,
68 .id = V4L2_CID_GAMMA,
69 .type = V4L2_CTRL_TYPE_INTEGER,
70 .name = "Gamma",
71 .minimum = 0,
72 .maximum = 32,
73 .step = 1,
74 .default_value = 0,
77 .id = V4L2_CID_RED_BALANCE,
78 .type = V4L2_CTRL_TYPE_INTEGER,
79 .name = "Red Gain",
80 .minimum = 0,
81 .maximum = 256,
82 .step = 1,
83 .default_value = 0,
86 .id = V4L2_CID_BLUE_BALANCE,
87 .type = V4L2_CTRL_TYPE_INTEGER,
88 .name = "Blue Gain",
89 .minimum = 0,
90 .maximum = 256,
91 .step = 1,
92 .default_value = 0,
95 .id = V4L2_CID_AUTO_WHITE_BALANCE,
96 .type = V4L2_CTRL_TYPE_BOOLEAN,
97 .name = "Auto White Balance",
98 .minimum = 0,
99 .maximum = 1,
100 .step = 1,
101 .default_value = 0,
104 .id = V4L2_CID_EXPOSURE,
105 .type = V4L2_CTRL_TYPE_INTEGER,
106 .name = "Shutter Speed (Exposure)",
107 .minimum = 0,
108 .maximum = 256,
109 .step = 1,
110 .default_value = 200,
113 .id = V4L2_CID_AUTOGAIN,
114 .type = V4L2_CTRL_TYPE_BOOLEAN,
115 .name = "Auto Gain Enabled",
116 .minimum = 0,
117 .maximum = 1,
118 .step = 1,
119 .default_value = 1,
122 .id = V4L2_CID_GAIN,
123 .type = V4L2_CTRL_TYPE_INTEGER,
124 .name = "Gain Level",
125 .minimum = 0,
126 .maximum = 256,
127 .step = 1,
128 .default_value = 0,
131 .id = V4L2_CID_PRIVATE_SAVE_USER,
132 .type = V4L2_CTRL_TYPE_BUTTON,
133 .name = "Save User Settings",
134 .minimum = 0,
135 .maximum = 0,
136 .step = 0,
137 .default_value = 0,
140 .id = V4L2_CID_PRIVATE_RESTORE_USER,
141 .type = V4L2_CTRL_TYPE_BUTTON,
142 .name = "Restore User Settings",
143 .minimum = 0,
144 .maximum = 0,
145 .step = 0,
146 .default_value = 0,
149 .id = V4L2_CID_PRIVATE_RESTORE_FACTORY,
150 .type = V4L2_CTRL_TYPE_BUTTON,
151 .name = "Restore Factory Settings",
152 .minimum = 0,
153 .maximum = 0,
154 .step = 0,
155 .default_value = 0,
158 .id = V4L2_CID_PRIVATE_COLOUR_MODE,
159 .type = V4L2_CTRL_TYPE_BOOLEAN,
160 .name = "Colour mode",
161 .minimum = 0,
162 .maximum = 1,
163 .step = 1,
164 .default_value = 0,
167 .id = V4L2_CID_PRIVATE_AUTOCONTOUR,
168 .type = V4L2_CTRL_TYPE_BOOLEAN,
169 .name = "Auto contour",
170 .minimum = 0,
171 .maximum = 1,
172 .step = 1,
173 .default_value = 0,
176 .id = V4L2_CID_PRIVATE_CONTOUR,
177 .type = V4L2_CTRL_TYPE_INTEGER,
178 .name = "Contour",
179 .minimum = 0,
180 .maximum = 63,
181 .step = 1,
182 .default_value = 0,
185 .id = V4L2_CID_PRIVATE_BACKLIGHT,
186 .type = V4L2_CTRL_TYPE_BOOLEAN,
187 .name = "Backlight compensation",
188 .minimum = 0,
189 .maximum = 1,
190 .step = 1,
191 .default_value = 0,
194 .id = V4L2_CID_PRIVATE_FLICKERLESS,
195 .type = V4L2_CTRL_TYPE_BOOLEAN,
196 .name = "Flickerless",
197 .minimum = 0,
198 .maximum = 1,
199 .step = 1,
200 .default_value = 0,
203 .id = V4L2_CID_PRIVATE_NOISE_REDUCTION,
204 .type = V4L2_CTRL_TYPE_INTEGER,
205 .name = "Noise reduction",
206 .minimum = 0,
207 .maximum = 3,
208 .step = 1,
209 .default_value = 0,
214 static void pwc_vidioc_fill_fmt(const struct pwc_device *pdev, struct v4l2_format *f)
216 memset(&f->fmt.pix, 0, sizeof(struct v4l2_pix_format));
217 f->fmt.pix.width = pdev->view.x;
218 f->fmt.pix.height = pdev->view.y;
219 f->fmt.pix.field = V4L2_FIELD_NONE;
220 if (pdev->vpalette == VIDEO_PALETTE_YUV420P) {
221 f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420;
222 f->fmt.pix.bytesperline = (f->fmt.pix.width * 3)/2;
223 f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
224 } else {
225 /* vbandlength contains 4 lines ... */
226 f->fmt.pix.bytesperline = pdev->vbandlength/4;
227 f->fmt.pix.sizeimage = pdev->frame_size + sizeof(struct pwc_raw_frame);
228 if (DEVICE_USE_CODEC1(pdev->type))
229 f->fmt.pix.pixelformat = V4L2_PIX_FMT_PWC1;
230 else
231 f->fmt.pix.pixelformat = V4L2_PIX_FMT_PWC2;
233 PWC_DEBUG_IOCTL("pwc_vidioc_fill_fmt() "
234 "width=%d, height=%d, bytesperline=%d, sizeimage=%d, pixelformat=%c%c%c%c\n",
235 f->fmt.pix.width,
236 f->fmt.pix.height,
237 f->fmt.pix.bytesperline,
238 f->fmt.pix.sizeimage,
239 (f->fmt.pix.pixelformat)&255,
240 (f->fmt.pix.pixelformat>>8)&255,
241 (f->fmt.pix.pixelformat>>16)&255,
242 (f->fmt.pix.pixelformat>>24)&255);
245 /* ioctl(VIDIOC_TRY_FMT) */
246 static int pwc_vidioc_try_fmt(struct pwc_device *pdev, struct v4l2_format *f)
248 if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
249 PWC_DEBUG_IOCTL("Bad video type must be V4L2_BUF_TYPE_VIDEO_CAPTURE\n");
250 return -EINVAL;
253 switch (f->fmt.pix.pixelformat) {
254 case V4L2_PIX_FMT_YUV420:
255 break;
256 case V4L2_PIX_FMT_PWC1:
257 if (DEVICE_USE_CODEC23(pdev->type)) {
258 PWC_DEBUG_IOCTL("codec1 is only supported for old pwc webcam\n");
259 return -EINVAL;
261 break;
262 case V4L2_PIX_FMT_PWC2:
263 if (DEVICE_USE_CODEC1(pdev->type)) {
264 PWC_DEBUG_IOCTL("codec23 is only supported for new pwc webcam\n");
265 return -EINVAL;
267 break;
268 default:
269 PWC_DEBUG_IOCTL("Unsupported pixel format\n");
270 return -EINVAL;
274 if (f->fmt.pix.width > pdev->view_max.x)
275 f->fmt.pix.width = pdev->view_max.x;
276 else if (f->fmt.pix.width < pdev->view_min.x)
277 f->fmt.pix.width = pdev->view_min.x;
279 if (f->fmt.pix.height > pdev->view_max.y)
280 f->fmt.pix.height = pdev->view_max.y;
281 else if (f->fmt.pix.height < pdev->view_min.y)
282 f->fmt.pix.height = pdev->view_min.y;
284 return 0;
287 /* ioctl(VIDIOC_SET_FMT) */
288 static int pwc_vidioc_set_fmt(struct pwc_device *pdev, struct v4l2_format *f)
290 int ret, fps, snapshot, compression, pixelformat;
292 ret = pwc_vidioc_try_fmt(pdev, f);
293 if (ret<0)
294 return ret;
296 pixelformat = f->fmt.pix.pixelformat;
297 compression = pdev->vcompression;
298 snapshot = 0;
299 fps = pdev->vframes;
300 if (f->fmt.pix.priv) {
301 compression = (f->fmt.pix.priv & PWC_QLT_MASK) >> PWC_QLT_SHIFT;
302 snapshot = !!(f->fmt.pix.priv & PWC_FPS_SNAPSHOT);
303 fps = (f->fmt.pix.priv & PWC_FPS_FRMASK) >> PWC_FPS_SHIFT;
304 if (fps == 0)
305 fps = pdev->vframes;
308 if (pixelformat == V4L2_PIX_FMT_YUV420)
309 pdev->vpalette = VIDEO_PALETTE_YUV420P;
310 else
311 pdev->vpalette = VIDEO_PALETTE_RAW;
313 PWC_DEBUG_IOCTL("Try to change format to: width=%d height=%d fps=%d "
314 "compression=%d snapshot=%d format=%c%c%c%c\n",
315 f->fmt.pix.width, f->fmt.pix.height, fps,
316 compression, snapshot,
317 (pixelformat)&255,
318 (pixelformat>>8)&255,
319 (pixelformat>>16)&255,
320 (pixelformat>>24)&255);
322 ret = pwc_try_video_mode(pdev,
323 f->fmt.pix.width,
324 f->fmt.pix.height,
325 fps,
326 compression,
327 snapshot);
329 PWC_DEBUG_IOCTL("pwc_try_video_mode(), return=%d\n", ret);
331 if (ret)
332 return ret;
334 pwc_vidioc_fill_fmt(pdev, f);
336 return 0;
340 int pwc_video_do_ioctl(struct inode *inode, struct file *file,
341 unsigned int cmd, void *arg)
343 struct video_device *vdev = video_devdata(file);
344 struct pwc_device *pdev;
345 DECLARE_WAITQUEUE(wait, current);
347 if (vdev == NULL)
348 return -EFAULT;
349 pdev = vdev->priv;
350 if (pdev == NULL)
351 return -EFAULT;
353 #ifdef CONFIG_USB_PWC_DEBUG
354 if (PWC_DEBUG_LEVEL_IOCTL & pwc_trace) {
355 v4l_printk_ioctl(cmd);
356 printk("\n");
358 #endif
361 switch (cmd) {
362 /* Query cabapilities */
363 case VIDIOCGCAP:
365 struct video_capability *caps = arg;
367 strcpy(caps->name, vdev->name);
368 caps->type = VID_TYPE_CAPTURE;
369 caps->channels = 1;
370 caps->audios = 1;
371 caps->minwidth = pdev->view_min.x;
372 caps->minheight = pdev->view_min.y;
373 caps->maxwidth = pdev->view_max.x;
374 caps->maxheight = pdev->view_max.y;
375 break;
378 /* Channel functions (simulate 1 channel) */
379 case VIDIOCGCHAN:
381 struct video_channel *v = arg;
383 if (v->channel != 0)
384 return -EINVAL;
385 v->flags = 0;
386 v->tuners = 0;
387 v->type = VIDEO_TYPE_CAMERA;
388 strcpy(v->name, "Webcam");
389 return 0;
392 case VIDIOCSCHAN:
394 /* The spec says the argument is an integer, but
395 the bttv driver uses a video_channel arg, which
396 makes sense becasue it also has the norm flag.
398 struct video_channel *v = arg;
399 if (v->channel != 0)
400 return -EINVAL;
401 return 0;
405 /* Picture functions; contrast etc. */
406 case VIDIOCGPICT:
408 struct video_picture *p = arg;
409 int val;
411 val = pwc_get_brightness(pdev);
412 if (val >= 0)
413 p->brightness = (val<<9);
414 else
415 p->brightness = 0xffff;
416 val = pwc_get_contrast(pdev);
417 if (val >= 0)
418 p->contrast = (val<<10);
419 else
420 p->contrast = 0xffff;
421 /* Gamma, Whiteness, what's the difference? :) */
422 val = pwc_get_gamma(pdev);
423 if (val >= 0)
424 p->whiteness = (val<<11);
425 else
426 p->whiteness = 0xffff;
427 if (pwc_get_saturation(pdev, &val)<0)
428 p->colour = 0xffff;
429 else
430 p->colour = 32768 + val * 327;
431 p->depth = 24;
432 p->palette = pdev->vpalette;
433 p->hue = 0xFFFF; /* N/A */
434 break;
437 case VIDIOCSPICT:
439 struct video_picture *p = arg;
441 * FIXME: Suppose we are mid read
442 ANSWER: No problem: the firmware of the camera
443 can handle brightness/contrast/etc
444 changes at _any_ time, and the palette
445 is used exactly once in the uncompress
446 routine.
448 pwc_set_brightness(pdev, p->brightness);
449 pwc_set_contrast(pdev, p->contrast);
450 pwc_set_gamma(pdev, p->whiteness);
451 pwc_set_saturation(pdev, (p->colour-32768)/327);
452 if (p->palette && p->palette != pdev->vpalette) {
453 switch (p->palette) {
454 case VIDEO_PALETTE_YUV420P:
455 case VIDEO_PALETTE_RAW:
456 pdev->vpalette = p->palette;
457 return pwc_try_video_mode(pdev, pdev->image.x, pdev->image.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
458 break;
459 default:
460 return -EINVAL;
461 break;
464 break;
467 /* Window/size parameters */
468 case VIDIOCGWIN:
470 struct video_window *vw = arg;
472 vw->x = 0;
473 vw->y = 0;
474 vw->width = pdev->view.x;
475 vw->height = pdev->view.y;
476 vw->chromakey = 0;
477 vw->flags = (pdev->vframes << PWC_FPS_SHIFT) |
478 (pdev->vsnapshot ? PWC_FPS_SNAPSHOT : 0);
479 break;
482 case VIDIOCSWIN:
484 struct video_window *vw = arg;
485 int fps, snapshot, ret;
487 fps = (vw->flags & PWC_FPS_FRMASK) >> PWC_FPS_SHIFT;
488 snapshot = vw->flags & PWC_FPS_SNAPSHOT;
489 if (fps == 0)
490 fps = pdev->vframes;
491 if (pdev->view.x == vw->width && pdev->view.y && fps == pdev->vframes && snapshot == pdev->vsnapshot)
492 return 0;
493 ret = pwc_try_video_mode(pdev, vw->width, vw->height, fps, pdev->vcompression, snapshot);
494 if (ret)
495 return ret;
496 break;
499 /* We don't have overlay support (yet) */
500 case VIDIOCGFBUF:
502 struct video_buffer *vb = arg;
504 memset(vb,0,sizeof(*vb));
505 break;
508 /* mmap() functions */
509 case VIDIOCGMBUF:
511 /* Tell the user program how much memory is needed for a mmap() */
512 struct video_mbuf *vm = arg;
513 int i;
515 memset(vm, 0, sizeof(*vm));
516 vm->size = pwc_mbufs * pdev->len_per_image;
517 vm->frames = pwc_mbufs; /* double buffering should be enough for most applications */
518 for (i = 0; i < pwc_mbufs; i++)
519 vm->offsets[i] = i * pdev->len_per_image;
520 break;
523 case VIDIOCMCAPTURE:
525 /* Start capture into a given image buffer (called 'frame' in video_mmap structure) */
526 struct video_mmap *vm = arg;
528 PWC_DEBUG_READ("VIDIOCMCAPTURE: %dx%d, frame %d, format %d\n", vm->width, vm->height, vm->frame, vm->format);
529 if (vm->frame < 0 || vm->frame >= pwc_mbufs)
530 return -EINVAL;
532 /* xawtv is nasty. It probes the available palettes
533 by setting a very small image size and trying
534 various palettes... The driver doesn't support
535 such small images, so I'm working around it.
537 if (vm->format)
539 switch (vm->format)
541 case VIDEO_PALETTE_YUV420P:
542 case VIDEO_PALETTE_RAW:
543 break;
544 default:
545 return -EINVAL;
546 break;
550 if ((vm->width != pdev->view.x || vm->height != pdev->view.y) &&
551 (vm->width >= pdev->view_min.x && vm->height >= pdev->view_min.y)) {
552 int ret;
554 PWC_DEBUG_OPEN("VIDIOCMCAPTURE: changing size to please xawtv :-(.\n");
555 ret = pwc_try_video_mode(pdev, vm->width, vm->height, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
556 if (ret)
557 return ret;
558 } /* ... size mismatch */
560 /* FIXME: should we lock here? */
561 if (pdev->image_used[vm->frame])
562 return -EBUSY; /* buffer wasn't available. Bummer */
563 pdev->image_used[vm->frame] = 1;
565 /* Okay, we're done here. In the SYNC call we wait until a
566 frame comes available, then expand image into the given
567 buffer.
568 In contrast to the CPiA cam the Philips cams deliver a
569 constant stream, almost like a grabber card. Also,
570 we have separate buffers for the rawdata and the image,
571 meaning we can nearly always expand into the requested buffer.
573 PWC_DEBUG_READ("VIDIOCMCAPTURE done.\n");
574 break;
577 case VIDIOCSYNC:
579 /* The doc says: "Whenever a buffer is used it should
580 call VIDIOCSYNC to free this frame up and continue."
582 The only odd thing about this whole procedure is
583 that MCAPTURE flags the buffer as "in use", and
584 SYNC immediately unmarks it, while it isn't
585 after SYNC that you know that the buffer actually
586 got filled! So you better not start a CAPTURE in
587 the same frame immediately (use double buffering).
588 This is not a problem for this cam, since it has
589 extra intermediate buffers, but a hardware
590 grabber card will then overwrite the buffer
591 you're working on.
593 int *mbuf = arg;
594 int ret;
596 PWC_DEBUG_READ("VIDIOCSYNC called (%d).\n", *mbuf);
598 /* bounds check */
599 if (*mbuf < 0 || *mbuf >= pwc_mbufs)
600 return -EINVAL;
601 /* check if this buffer was requested anyway */
602 if (pdev->image_used[*mbuf] == 0)
603 return -EINVAL;
605 /* Add ourselves to the frame wait-queue.
607 FIXME: needs auditing for safety.
608 QUESTION: In what respect? I think that using the
609 frameq is safe now.
611 add_wait_queue(&pdev->frameq, &wait);
612 while (pdev->full_frames == NULL) {
613 /* Check for unplugged/etc. here */
614 if (pdev->error_status) {
615 remove_wait_queue(&pdev->frameq, &wait);
616 set_current_state(TASK_RUNNING);
617 return -pdev->error_status;
620 if (signal_pending(current)) {
621 remove_wait_queue(&pdev->frameq, &wait);
622 set_current_state(TASK_RUNNING);
623 return -ERESTARTSYS;
625 schedule();
626 set_current_state(TASK_INTERRUPTIBLE);
628 remove_wait_queue(&pdev->frameq, &wait);
629 set_current_state(TASK_RUNNING);
631 /* The frame is ready. Expand in the image buffer
632 requested by the user. I don't care if you
633 mmap() 5 buffers and request data in this order:
634 buffer 4 2 3 0 1 2 3 0 4 3 1 . . .
635 Grabber hardware may not be so forgiving.
637 PWC_DEBUG_READ("VIDIOCSYNC: frame ready.\n");
638 pdev->fill_image = *mbuf; /* tell in which buffer we want the image to be expanded */
639 /* Decompress, etc */
640 ret = pwc_handle_frame(pdev);
641 pdev->image_used[*mbuf] = 0;
642 if (ret)
643 return -EFAULT;
644 break;
647 case VIDIOCGAUDIO:
649 struct video_audio *v = arg;
651 strcpy(v->name, "Microphone");
652 v->audio = -1; /* unknown audio minor */
653 v->flags = 0;
654 v->mode = VIDEO_SOUND_MONO;
655 v->volume = 0;
656 v->bass = 0;
657 v->treble = 0;
658 v->balance = 0x8000;
659 v->step = 1;
660 break;
663 case VIDIOCSAUDIO:
665 /* Dummy: nothing can be set */
666 break;
669 case VIDIOCGUNIT:
671 struct video_unit *vu = arg;
673 vu->video = pdev->vdev->minor & 0x3F;
674 vu->audio = -1; /* not known yet */
675 vu->vbi = -1;
676 vu->radio = -1;
677 vu->teletext = -1;
678 break;
681 /* V4L2 Layer */
682 case VIDIOC_QUERYCAP:
684 struct v4l2_capability *cap = arg;
686 PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCAP) This application "\
687 "try to use the v4l2 layer\n");
688 strcpy(cap->driver,PWC_NAME);
689 strlcpy(cap->card, vdev->name, sizeof(cap->card));
690 usb_make_path(pdev->udev,cap->bus_info,sizeof(cap->bus_info));
691 cap->version = PWC_VERSION_CODE;
692 cap->capabilities =
693 V4L2_CAP_VIDEO_CAPTURE |
694 V4L2_CAP_STREAMING |
695 V4L2_CAP_READWRITE;
696 return 0;
699 case VIDIOC_ENUMINPUT:
701 struct v4l2_input *i = arg;
703 if ( i->index ) /* Only one INPUT is supported */
704 return -EINVAL;
706 memset(i, 0, sizeof(struct v4l2_input));
707 strcpy(i->name, "usb");
708 return 0;
711 case VIDIOC_G_INPUT:
713 int *i = arg;
714 *i = 0; /* Only one INPUT is supported */
715 return 0;
717 case VIDIOC_S_INPUT:
719 int *i = arg;
721 if ( *i ) { /* Only one INPUT is supported */
722 PWC_DEBUG_IOCTL("Only one input source is"\
723 " supported with this webcam.\n");
724 return -EINVAL;
726 return 0;
729 /* TODO: */
730 case VIDIOC_QUERYCTRL:
732 struct v4l2_queryctrl *c = arg;
733 int i;
735 PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) query id=%d\n", c->id);
736 for (i=0; i<sizeof(pwc_controls)/sizeof(struct v4l2_queryctrl); i++) {
737 if (pwc_controls[i].id == c->id) {
738 PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) found\n");
739 memcpy(c,&pwc_controls[i],sizeof(struct v4l2_queryctrl));
740 return 0;
743 PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) not found\n");
745 return -EINVAL;
747 case VIDIOC_G_CTRL:
749 struct v4l2_control *c = arg;
750 int ret;
752 switch (c->id)
754 case V4L2_CID_BRIGHTNESS:
755 c->value = pwc_get_brightness(pdev);
756 if (c->value<0)
757 return -EINVAL;
758 return 0;
759 case V4L2_CID_CONTRAST:
760 c->value = pwc_get_contrast(pdev);
761 if (c->value<0)
762 return -EINVAL;
763 return 0;
764 case V4L2_CID_SATURATION:
765 ret = pwc_get_saturation(pdev, &c->value);
766 if (ret<0)
767 return -EINVAL;
768 return 0;
769 case V4L2_CID_GAMMA:
770 c->value = pwc_get_gamma(pdev);
771 if (c->value<0)
772 return -EINVAL;
773 return 0;
774 case V4L2_CID_RED_BALANCE:
775 ret = pwc_get_red_gain(pdev, &c->value);
776 if (ret<0)
777 return -EINVAL;
778 c->value >>= 8;
779 return 0;
780 case V4L2_CID_BLUE_BALANCE:
781 ret = pwc_get_blue_gain(pdev, &c->value);
782 if (ret<0)
783 return -EINVAL;
784 c->value >>= 8;
785 return 0;
786 case V4L2_CID_AUTO_WHITE_BALANCE:
787 ret = pwc_get_awb(pdev);
788 if (ret<0)
789 return -EINVAL;
790 c->value = (ret == PWC_WB_MANUAL)?0:1;
791 return 0;
792 case V4L2_CID_GAIN:
793 ret = pwc_get_agc(pdev, &c->value);
794 if (ret<0)
795 return -EINVAL;
796 c->value >>= 8;
797 return 0;
798 case V4L2_CID_AUTOGAIN:
799 ret = pwc_get_agc(pdev, &c->value);
800 if (ret<0)
801 return -EINVAL;
802 c->value = (c->value < 0)?1:0;
803 return 0;
804 case V4L2_CID_EXPOSURE:
805 ret = pwc_get_shutter_speed(pdev, &c->value);
806 if (ret<0)
807 return -EINVAL;
808 return 0;
809 case V4L2_CID_PRIVATE_COLOUR_MODE:
810 ret = pwc_get_colour_mode(pdev, &c->value);
811 if (ret < 0)
812 return -EINVAL;
813 return 0;
814 case V4L2_CID_PRIVATE_AUTOCONTOUR:
815 ret = pwc_get_contour(pdev, &c->value);
816 if (ret < 0)
817 return -EINVAL;
818 c->value=(c->value == -1?1:0);
819 return 0;
820 case V4L2_CID_PRIVATE_CONTOUR:
821 ret = pwc_get_contour(pdev, &c->value);
822 if (ret < 0)
823 return -EINVAL;
824 c->value >>= 10;
825 return 0;
826 case V4L2_CID_PRIVATE_BACKLIGHT:
827 ret = pwc_get_backlight(pdev, &c->value);
828 if (ret < 0)
829 return -EINVAL;
830 return 0;
831 case V4L2_CID_PRIVATE_FLICKERLESS:
832 ret = pwc_get_flicker(pdev, &c->value);
833 if (ret < 0)
834 return -EINVAL;
835 c->value=(c->value?1:0);
836 return 0;
837 case V4L2_CID_PRIVATE_NOISE_REDUCTION:
838 ret = pwc_get_dynamic_noise(pdev, &c->value);
839 if (ret < 0)
840 return -EINVAL;
841 return 0;
843 case V4L2_CID_PRIVATE_SAVE_USER:
844 case V4L2_CID_PRIVATE_RESTORE_USER:
845 case V4L2_CID_PRIVATE_RESTORE_FACTORY:
846 return -EINVAL;
848 return -EINVAL;
850 case VIDIOC_S_CTRL:
852 struct v4l2_control *c = arg;
853 int ret;
855 switch (c->id)
857 case V4L2_CID_BRIGHTNESS:
858 c->value <<= 9;
859 ret = pwc_set_brightness(pdev, c->value);
860 if (ret<0)
861 return -EINVAL;
862 return 0;
863 case V4L2_CID_CONTRAST:
864 c->value <<= 10;
865 ret = pwc_set_contrast(pdev, c->value);
866 if (ret<0)
867 return -EINVAL;
868 return 0;
869 case V4L2_CID_SATURATION:
870 ret = pwc_set_saturation(pdev, c->value);
871 if (ret<0)
872 return -EINVAL;
873 return 0;
874 case V4L2_CID_GAMMA:
875 c->value <<= 11;
876 ret = pwc_set_gamma(pdev, c->value);
877 if (ret<0)
878 return -EINVAL;
879 return 0;
880 case V4L2_CID_RED_BALANCE:
881 c->value <<= 8;
882 ret = pwc_set_red_gain(pdev, c->value);
883 if (ret<0)
884 return -EINVAL;
885 return 0;
886 case V4L2_CID_BLUE_BALANCE:
887 c->value <<= 8;
888 ret = pwc_set_blue_gain(pdev, c->value);
889 if (ret<0)
890 return -EINVAL;
891 return 0;
892 case V4L2_CID_AUTO_WHITE_BALANCE:
893 c->value = (c->value == 0)?PWC_WB_MANUAL:PWC_WB_AUTO;
894 ret = pwc_set_awb(pdev, c->value);
895 if (ret<0)
896 return -EINVAL;
897 return 0;
898 case V4L2_CID_EXPOSURE:
899 c->value <<= 8;
900 ret = pwc_set_shutter_speed(pdev, c->value?0:1, c->value);
901 if (ret<0)
902 return -EINVAL;
903 return 0;
904 case V4L2_CID_AUTOGAIN:
905 /* autogain off means nothing without a gain */
906 if (c->value == 0)
907 return 0;
908 ret = pwc_set_agc(pdev, c->value, 0);
909 if (ret<0)
910 return -EINVAL;
911 return 0;
912 case V4L2_CID_GAIN:
913 c->value <<= 8;
914 ret = pwc_set_agc(pdev, 0, c->value);
915 if (ret<0)
916 return -EINVAL;
917 return 0;
918 case V4L2_CID_PRIVATE_SAVE_USER:
919 if (pwc_save_user(pdev))
920 return -EINVAL;
921 return 0;
922 case V4L2_CID_PRIVATE_RESTORE_USER:
923 if (pwc_restore_user(pdev))
924 return -EINVAL;
925 return 0;
926 case V4L2_CID_PRIVATE_RESTORE_FACTORY:
927 if (pwc_restore_factory(pdev))
928 return -EINVAL;
929 return 0;
930 case V4L2_CID_PRIVATE_COLOUR_MODE:
931 ret = pwc_set_colour_mode(pdev, c->value);
932 if (ret < 0)
933 return -EINVAL;
934 return 0;
935 case V4L2_CID_PRIVATE_AUTOCONTOUR:
936 c->value=(c->value == 1)?-1:0;
937 ret = pwc_set_contour(pdev, c->value);
938 if (ret < 0)
939 return -EINVAL;
940 return 0;
941 case V4L2_CID_PRIVATE_CONTOUR:
942 c->value <<= 10;
943 ret = pwc_set_contour(pdev, c->value);
944 if (ret < 0)
945 return -EINVAL;
946 return 0;
947 case V4L2_CID_PRIVATE_BACKLIGHT:
948 ret = pwc_set_backlight(pdev, c->value);
949 if (ret < 0)
950 return -EINVAL;
951 return 0;
952 case V4L2_CID_PRIVATE_FLICKERLESS:
953 ret = pwc_set_flicker(pdev, c->value);
954 if (ret < 0)
955 return -EINVAL;
956 case V4L2_CID_PRIVATE_NOISE_REDUCTION:
957 ret = pwc_set_dynamic_noise(pdev, c->value);
958 if (ret < 0)
959 return -EINVAL;
960 return 0;
963 return -EINVAL;
966 case VIDIOC_ENUM_FMT:
968 struct v4l2_fmtdesc *f = arg;
969 int index;
971 if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
972 return -EINVAL;
974 /* We only support two format: the raw format, and YUV */
975 index = f->index;
976 memset(f,0,sizeof(struct v4l2_fmtdesc));
977 f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
978 f->index = index;
979 switch(index)
981 case 0:
982 /* RAW format */
983 f->pixelformat = pdev->type<=646?V4L2_PIX_FMT_PWC1:V4L2_PIX_FMT_PWC2;
984 f->flags = V4L2_FMT_FLAG_COMPRESSED;
985 strlcpy(f->description,"Raw Philips Webcam",sizeof(f->description));
986 break;
987 case 1:
988 f->pixelformat = V4L2_PIX_FMT_YUV420;
989 strlcpy(f->description,"4:2:0, planar, Y-Cb-Cr",sizeof(f->description));
990 break;
991 default:
992 return -EINVAL;
994 return 0;
997 case VIDIOC_G_FMT:
999 struct v4l2_format *f = arg;
1001 PWC_DEBUG_IOCTL("ioctl(VIDIOC_G_FMT) return size %dx%d\n",pdev->image.x,pdev->image.y);
1002 if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1003 return -EINVAL;
1005 pwc_vidioc_fill_fmt(pdev, f);
1007 return 0;
1010 case VIDIOC_TRY_FMT:
1011 return pwc_vidioc_try_fmt(pdev, arg);
1013 case VIDIOC_S_FMT:
1014 return pwc_vidioc_set_fmt(pdev, arg);
1016 case VIDIOC_G_STD:
1018 v4l2_std_id *std = arg;
1019 *std = V4L2_STD_UNKNOWN;
1020 return 0;
1023 case VIDIOC_S_STD:
1025 v4l2_std_id *std = arg;
1026 if (*std != V4L2_STD_UNKNOWN)
1027 return -EINVAL;
1028 return 0;
1031 case VIDIOC_ENUMSTD:
1033 struct v4l2_standard *std = arg;
1034 if (std->index != 0)
1035 return -EINVAL;
1036 std->id = V4L2_STD_UNKNOWN;
1037 strncpy(std->name, "webcam", sizeof(std->name));
1038 return 0;
1041 case VIDIOC_REQBUFS:
1043 struct v4l2_requestbuffers *rb = arg;
1044 int nbuffers;
1046 PWC_DEBUG_IOCTL("ioctl(VIDIOC_REQBUFS) count=%d\n",rb->count);
1047 if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1048 return -EINVAL;
1049 if (rb->memory != V4L2_MEMORY_MMAP)
1050 return -EINVAL;
1052 nbuffers = rb->count;
1053 if (nbuffers < 2)
1054 nbuffers = 2;
1055 else if (nbuffers > pwc_mbufs)
1056 nbuffers = pwc_mbufs;
1057 /* Force to use our # of buffers */
1058 rb->count = pwc_mbufs;
1059 return 0;
1062 case VIDIOC_QUERYBUF:
1064 struct v4l2_buffer *buf = arg;
1065 int index;
1067 PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) index=%d\n",buf->index);
1068 if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
1069 PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad type\n");
1070 return -EINVAL;
1072 if (buf->memory != V4L2_MEMORY_MMAP) {
1073 PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad memory type\n");
1074 return -EINVAL;
1076 index = buf->index;
1077 if (index < 0 || index >= pwc_mbufs) {
1078 PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad index %d\n", buf->index);
1079 return -EINVAL;
1082 memset(buf, 0, sizeof(struct v4l2_buffer));
1083 buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1084 buf->index = index;
1085 buf->m.offset = index * pdev->len_per_image;
1086 if (pdev->vpalette == VIDEO_PALETTE_RAW)
1087 buf->bytesused = pdev->frame_size + sizeof(struct pwc_raw_frame);
1088 else
1089 buf->bytesused = pdev->view.size;
1090 buf->field = V4L2_FIELD_NONE;
1091 buf->memory = V4L2_MEMORY_MMAP;
1092 //buf->flags = V4L2_BUF_FLAG_MAPPED;
1093 buf->length = pdev->len_per_image;
1095 PWC_DEBUG_READ("VIDIOC_QUERYBUF: index=%d\n",buf->index);
1096 PWC_DEBUG_READ("VIDIOC_QUERYBUF: m.offset=%d\n",buf->m.offset);
1097 PWC_DEBUG_READ("VIDIOC_QUERYBUF: bytesused=%d\n",buf->bytesused);
1099 return 0;
1102 case VIDIOC_QBUF:
1104 struct v4l2_buffer *buf = arg;
1106 PWC_DEBUG_IOCTL("ioctl(VIDIOC_QBUF) index=%d\n",buf->index);
1107 if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1108 return -EINVAL;
1109 if (buf->memory != V4L2_MEMORY_MMAP)
1110 return -EINVAL;
1111 if (buf->index < 0 || buf->index >= pwc_mbufs)
1112 return -EINVAL;
1114 buf->flags |= V4L2_BUF_FLAG_QUEUED;
1115 buf->flags &= ~V4L2_BUF_FLAG_DONE;
1117 return 0;
1120 case VIDIOC_DQBUF:
1122 struct v4l2_buffer *buf = arg;
1123 int ret;
1125 PWC_DEBUG_IOCTL("ioctl(VIDIOC_DQBUF)\n");
1127 if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1128 return -EINVAL;
1130 /* Add ourselves to the frame wait-queue.
1132 FIXME: needs auditing for safety.
1133 QUESTION: In what respect? I think that using the
1134 frameq is safe now.
1136 add_wait_queue(&pdev->frameq, &wait);
1137 while (pdev->full_frames == NULL) {
1138 if (pdev->error_status) {
1139 remove_wait_queue(&pdev->frameq, &wait);
1140 set_current_state(TASK_RUNNING);
1141 return -pdev->error_status;
1144 if (signal_pending(current)) {
1145 remove_wait_queue(&pdev->frameq, &wait);
1146 set_current_state(TASK_RUNNING);
1147 return -ERESTARTSYS;
1149 schedule();
1150 set_current_state(TASK_INTERRUPTIBLE);
1152 remove_wait_queue(&pdev->frameq, &wait);
1153 set_current_state(TASK_RUNNING);
1155 PWC_DEBUG_IOCTL("VIDIOC_DQBUF: frame ready.\n");
1156 /* Decompress data in pdev->images[pdev->fill_image] */
1157 ret = pwc_handle_frame(pdev);
1158 if (ret)
1159 return -EFAULT;
1160 PWC_DEBUG_IOCTL("VIDIOC_DQBUF: after pwc_handle_frame\n");
1162 buf->index = pdev->fill_image;
1163 if (pdev->vpalette == VIDEO_PALETTE_RAW)
1164 buf->bytesused = pdev->frame_size + sizeof(struct pwc_raw_frame);
1165 else
1166 buf->bytesused = pdev->view.size;
1167 buf->flags = V4L2_BUF_FLAG_MAPPED;
1168 buf->field = V4L2_FIELD_NONE;
1169 do_gettimeofday(&buf->timestamp);
1170 buf->sequence = 0;
1171 buf->memory = V4L2_MEMORY_MMAP;
1172 buf->m.offset = pdev->fill_image * pdev->len_per_image;
1173 buf->length = pdev->len_per_image;
1174 pwc_next_image(pdev);
1176 PWC_DEBUG_IOCTL("VIDIOC_DQBUF: buf->index=%d\n",buf->index);
1177 PWC_DEBUG_IOCTL("VIDIOC_DQBUF: buf->length=%d\n",buf->length);
1178 PWC_DEBUG_IOCTL("VIDIOC_DQBUF: m.offset=%d\n",buf->m.offset);
1179 PWC_DEBUG_IOCTL("VIDIOC_DQBUF: bytesused=%d\n",buf->bytesused);
1180 PWC_DEBUG_IOCTL("VIDIOC_DQBUF: leaving\n");
1181 return 0;
1185 case VIDIOC_STREAMON:
1187 /* WARNING: pwc_try_video_mode() called pwc_isoc_init */
1188 pwc_isoc_init(pdev);
1189 return 0;
1192 case VIDIOC_STREAMOFF:
1194 pwc_isoc_cleanup(pdev);
1195 return 0;
1198 case VIDIOC_ENUM_FRAMESIZES:
1200 struct v4l2_frmsizeenum *fsize = arg;
1201 unsigned int i = 0, index = fsize->index;
1203 if (fsize->pixel_format == V4L2_PIX_FMT_YUV420) {
1204 for (i = 0; i < PSZ_MAX; i++) {
1205 if (pdev->image_mask & (1UL << i)) {
1206 if (!index--) {
1207 fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
1208 fsize->discrete.width = pwc_image_sizes[i].x;
1209 fsize->discrete.height = pwc_image_sizes[i].y;
1210 return 0;
1214 } else if (fsize->index == 0 &&
1215 ((fsize->pixel_format == V4L2_PIX_FMT_PWC1 && DEVICE_USE_CODEC1(pdev->type)) ||
1216 (fsize->pixel_format == V4L2_PIX_FMT_PWC2 && DEVICE_USE_CODEC23(pdev->type)))) {
1218 fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
1219 fsize->discrete.width = pdev->abs_max.x;
1220 fsize->discrete.height = pdev->abs_max.y;
1221 return 0;
1223 return -EINVAL;
1226 case VIDIOC_ENUM_FRAMEINTERVALS:
1228 struct v4l2_frmivalenum *fival = arg;
1229 int size = -1;
1230 unsigned int i;
1232 for (i = 0; i < PSZ_MAX; i++) {
1233 if (pwc_image_sizes[i].x == fival->width &&
1234 pwc_image_sizes[i].y == fival->height) {
1235 size = i;
1236 break;
1240 /* TODO: Support raw format */
1241 if (size < 0 || fival->pixel_format != V4L2_PIX_FMT_YUV420) {
1242 return -EINVAL;
1245 i = pwc_get_fps(pdev, fival->index, size);
1246 if (!i)
1247 return -EINVAL;
1249 fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
1250 fival->discrete.numerator = 1;
1251 fival->discrete.denominator = i;
1253 return 0;
1256 default:
1257 return pwc_ioctl(pdev, cmd, arg);
1258 } /* ..switch */
1259 return 0;
1262 /* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */