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