]> pilppa.org Git - linux-2.6-omap-h63xx.git/blob - drivers/media/video/pwc/pwc-v4l.c
V4L/DVB (3968): Fix checking logic for a broken xawtv version
[linux-2.6-omap-h63xx.git] / drivers / media / video / pwc / pwc-v4l.c
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)
5
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.
11
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.
16
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.
21
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
25
26 */
27
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>
36
37 #include "pwc.h"
38
39 static struct v4l2_queryctrl pwc_controls[] = {
40         {
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,
48         },
49         {
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,
57         },
58         {
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,
66         },
67         {
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,
75         },
76         {
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,
84         },
85         {
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,
93         },
94         {
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,
102         },
103         {
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,
111         },
112         {
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,
120         },
121         {
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,
129         },
130         {
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,
138         },
139         {
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,
147         },
148         {
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,
156         },
157         {
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,
165         },
166         {
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,
174         },
175         {
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,
183         },
184         {
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,
192         },
193         {
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,
201         },
202         {
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,
210         },
211 };
212
213 #if CONFIG_PWC_DEBUG
214 /* In 2.6.16-rc1 v4l_printk_ioctl is not defined but exported */
215 extern void v4l_printk_ioctl(unsigned int cmd);
216 #endif
217
218 static void pwc_vidioc_fill_fmt(const struct pwc_device *pdev, struct v4l2_format *f)
219 {
220         memset(&f->fmt.pix, 0, sizeof(struct v4l2_pix_format));
221         f->fmt.pix.width        = pdev->view.x;
222         f->fmt.pix.height       = pdev->view.y;
223         f->fmt.pix.field        = V4L2_FIELD_NONE;
224         if (pdev->vpalette == VIDEO_PALETTE_YUV420P) {
225                 f->fmt.pix.pixelformat  = V4L2_PIX_FMT_YUV420;
226                 f->fmt.pix.bytesperline = (f->fmt.pix.width * 3)/2;
227                 f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
228         } else {
229                 /* vbandlength contains 4 lines ...  */
230                 f->fmt.pix.bytesperline = pdev->vbandlength/4;
231                 f->fmt.pix.sizeimage = pdev->frame_size + sizeof(struct pwc_raw_frame);
232                 if (DEVICE_USE_CODEC1(pdev->type))
233                         f->fmt.pix.pixelformat  = V4L2_PIX_FMT_PWC1;
234                 else
235                         f->fmt.pix.pixelformat  = V4L2_PIX_FMT_PWC2;
236         }
237         PWC_DEBUG_IOCTL("pwc_vidioc_fill_fmt() "
238                         "width=%d, height=%d, bytesperline=%d, sizeimage=%d, pixelformat=%c%c%c%c\n",
239                         f->fmt.pix.width,
240                         f->fmt.pix.height,
241                         f->fmt.pix.bytesperline,
242                         f->fmt.pix.sizeimage,
243                         (f->fmt.pix.pixelformat)&255,
244                         (f->fmt.pix.pixelformat>>8)&255,
245                         (f->fmt.pix.pixelformat>>16)&255,
246                         (f->fmt.pix.pixelformat>>24)&255);
247 }
248
249 /* ioctl(VIDIOC_TRY_FMT) */
250 static int pwc_vidioc_try_fmt(struct pwc_device *pdev, struct v4l2_format *f)
251 {
252         if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
253                 PWC_DEBUG_IOCTL("Bad video type must be V4L2_BUF_TYPE_VIDEO_CAPTURE\n");
254                 return -EINVAL;
255         }
256
257         switch (f->fmt.pix.pixelformat) {
258                 case V4L2_PIX_FMT_YUV420:
259                         break;
260                 case V4L2_PIX_FMT_PWC1:
261                         if (DEVICE_USE_CODEC23(pdev->type)) {
262                                 PWC_DEBUG_IOCTL("codec1 is only supported for old pwc webcam\n");
263                                 return -EINVAL;
264                         }
265                         break;
266                 case V4L2_PIX_FMT_PWC2:
267                         if (DEVICE_USE_CODEC1(pdev->type)) {
268                                 PWC_DEBUG_IOCTL("codec23 is only supported for new pwc webcam\n");
269                                 return -EINVAL;
270                         }
271                         break;
272                 default:
273                         PWC_DEBUG_IOCTL("Unsupported pixel format\n");
274                         return -EINVAL;
275
276         }
277
278         if (f->fmt.pix.width > pdev->view_max.x)
279                 f->fmt.pix.width = pdev->view_max.x;
280         else if (f->fmt.pix.width < pdev->view_min.x)
281                 f->fmt.pix.width = pdev->view_min.x;
282
283         if (f->fmt.pix.height > pdev->view_max.y)
284                 f->fmt.pix.height = pdev->view_max.y;
285         else if (f->fmt.pix.height < pdev->view_min.y)
286                 f->fmt.pix.height = pdev->view_min.y;
287
288         return 0;
289 }
290
291 /* ioctl(VIDIOC_SET_FMT) */
292 static int pwc_vidioc_set_fmt(struct pwc_device *pdev, struct v4l2_format *f)
293 {
294         int ret, fps, snapshot, compression, pixelformat;
295
296         ret = pwc_vidioc_try_fmt(pdev, f);
297         if (ret<0)
298                 return ret;
299
300         pixelformat = f->fmt.pix.pixelformat;
301         compression = pdev->vcompression;
302         snapshot = 0;
303         fps = pdev->vframes;
304         if (f->fmt.pix.priv) {
305                 compression = (f->fmt.pix.priv & PWC_QLT_MASK) >> PWC_QLT_SHIFT;
306                 snapshot = !!(f->fmt.pix.priv & PWC_FPS_SNAPSHOT);
307                 fps = (f->fmt.pix.priv & PWC_FPS_FRMASK) >> PWC_FPS_SHIFT;
308                 if (fps == 0)
309                         fps = pdev->vframes;
310         }
311
312         if (pixelformat == V4L2_PIX_FMT_YUV420)
313                 pdev->vpalette = VIDEO_PALETTE_YUV420P;
314         else
315                 pdev->vpalette = VIDEO_PALETTE_RAW;
316
317         PWC_DEBUG_IOCTL("Try to change format to: width=%d height=%d fps=%d "
318                         "compression=%d snapshot=%d format=%c%c%c%c\n",
319                         f->fmt.pix.width, f->fmt.pix.height, fps,
320                         compression, snapshot,
321                         (pixelformat)&255,
322                         (pixelformat>>8)&255,
323                         (pixelformat>>16)&255,
324                         (pixelformat>>24)&255);
325
326         ret = pwc_try_video_mode(pdev,
327                                  f->fmt.pix.width,
328                                  f->fmt.pix.height,
329                                  fps,
330                                  compression,
331                                  snapshot);
332
333         PWC_DEBUG_IOCTL("pwc_try_video_mode(), return=%d\n", ret);
334
335         if (ret)
336                 return ret;
337
338         pwc_vidioc_fill_fmt(pdev, f);
339
340         return 0;
341
342 }
343
344 int pwc_video_do_ioctl(struct inode *inode, struct file *file,
345                        unsigned int cmd, void *arg)
346 {
347         struct video_device *vdev = video_devdata(file);
348         struct pwc_device *pdev;
349         DECLARE_WAITQUEUE(wait, current);
350
351         if (vdev == NULL)
352                 return -EFAULT;
353         pdev = vdev->priv;
354         if (pdev == NULL)
355                 return -EFAULT;
356
357 #if CONFIG_PWC_DEBUG
358         if (PWC_DEBUG_LEVEL_IOCTL & pwc_trace)
359                 v4l_printk_ioctl(cmd);
360 #endif
361
362
363         switch (cmd) {
364                 /* Query cabapilities */
365                 case VIDIOCGCAP:
366                 {
367                         struct video_capability *caps = arg;
368
369                         strcpy(caps->name, vdev->name);
370                         caps->type = VID_TYPE_CAPTURE;
371                         caps->channels = 1;
372                         caps->audios = 1;
373                         caps->minwidth  = pdev->view_min.x;
374                         caps->minheight = pdev->view_min.y;
375                         caps->maxwidth  = pdev->view_max.x;
376                         caps->maxheight = pdev->view_max.y;
377                         break;
378                 }
379
380                 /* Channel functions (simulate 1 channel) */
381                 case VIDIOCGCHAN:
382                 {
383                         struct video_channel *v = arg;
384
385                         if (v->channel != 0)
386                                 return -EINVAL;
387                         v->flags = 0;
388                         v->tuners = 0;
389                         v->type = VIDEO_TYPE_CAMERA;
390                         strcpy(v->name, "Webcam");
391                         return 0;
392                 }
393
394                 case VIDIOCSCHAN:
395                 {
396                         /* The spec says the argument is an integer, but
397                            the bttv driver uses a video_channel arg, which
398                            makes sense becasue it also has the norm flag.
399                          */
400                         struct video_channel *v = arg;
401                         if (v->channel != 0)
402                                 return -EINVAL;
403                         return 0;
404                 }
405
406
407                 /* Picture functions; contrast etc. */
408                 case VIDIOCGPICT:
409                 {
410                         struct video_picture *p = arg;
411                         int val;
412
413                         val = pwc_get_brightness(pdev);
414                         if (val >= 0)
415                                 p->brightness = (val<<9);
416                         else
417                                 p->brightness = 0xffff;
418                         val = pwc_get_contrast(pdev);
419                         if (val >= 0)
420                                 p->contrast = (val<<10);
421                         else
422                                 p->contrast = 0xffff;
423                         /* Gamma, Whiteness, what's the difference? :) */
424                         val = pwc_get_gamma(pdev);
425                         if (val >= 0)
426                                 p->whiteness = (val<<11);
427                         else
428                                 p->whiteness = 0xffff;
429                         if (pwc_get_saturation(pdev, &val)<0)
430                                 p->colour = 0xffff;
431                         else
432                                 p->colour = 32768 + val * 327;
433                         p->depth = 24;
434                         p->palette = pdev->vpalette;
435                         p->hue = 0xFFFF; /* N/A */
436                         break;
437                 }
438
439                 case VIDIOCSPICT:
440                 {
441                         struct video_picture *p = arg;
442                         /*
443                          *      FIXME:  Suppose we are mid read
444                                 ANSWER: No problem: the firmware of the camera
445                                         can handle brightness/contrast/etc
446                                         changes at _any_ time, and the palette
447                                         is used exactly once in the uncompress
448                                         routine.
449                          */
450                         pwc_set_brightness(pdev, p->brightness);
451                         pwc_set_contrast(pdev, p->contrast);
452                         pwc_set_gamma(pdev, p->whiteness);
453                         pwc_set_saturation(pdev, (p->colour-32768)/327);
454                         if (p->palette && p->palette != pdev->vpalette) {
455                                 switch (p->palette) {
456                                         case VIDEO_PALETTE_YUV420P:
457                                         case VIDEO_PALETTE_RAW:
458                                                 pdev->vpalette = p->palette;
459                                                 return pwc_try_video_mode(pdev, pdev->image.x, pdev->image.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
460                                                 break;
461                                         default:
462                                                 return -EINVAL;
463                                                 break;
464                                 }
465                         }
466                         break;
467                 }
468
469                 /* Window/size parameters */
470                 case VIDIOCGWIN:
471                 {
472                         struct video_window *vw = arg;
473
474                         vw->x = 0;
475                         vw->y = 0;
476                         vw->width = pdev->view.x;
477                         vw->height = pdev->view.y;
478                         vw->chromakey = 0;
479                         vw->flags = (pdev->vframes << PWC_FPS_SHIFT) |
480                                    (pdev->vsnapshot ? PWC_FPS_SNAPSHOT : 0);
481                         break;
482                 }
483
484                 case VIDIOCSWIN:
485                 {
486                         struct video_window *vw = arg;
487                         int fps, snapshot, ret;
488
489                         fps = (vw->flags & PWC_FPS_FRMASK) >> PWC_FPS_SHIFT;
490                         snapshot = vw->flags & PWC_FPS_SNAPSHOT;
491                         if (fps == 0)
492                                 fps = pdev->vframes;
493                         if (pdev->view.x == vw->width && pdev->view.y && fps == pdev->vframes && snapshot == pdev->vsnapshot)
494                                 return 0;
495                         ret = pwc_try_video_mode(pdev, vw->width, vw->height, fps, pdev->vcompression, snapshot);
496                         if (ret)
497                                 return ret;
498                         break;
499                 }
500
501                 /* We don't have overlay support (yet) */
502                 case VIDIOCGFBUF:
503                 {
504                         struct video_buffer *vb = arg;
505
506                         memset(vb,0,sizeof(*vb));
507                         break;
508                 }
509
510                 /* mmap() functions */
511                 case VIDIOCGMBUF:
512                 {
513                         /* Tell the user program how much memory is needed for a mmap() */
514                         struct video_mbuf *vm = arg;
515                         int i;
516
517                         memset(vm, 0, sizeof(*vm));
518                         vm->size = pwc_mbufs * pdev->len_per_image;
519                         vm->frames = pwc_mbufs; /* double buffering should be enough for most applications */
520                         for (i = 0; i < pwc_mbufs; i++)
521                                 vm->offsets[i] = i * pdev->len_per_image;
522                         break;
523                 }
524
525                 case VIDIOCMCAPTURE:
526                 {
527                         /* Start capture into a given image buffer (called 'frame' in video_mmap structure) */
528                         struct video_mmap *vm = arg;
529
530                         PWC_DEBUG_READ("VIDIOCMCAPTURE: %dx%d, frame %d, format %d\n", vm->width, vm->height, vm->frame, vm->format);
531                         if (vm->frame < 0 || vm->frame >= pwc_mbufs)
532                                 return -EINVAL;
533
534                         /* xawtv is nasty. It probes the available palettes
535                            by setting a very small image size and trying
536                            various palettes... The driver doesn't support
537                            such small images, so I'm working around it.
538                          */
539                         if (vm->format)
540                         {
541                                 switch (vm->format)
542                                 {
543                                         case VIDEO_PALETTE_YUV420P:
544                                         case VIDEO_PALETTE_RAW:
545                                                 break;
546                                         default:
547                                                 return -EINVAL;
548                                                 break;
549                                 }
550                         }
551
552                         if ((vm->width != pdev->view.x || vm->height != pdev->view.y) &&
553                             (vm->width >= pdev->view_min.x && vm->height >= pdev->view_min.y)) {
554                                 int ret;
555
556                                 PWC_DEBUG_OPEN("VIDIOCMCAPTURE: changing size to please xawtv :-(.\n");
557                                 ret = pwc_try_video_mode(pdev, vm->width, vm->height, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
558                                 if (ret)
559                                         return ret;
560                         } /* ... size mismatch */
561
562                         /* FIXME: should we lock here? */
563                         if (pdev->image_used[vm->frame])
564                                 return -EBUSY;  /* buffer wasn't available. Bummer */
565                         pdev->image_used[vm->frame] = 1;
566
567                         /* Okay, we're done here. In the SYNC call we wait until a
568                            frame comes available, then expand image into the given
569                            buffer.
570                            In contrast to the CPiA cam the Philips cams deliver a
571                            constant stream, almost like a grabber card. Also,
572                            we have separate buffers for the rawdata and the image,
573                            meaning we can nearly always expand into the requested buffer.
574                          */
575                         PWC_DEBUG_READ("VIDIOCMCAPTURE done.\n");
576                         break;
577                 }
578
579                 case VIDIOCSYNC:
580                 {
581                         /* The doc says: "Whenever a buffer is used it should
582                            call VIDIOCSYNC to free this frame up and continue."
583
584                            The only odd thing about this whole procedure is
585                            that MCAPTURE flags the buffer as "in use", and
586                            SYNC immediately unmarks it, while it isn't
587                            after SYNC that you know that the buffer actually
588                            got filled! So you better not start a CAPTURE in
589                            the same frame immediately (use double buffering).
590                            This is not a problem for this cam, since it has
591                            extra intermediate buffers, but a hardware
592                            grabber card will then overwrite the buffer
593                            you're working on.
594                          */
595                         int *mbuf = arg;
596                         int ret;
597
598                         PWC_DEBUG_READ("VIDIOCSYNC called (%d).\n", *mbuf);
599
600                         /* bounds check */
601                         if (*mbuf < 0 || *mbuf >= pwc_mbufs)
602                                 return -EINVAL;
603                         /* check if this buffer was requested anyway */
604                         if (pdev->image_used[*mbuf] == 0)
605                                 return -EINVAL;
606
607                         /* Add ourselves to the frame wait-queue.
608
609                            FIXME: needs auditing for safety.
610                            QUESTION: In what respect? I think that using the
611                                      frameq is safe now.
612                          */
613                         add_wait_queue(&pdev->frameq, &wait);
614                         while (pdev->full_frames == NULL) {
615                                 /* Check for unplugged/etc. here */
616                                 if (pdev->error_status) {
617                                         remove_wait_queue(&pdev->frameq, &wait);
618                                         set_current_state(TASK_RUNNING);
619                                         return -pdev->error_status;
620                                 }
621
622                                 if (signal_pending(current)) {
623                                         remove_wait_queue(&pdev->frameq, &wait);
624                                         set_current_state(TASK_RUNNING);
625                                         return -ERESTARTSYS;
626                                 }
627                                 schedule();
628                                 set_current_state(TASK_INTERRUPTIBLE);
629                         }
630                         remove_wait_queue(&pdev->frameq, &wait);
631                         set_current_state(TASK_RUNNING);
632
633                         /* The frame is ready. Expand in the image buffer
634                            requested by the user. I don't care if you
635                            mmap() 5 buffers and request data in this order:
636                            buffer 4 2 3 0 1 2 3 0 4 3 1 . . .
637                            Grabber hardware may not be so forgiving.
638                          */
639                         PWC_DEBUG_READ("VIDIOCSYNC: frame ready.\n");
640                         pdev->fill_image = *mbuf; /* tell in which buffer we want the image to be expanded */
641                         /* Decompress, etc */
642                         ret = pwc_handle_frame(pdev);
643                         pdev->image_used[*mbuf] = 0;
644                         if (ret)
645                                 return -EFAULT;
646                         break;
647                 }
648
649                 case VIDIOCGAUDIO:
650                 {
651                         struct video_audio *v = arg;
652
653                         strcpy(v->name, "Microphone");
654                         v->audio = -1; /* unknown audio minor */
655                         v->flags = 0;
656                         v->mode = VIDEO_SOUND_MONO;
657                         v->volume = 0;
658                         v->bass = 0;
659                         v->treble = 0;
660                         v->balance = 0x8000;
661                         v->step = 1;
662                         break;
663                 }
664
665                 case VIDIOCSAUDIO:
666                 {
667                         /* Dummy: nothing can be set */
668                         break;
669                 }
670
671                 case VIDIOCGUNIT:
672                 {
673                         struct video_unit *vu = arg;
674
675                         vu->video = pdev->vdev->minor & 0x3F;
676                         vu->audio = -1; /* not known yet */
677                         vu->vbi = -1;
678                         vu->radio = -1;
679                         vu->teletext = -1;
680                         break;
681                 }
682
683                 /* V4L2 Layer */
684                 case VIDIOC_QUERYCAP:
685                 {
686                     struct v4l2_capability *cap = arg;
687
688                     PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCAP) This application "\
689                                        "try to use the v4l2 layer\n");
690                     strcpy(cap->driver,PWC_NAME);
691                     strlcpy(cap->card, vdev->name, sizeof(cap->card));
692                     usb_make_path(pdev->udev,cap->bus_info,sizeof(cap->bus_info));
693                     cap->version = PWC_VERSION_CODE;
694                     cap->capabilities =
695                         V4L2_CAP_VIDEO_CAPTURE  |
696                         V4L2_CAP_STREAMING      |
697                         V4L2_CAP_READWRITE;
698                     return 0;
699                 }
700
701                 case VIDIOC_ENUMINPUT:
702                 {
703                     struct v4l2_input *i = arg;
704
705                     if ( i->index )     /* Only one INPUT is supported */
706                           return -EINVAL;
707
708                     memset(i, 0, sizeof(struct v4l2_input));
709                     strcpy(i->name, "usb");
710                     return 0;
711                 }
712
713                 case VIDIOC_G_INPUT:
714                 {
715                     int *i = arg;
716                     *i = 0;     /* Only one INPUT is supported */
717                     return 0;
718                 }
719                 case VIDIOC_S_INPUT:
720                 {
721                         int *i = arg;
722
723                         if ( *i ) {     /* Only one INPUT is supported */
724                                 PWC_DEBUG_IOCTL("Only one input source is"\
725                                         " supported with this webcam.\n");
726                                 return -EINVAL;
727                         }
728                         return 0;
729                 }
730
731                 /* TODO: */
732                 case VIDIOC_QUERYCTRL:
733                 {
734                         struct v4l2_queryctrl *c = arg;
735                         int i;
736
737                         PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) query id=%d\n", c->id);
738                         for (i=0; i<sizeof(pwc_controls)/sizeof(struct v4l2_queryctrl); i++) {
739                                 if (pwc_controls[i].id == c->id) {
740                                         PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) found\n");
741                                         memcpy(c,&pwc_controls[i],sizeof(struct v4l2_queryctrl));
742                                         return 0;
743                                 }
744                         }
745                         PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) not found\n");
746
747                         return -EINVAL;
748                 }
749                 case VIDIOC_G_CTRL:
750                 {
751                         struct v4l2_control *c = arg;
752                         int ret;
753
754                         switch (c->id)
755                         {
756                                 case V4L2_CID_BRIGHTNESS:
757                                         c->value = pwc_get_brightness(pdev);
758                                         if (c->value<0)
759                                                 return -EINVAL;
760                                         return 0;
761                                 case V4L2_CID_CONTRAST:
762                                         c->value = pwc_get_contrast(pdev);
763                                         if (c->value<0)
764                                                 return -EINVAL;
765                                         return 0;
766                                 case V4L2_CID_SATURATION:
767                                         ret = pwc_get_saturation(pdev, &c->value);
768                                         if (ret<0)
769                                                 return -EINVAL;
770                                         return 0;
771                                 case V4L2_CID_GAMMA:
772                                         c->value = pwc_get_gamma(pdev);
773                                         if (c->value<0)
774                                                 return -EINVAL;
775                                         return 0;
776                                 case V4L2_CID_RED_BALANCE:
777                                         ret = pwc_get_red_gain(pdev, &c->value);
778                                         if (ret<0)
779                                                 return -EINVAL;
780                                         c->value >>= 8;
781                                         return 0;
782                                 case V4L2_CID_BLUE_BALANCE:
783                                         ret = pwc_get_blue_gain(pdev, &c->value);
784                                         if (ret<0)
785                                                 return -EINVAL;
786                                         c->value >>= 8;
787                                         return 0;
788                                 case V4L2_CID_AUTO_WHITE_BALANCE:
789                                         ret = pwc_get_awb(pdev);
790                                         if (ret<0)
791                                                 return -EINVAL;
792                                         c->value = (ret == PWC_WB_MANUAL)?0:1;
793                                         return 0;
794                                 case V4L2_CID_GAIN:
795                                         ret = pwc_get_agc(pdev, &c->value);
796                                         if (ret<0)
797                                                 return -EINVAL;
798                                         c->value >>= 8;
799                                         return 0;
800                                 case V4L2_CID_AUTOGAIN:
801                                         ret = pwc_get_agc(pdev, &c->value);
802                                         if (ret<0)
803                                                 return -EINVAL;
804                                         c->value = (c->value < 0)?1:0;
805                                         return 0;
806                                 case V4L2_CID_EXPOSURE:
807                                         ret = pwc_get_shutter_speed(pdev, &c->value);
808                                         if (ret<0)
809                                                 return -EINVAL;
810                                         return 0;
811                                 case V4L2_CID_PRIVATE_COLOUR_MODE:
812                                         ret = pwc_get_colour_mode(pdev, &c->value);
813                                         if (ret < 0)
814                                                 return -EINVAL;
815                                         return 0;
816                                 case V4L2_CID_PRIVATE_AUTOCONTOUR:
817                                         ret = pwc_get_contour(pdev, &c->value);
818                                         if (ret < 0)
819                                                 return -EINVAL;
820                                         c->value=(c->value == -1?1:0);
821                                         return 0;
822                                 case V4L2_CID_PRIVATE_CONTOUR:
823                                         ret = pwc_get_contour(pdev, &c->value);
824                                         if (ret < 0)
825                                                 return -EINVAL;
826                                         c->value >>= 10;
827                                         return 0;
828                                 case V4L2_CID_PRIVATE_BACKLIGHT:
829                                         ret = pwc_get_backlight(pdev, &c->value);
830                                         if (ret < 0)
831                                                 return -EINVAL;
832                                         return 0;
833                                 case V4L2_CID_PRIVATE_FLICKERLESS:
834                                         ret = pwc_get_flicker(pdev, &c->value);
835                                         if (ret < 0)
836                                                 return -EINVAL;
837                                         c->value=(c->value?1:0);
838                                         return 0;
839                                 case V4L2_CID_PRIVATE_NOISE_REDUCTION:
840                                         ret = pwc_get_dynamic_noise(pdev, &c->value);
841                                         if (ret < 0)
842                                                 return -EINVAL;
843                                         return 0;
844
845                                 case V4L2_CID_PRIVATE_SAVE_USER:
846                                 case V4L2_CID_PRIVATE_RESTORE_USER:
847                                 case V4L2_CID_PRIVATE_RESTORE_FACTORY:
848                                         return -EINVAL;
849                         }
850                         return -EINVAL;
851                 }
852                 case VIDIOC_S_CTRL:
853                 {
854                         struct v4l2_control *c = arg;
855                         int ret;
856
857                         switch (c->id)
858                         {
859                                 case V4L2_CID_BRIGHTNESS:
860                                         c->value <<= 9;
861                                         ret = pwc_set_brightness(pdev, c->value);
862                                         if (ret<0)
863                                                 return -EINVAL;
864                                         return 0;
865                                 case V4L2_CID_CONTRAST:
866                                         c->value <<= 10;
867                                         ret = pwc_set_contrast(pdev, c->value);
868                                         if (ret<0)
869                                                 return -EINVAL;
870                                         return 0;
871                                 case V4L2_CID_SATURATION:
872                                         ret = pwc_set_saturation(pdev, c->value);
873                                         if (ret<0)
874                                           return -EINVAL;
875                                         return 0;
876                                 case V4L2_CID_GAMMA:
877                                         c->value <<= 11;
878                                         ret = pwc_set_gamma(pdev, c->value);
879                                         if (ret<0)
880                                                 return -EINVAL;
881                                         return 0;
882                                 case V4L2_CID_RED_BALANCE:
883                                         c->value <<= 8;
884                                         ret = pwc_set_red_gain(pdev, c->value);
885                                         if (ret<0)
886                                                 return -EINVAL;
887                                         return 0;
888                                 case V4L2_CID_BLUE_BALANCE:
889                                         c->value <<= 8;
890                                         ret = pwc_set_blue_gain(pdev, c->value);
891                                         if (ret<0)
892                                                 return -EINVAL;
893                                         return 0;
894                                 case V4L2_CID_AUTO_WHITE_BALANCE:
895                                         c->value = (c->value == 0)?PWC_WB_MANUAL:PWC_WB_AUTO;
896                                         ret = pwc_set_awb(pdev, c->value);
897                                         if (ret<0)
898                                                 return -EINVAL;
899                                         return 0;
900                                 case V4L2_CID_EXPOSURE:
901                                         c->value <<= 8;
902                                         ret = pwc_set_shutter_speed(pdev, c->value?0:1, c->value);
903                                         if (ret<0)
904                                                 return -EINVAL;
905                                         return 0;
906                                 case V4L2_CID_AUTOGAIN:
907                                         /* autogain off means nothing without a gain */
908                                         if (c->value == 0)
909                                                 return 0;
910                                         ret = pwc_set_agc(pdev, c->value, 0);
911                                         if (ret<0)
912                                                 return -EINVAL;
913                                         return 0;
914                                 case V4L2_CID_GAIN:
915                                         c->value <<= 8;
916                                         ret = pwc_set_agc(pdev, 0, c->value);
917                                         if (ret<0)
918                                                 return -EINVAL;
919                                         return 0;
920                                 case V4L2_CID_PRIVATE_SAVE_USER:
921                                         if (pwc_save_user(pdev))
922                                                 return -EINVAL;
923                                         return 0;
924                                 case V4L2_CID_PRIVATE_RESTORE_USER:
925                                         if (pwc_restore_user(pdev))
926                                                 return -EINVAL;
927                                         return 0;
928                                 case V4L2_CID_PRIVATE_RESTORE_FACTORY:
929                                         if (pwc_restore_factory(pdev))
930                                                 return -EINVAL;
931                                         return 0;
932                                 case V4L2_CID_PRIVATE_COLOUR_MODE:
933                                         ret = pwc_set_colour_mode(pdev, c->value);
934                                         if (ret < 0)
935                                           return -EINVAL;
936                                         return 0;
937                                 case V4L2_CID_PRIVATE_AUTOCONTOUR:
938                                   c->value=(c->value == 1)?-1:0;
939                                   ret = pwc_set_contour(pdev, c->value);
940                                   if (ret < 0)
941                                     return -EINVAL;
942                                   return 0;
943                                 case V4L2_CID_PRIVATE_CONTOUR:
944                                   c->value <<= 10;
945                                   ret = pwc_set_contour(pdev, c->value);
946                                   if (ret < 0)
947                                     return -EINVAL;
948                                   return 0;
949                                 case V4L2_CID_PRIVATE_BACKLIGHT:
950                                   ret = pwc_set_backlight(pdev, c->value);
951                                   if (ret < 0)
952                                     return -EINVAL;
953                                   return 0;
954                                 case V4L2_CID_PRIVATE_FLICKERLESS:
955                                   ret = pwc_set_flicker(pdev, c->value);
956                                   if (ret < 0)
957                                     return -EINVAL;
958                                 case V4L2_CID_PRIVATE_NOISE_REDUCTION:
959                                   ret = pwc_set_dynamic_noise(pdev, c->value);
960                                   if (ret < 0)
961                                     return -EINVAL;
962                                   return 0;
963
964                         }
965                         return -EINVAL;
966                 }
967
968                 case VIDIOC_ENUM_FMT:
969                 {
970                         struct v4l2_fmtdesc *f = arg;
971                         int index;
972
973                         if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
974                               return -EINVAL;
975
976                         /* We only support two format: the raw format, and YUV */
977                         index = f->index;
978                         memset(f,0,sizeof(struct v4l2_fmtdesc));
979                         f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
980                         f->index = index;
981                         switch(index)
982                         {
983                                 case 0:
984                                         /* RAW format */
985                                         f->pixelformat = pdev->type<=646?V4L2_PIX_FMT_PWC1:V4L2_PIX_FMT_PWC2;
986                                         f->flags = V4L2_FMT_FLAG_COMPRESSED;
987                                         strlcpy(f->description,"Raw Philips Webcam",sizeof(f->description));
988                                         break;
989                                 case 1:
990                                         f->pixelformat = V4L2_PIX_FMT_YUV420;
991                                         strlcpy(f->description,"4:2:0, planar, Y-Cb-Cr",sizeof(f->description));
992                                         break;
993                                 default:
994                                         return -EINVAL;
995                         }
996                         return 0;
997                 }
998
999                 case VIDIOC_G_FMT:
1000                 {
1001                         struct v4l2_format *f = arg;
1002
1003                         PWC_DEBUG_IOCTL("ioctl(VIDIOC_G_FMT) return size %dx%d\n",pdev->image.x,pdev->image.y);
1004                         if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1005                               return -EINVAL;
1006
1007                         pwc_vidioc_fill_fmt(pdev, f);
1008
1009                         return 0;
1010                 }
1011
1012                 case VIDIOC_TRY_FMT:
1013                         return pwc_vidioc_try_fmt(pdev, arg);
1014
1015                 case VIDIOC_S_FMT:
1016                         return pwc_vidioc_set_fmt(pdev, arg);
1017
1018                 case VIDIOC_G_STD:
1019                 {
1020                         v4l2_std_id *std = arg;
1021                         *std = V4L2_STD_UNKNOWN;
1022                         return 0;
1023                 }
1024
1025                 case VIDIOC_S_STD:
1026                 {
1027                         v4l2_std_id *std = arg;
1028                         if (*std != V4L2_STD_UNKNOWN)
1029                                 return -EINVAL;
1030                         return 0;
1031                 }
1032
1033                 case VIDIOC_ENUMSTD:
1034                 {
1035                         struct v4l2_standard *std = arg;
1036                         if (std->index != 0)
1037                                 return -EINVAL;
1038                         std->id = V4L2_STD_UNKNOWN;
1039                         strncpy(std->name, "webcam", sizeof(std->name));
1040                         return 0;
1041                 }
1042
1043                 case VIDIOC_REQBUFS:
1044                 {
1045                         struct v4l2_requestbuffers *rb = arg;
1046                         int nbuffers;
1047
1048                         PWC_DEBUG_IOCTL("ioctl(VIDIOC_REQBUFS) count=%d\n",rb->count);
1049                         if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1050                                 return -EINVAL;
1051                         if (rb->memory != V4L2_MEMORY_MMAP)
1052                                 return -EINVAL;
1053
1054                         nbuffers = rb->count;
1055                         if (nbuffers < 2)
1056                                 nbuffers = 2;
1057                         else if (nbuffers > pwc_mbufs)
1058                                 nbuffers = pwc_mbufs;
1059                         /* Force to use our # of buffers */
1060                         rb->count = pwc_mbufs;
1061                         return 0;
1062                 }
1063
1064                 case VIDIOC_QUERYBUF:
1065                 {
1066                         struct v4l2_buffer *buf = arg;
1067                         int index;
1068
1069                         PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) index=%d\n",buf->index);
1070                         if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
1071                                 PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad type\n");
1072                                 return -EINVAL;
1073                         }
1074                         if (buf->memory != V4L2_MEMORY_MMAP) {
1075                                 PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad memory type\n");
1076                                 return -EINVAL;
1077                         }
1078                         index = buf->index;
1079                         if (index < 0 || index >= pwc_mbufs) {
1080                                 PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad index %d\n", buf->index);
1081                                 return -EINVAL;
1082                         }
1083
1084                         memset(buf, 0, sizeof(struct v4l2_buffer));
1085                         buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1086                         buf->index = index;
1087                         buf->m.offset = index * pdev->len_per_image;
1088                         if (pdev->vpalette == VIDEO_PALETTE_RAW)
1089                                 buf->bytesused = pdev->frame_size + sizeof(struct pwc_raw_frame);
1090                         else
1091                                 buf->bytesused = pdev->view.size;
1092                         buf->field = V4L2_FIELD_NONE;
1093                         buf->memory = V4L2_MEMORY_MMAP;
1094                         //buf->flags = V4L2_BUF_FLAG_MAPPED;
1095                         buf->length = pdev->len_per_image;
1096
1097                         PWC_DEBUG_READ("VIDIOC_QUERYBUF: index=%d\n",buf->index);
1098                         PWC_DEBUG_READ("VIDIOC_QUERYBUF: m.offset=%d\n",buf->m.offset);
1099                         PWC_DEBUG_READ("VIDIOC_QUERYBUF: bytesused=%d\n",buf->bytesused);
1100
1101                         return 0;
1102                 }
1103
1104                 case VIDIOC_QBUF:
1105                 {
1106                         struct v4l2_buffer *buf = arg;
1107
1108                         PWC_DEBUG_IOCTL("ioctl(VIDIOC_QBUF) index=%d\n",buf->index);
1109                         if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1110                                 return -EINVAL;
1111                         if (buf->memory != V4L2_MEMORY_MMAP)
1112                                 return -EINVAL;
1113                         if (buf->index < 0 || buf->index >= pwc_mbufs)
1114                                 return -EINVAL;
1115
1116                         buf->flags |= V4L2_BUF_FLAG_QUEUED;
1117                         buf->flags &= ~V4L2_BUF_FLAG_DONE;
1118
1119                         return 0;
1120                 }
1121
1122                 case VIDIOC_DQBUF:
1123                 {
1124                         struct v4l2_buffer *buf = arg;
1125                         int ret;
1126
1127                         PWC_DEBUG_IOCTL("ioctl(VIDIOC_DQBUF)\n");
1128
1129                         if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1130                                 return -EINVAL;
1131
1132                         /* Add ourselves to the frame wait-queue.
1133
1134                            FIXME: needs auditing for safety.
1135                            QUESTION: In what respect? I think that using the
1136                                      frameq is safe now.
1137                          */
1138                         add_wait_queue(&pdev->frameq, &wait);
1139                         while (pdev->full_frames == NULL) {
1140                                 if (pdev->error_status) {
1141                                         remove_wait_queue(&pdev->frameq, &wait);
1142                                         set_current_state(TASK_RUNNING);
1143                                         return -pdev->error_status;
1144                                 }
1145
1146                                 if (signal_pending(current)) {
1147                                         remove_wait_queue(&pdev->frameq, &wait);
1148                                         set_current_state(TASK_RUNNING);
1149                                         return -ERESTARTSYS;
1150                                 }
1151                                 schedule();
1152                                 set_current_state(TASK_INTERRUPTIBLE);
1153                         }
1154                         remove_wait_queue(&pdev->frameq, &wait);
1155                         set_current_state(TASK_RUNNING);
1156
1157                         PWC_DEBUG_IOCTL("VIDIOC_DQBUF: frame ready.\n");
1158                         /* Decompress data in pdev->images[pdev->fill_image] */
1159                         ret = pwc_handle_frame(pdev);
1160                         if (ret)
1161                                 return -EFAULT;
1162                         PWC_DEBUG_IOCTL("VIDIOC_DQBUF: after pwc_handle_frame\n");
1163
1164                         buf->index = pdev->fill_image;
1165                         if (pdev->vpalette == VIDEO_PALETTE_RAW)
1166                                 buf->bytesused = pdev->frame_size + sizeof(struct pwc_raw_frame);
1167                         else
1168                                 buf->bytesused = pdev->view.size;
1169                         buf->flags = V4L2_BUF_FLAG_MAPPED;
1170                         buf->field = V4L2_FIELD_NONE;
1171                         do_gettimeofday(&buf->timestamp);
1172                         buf->sequence = 0;
1173                         buf->memory = V4L2_MEMORY_MMAP;
1174                         buf->m.offset = pdev->fill_image * pdev->len_per_image;
1175                         buf->length = buf->bytesused;
1176                         pwc_next_image(pdev);
1177
1178                         PWC_DEBUG_IOCTL("VIDIOC_DQBUF: buf->index=%d\n",buf->index);
1179                         PWC_DEBUG_IOCTL("VIDIOC_DQBUF: buf->length=%d\n",buf->length);
1180                         PWC_DEBUG_IOCTL("VIDIOC_DQBUF: m.offset=%d\n",buf->m.offset);
1181                         PWC_DEBUG_IOCTL("VIDIOC_DQBUF: bytesused=%d\n",buf->bytesused);
1182                         PWC_DEBUG_IOCTL("VIDIOC_DQBUF: leaving\n");
1183                         return 0;
1184
1185                 }
1186
1187                 case VIDIOC_STREAMON:
1188                 {
1189                         /* WARNING: pwc_try_video_mode() called pwc_isoc_init */
1190                         pwc_isoc_init(pdev);
1191                         return 0;
1192                 }
1193
1194                 case VIDIOC_STREAMOFF:
1195                 {
1196                         pwc_isoc_cleanup(pdev);
1197                         return 0;
1198                 }
1199
1200                 default:
1201                         return pwc_ioctl(pdev, cmd, arg);
1202         } /* ..switch */
1203         return 0;
1204 }
1205
1206 /* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */