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