Merge branch 'for-linus' of git://git.kernel.dk/linux-block
[pandora-kernel.git] / drivers / media / video / pwc / pwc-v4l.c
1 /* Linux driver for Philips webcam
2    USB and Video4Linux interface part.
3    (C) 1999-2004 Nemosoft Unv.
4    (C) 2004-2006 Luc Saillard (luc@saillard.org)
5    (C) 2011 Hans de Goede <hdegoede@redhat.com>
6
7    NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
8    driver and thus may have bugs that are not present in the original version.
9    Please send bug reports and support requests to <luc@saillard.org>.
10    The decompression routines have been implemented by reverse-engineering the
11    Nemosoft binary pwcx module. Caveat emptor.
12
13    This program is free software; you can redistribute it and/or modify
14    it under the terms of the GNU General Public License as published by
15    the Free Software Foundation; either version 2 of the License, or
16    (at your option) any later version.
17
18    This program is distributed in the hope that it will be useful,
19    but WITHOUT ANY WARRANTY; without even the implied warranty of
20    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21    GNU General Public License for more details.
22
23    You should have received a copy of the GNU General Public License
24    along with this program; if not, write to the Free Software
25    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26
27 */
28
29 #include <linux/errno.h>
30 #include <linux/init.h>
31 #include <linux/mm.h>
32 #include <linux/module.h>
33 #include <linux/poll.h>
34 #include <linux/vmalloc.h>
35 #include <linux/jiffies.h>
36 #include <asm/io.h>
37
38 #include "pwc.h"
39
40 #define PWC_CID_CUSTOM(ctrl) ((V4L2_CID_USER_BASE | 0xf000) + custom_ ## ctrl)
41
42 static int pwc_g_volatile_ctrl(struct v4l2_ctrl *ctrl);
43 static int pwc_s_ctrl(struct v4l2_ctrl *ctrl);
44
45 static const struct v4l2_ctrl_ops pwc_ctrl_ops = {
46         .g_volatile_ctrl = pwc_g_volatile_ctrl,
47         .s_ctrl = pwc_s_ctrl,
48 };
49
50 enum { awb_indoor, awb_outdoor, awb_fl, awb_manual, awb_auto };
51 enum { custom_autocontour, custom_contour, custom_noise_reduction,
52         custom_save_user, custom_restore_user, custom_restore_factory };
53
54 const char * const pwc_auto_whitebal_qmenu[] = {
55         "Indoor (Incandescant Lighting) Mode",
56         "Outdoor (Sunlight) Mode",
57         "Indoor (Fluorescent Lighting) Mode",
58         "Manual Mode",
59         "Auto Mode",
60         NULL
61 };
62
63 static const struct v4l2_ctrl_config pwc_auto_white_balance_cfg = {
64         .ops    = &pwc_ctrl_ops,
65         .id     = V4L2_CID_AUTO_WHITE_BALANCE,
66         .type   = V4L2_CTRL_TYPE_MENU,
67         .max    = awb_auto,
68         .qmenu  = pwc_auto_whitebal_qmenu,
69 };
70
71 static const struct v4l2_ctrl_config pwc_autocontour_cfg = {
72         .ops    = &pwc_ctrl_ops,
73         .id     = PWC_CID_CUSTOM(autocontour),
74         .type   = V4L2_CTRL_TYPE_BOOLEAN,
75         .name   = "Auto contour",
76         .min    = 0,
77         .max    = 1,
78         .step   = 1,
79 };
80
81 static const struct v4l2_ctrl_config pwc_contour_cfg = {
82         .ops    = &pwc_ctrl_ops,
83         .id     = PWC_CID_CUSTOM(contour),
84         .type   = V4L2_CTRL_TYPE_INTEGER,
85         .name   = "Contour",
86         .min    = 0,
87         .max    = 63,
88         .step   = 1,
89 };
90
91 static const struct v4l2_ctrl_config pwc_backlight_cfg = {
92         .ops    = &pwc_ctrl_ops,
93         .id     = V4L2_CID_BACKLIGHT_COMPENSATION,
94         .type   = V4L2_CTRL_TYPE_BOOLEAN,
95         .min    = 0,
96         .max    = 1,
97         .step   = 1,
98 };
99
100 static const struct v4l2_ctrl_config pwc_flicker_cfg = {
101         .ops    = &pwc_ctrl_ops,
102         .id     = V4L2_CID_BAND_STOP_FILTER,
103         .type   = V4L2_CTRL_TYPE_BOOLEAN,
104         .min    = 0,
105         .max    = 1,
106         .step   = 1,
107 };
108
109 static const struct v4l2_ctrl_config pwc_noise_reduction_cfg = {
110         .ops    = &pwc_ctrl_ops,
111         .id     = PWC_CID_CUSTOM(noise_reduction),
112         .type   = V4L2_CTRL_TYPE_INTEGER,
113         .name   = "Dynamic Noise Reduction",
114         .min    = 0,
115         .max    = 3,
116         .step   = 1,
117 };
118
119 static const struct v4l2_ctrl_config pwc_save_user_cfg = {
120         .ops    = &pwc_ctrl_ops,
121         .id     = PWC_CID_CUSTOM(save_user),
122         .type   = V4L2_CTRL_TYPE_BUTTON,
123         .name    = "Save User Settings",
124 };
125
126 static const struct v4l2_ctrl_config pwc_restore_user_cfg = {
127         .ops    = &pwc_ctrl_ops,
128         .id     = PWC_CID_CUSTOM(restore_user),
129         .type   = V4L2_CTRL_TYPE_BUTTON,
130         .name    = "Restore User Settings",
131 };
132
133 static const struct v4l2_ctrl_config pwc_restore_factory_cfg = {
134         .ops    = &pwc_ctrl_ops,
135         .id     = PWC_CID_CUSTOM(restore_factory),
136         .type   = V4L2_CTRL_TYPE_BUTTON,
137         .name    = "Restore Factory Settings",
138 };
139
140 int pwc_init_controls(struct pwc_device *pdev)
141 {
142         struct v4l2_ctrl_handler *hdl;
143         struct v4l2_ctrl_config cfg;
144         int r, def;
145
146         hdl = &pdev->ctrl_handler;
147         r = v4l2_ctrl_handler_init(hdl, 20);
148         if (r)
149                 return r;
150
151         /* Brightness, contrast, saturation, gamma */
152         r = pwc_get_u8_ctrl(pdev, GET_LUM_CTL, BRIGHTNESS_FORMATTER, &def);
153         if (r || def > 127)
154                 def = 63;
155         pdev->brightness = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops,
156                                 V4L2_CID_BRIGHTNESS, 0, 127, 1, def);
157
158         r = pwc_get_u8_ctrl(pdev, GET_LUM_CTL, CONTRAST_FORMATTER, &def);
159         if (r || def > 63)
160                 def = 31;
161         pdev->contrast = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops,
162                                 V4L2_CID_CONTRAST, 0, 63, 1, def);
163
164         if (pdev->type >= 675) {
165                 if (pdev->type < 730)
166                         pdev->saturation_fmt = SATURATION_MODE_FORMATTER2;
167                 else
168                         pdev->saturation_fmt = SATURATION_MODE_FORMATTER1;
169                 r = pwc_get_s8_ctrl(pdev, GET_CHROM_CTL, pdev->saturation_fmt,
170                                     &def);
171                 if (r || def < -100 || def > 100)
172                         def = 0;
173                 pdev->saturation = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops,
174                                       V4L2_CID_SATURATION, -100, 100, 1, def);
175         }
176
177         r = pwc_get_u8_ctrl(pdev, GET_LUM_CTL, GAMMA_FORMATTER, &def);
178         if (r || def > 31)
179                 def = 15;
180         pdev->gamma = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops,
181                                 V4L2_CID_GAMMA, 0, 31, 1, def);
182
183         /* auto white balance, red gain, blue gain */
184         r = pwc_get_u8_ctrl(pdev, GET_CHROM_CTL, WB_MODE_FORMATTER, &def);
185         if (r || def > awb_auto)
186                 def = awb_auto;
187         cfg = pwc_auto_white_balance_cfg;
188         cfg.name = v4l2_ctrl_get_name(cfg.id);
189         cfg.def = def;
190         pdev->auto_white_balance = v4l2_ctrl_new_custom(hdl, &cfg, NULL);
191         /* check auto controls to avoid NULL deref in v4l2_ctrl_auto_cluster */
192         if (!pdev->auto_white_balance)
193                 return hdl->error;
194
195         r = pwc_get_u8_ctrl(pdev, GET_CHROM_CTL,
196                             PRESET_MANUAL_RED_GAIN_FORMATTER, &def);
197         if (r)
198                 def = 127;
199         pdev->red_balance = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops,
200                                 V4L2_CID_RED_BALANCE, 0, 255, 1, def);
201
202         r = pwc_get_u8_ctrl(pdev, GET_CHROM_CTL,
203                             PRESET_MANUAL_BLUE_GAIN_FORMATTER, &def);
204         if (r)
205                 def = 127;
206         pdev->blue_balance = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops,
207                                 V4L2_CID_BLUE_BALANCE, 0, 255, 1, def);
208
209         v4l2_ctrl_auto_cluster(3, &pdev->auto_white_balance, awb_manual,
210                                pdev->auto_white_balance->cur.val == awb_auto);
211
212         /* autogain, gain */
213         r = pwc_get_u8_ctrl(pdev, GET_LUM_CTL, AGC_MODE_FORMATTER, &def);
214         if (r || (def != 0 && def != 0xff))
215                 def = 0;
216         /* Note a register value if 0 means auto gain is on */
217         pdev->autogain = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops,
218                                 V4L2_CID_AUTOGAIN, 0, 1, 1, def == 0);
219         if (!pdev->autogain)
220                 return hdl->error;
221
222         r = pwc_get_u8_ctrl(pdev, GET_LUM_CTL, PRESET_AGC_FORMATTER, &def);
223         if (r || def > 63)
224                 def = 31;
225         pdev->gain = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops,
226                                 V4L2_CID_GAIN, 0, 63, 1, def);
227
228         /* auto exposure, exposure */
229         if (DEVICE_USE_CODEC2(pdev->type)) {
230                 r = pwc_get_u8_ctrl(pdev, GET_LUM_CTL, SHUTTER_MODE_FORMATTER,
231                                     &def);
232                 if (r || (def != 0 && def != 0xff))
233                         def = 0;
234                 /*
235                  * def = 0 auto, def = ff manual
236                  * menu idx 0 = auto, idx 1 = manual
237                  */
238                 pdev->exposure_auto = v4l2_ctrl_new_std_menu(hdl,
239                                         &pwc_ctrl_ops,
240                                         V4L2_CID_EXPOSURE_AUTO,
241                                         1, 0, def != 0);
242                 if (!pdev->exposure_auto)
243                         return hdl->error;
244
245                 /* GET_LUM_CTL, PRESET_SHUTTER_FORMATTER is unreliable */
246                 r = pwc_get_u16_ctrl(pdev, GET_STATUS_CTL,
247                                      READ_SHUTTER_FORMATTER, &def);
248                 if (r || def > 655)
249                         def = 655;
250                 pdev->exposure = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops,
251                                         V4L2_CID_EXPOSURE, 0, 655, 1, def);
252                 /* CODEC2: separate auto gain & auto exposure */
253                 v4l2_ctrl_auto_cluster(2, &pdev->autogain, 0, true);
254                 v4l2_ctrl_auto_cluster(2, &pdev->exposure_auto,
255                                        V4L2_EXPOSURE_MANUAL, true);
256         } else if (DEVICE_USE_CODEC3(pdev->type)) {
257                 /* GET_LUM_CTL, PRESET_SHUTTER_FORMATTER is unreliable */
258                 r = pwc_get_u16_ctrl(pdev, GET_STATUS_CTL,
259                                      READ_SHUTTER_FORMATTER, &def);
260                 if (r || def > 255)
261                         def = 255;
262                 pdev->exposure = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops,
263                                         V4L2_CID_EXPOSURE, 0, 255, 1, def);
264                 /* CODEC3: both gain and exposure controlled by autogain */
265                 pdev->autogain_expo_cluster[0] = pdev->autogain;
266                 pdev->autogain_expo_cluster[1] = pdev->gain;
267                 pdev->autogain_expo_cluster[2] = pdev->exposure;
268                 v4l2_ctrl_auto_cluster(3, pdev->autogain_expo_cluster,
269                                        0, true);
270         }
271
272         /* color / bw setting */
273         r = pwc_get_u8_ctrl(pdev, GET_CHROM_CTL, COLOUR_MODE_FORMATTER,
274                          &def);
275         if (r || (def != 0 && def != 0xff))
276                 def = 0xff;
277         /* def = 0 bw, def = ff color, menu idx 0 = color, idx 1 = bw */
278         pdev->colorfx = v4l2_ctrl_new_std_menu(hdl, &pwc_ctrl_ops,
279                                 V4L2_CID_COLORFX, 1, 0, def == 0);
280
281         /* autocontour, contour */
282         r = pwc_get_u8_ctrl(pdev, GET_LUM_CTL, AUTO_CONTOUR_FORMATTER, &def);
283         if (r || (def != 0 && def != 0xff))
284                 def = 0;
285         cfg = pwc_autocontour_cfg;
286         cfg.def = def == 0;
287         pdev->autocontour = v4l2_ctrl_new_custom(hdl, &cfg, NULL);
288         if (!pdev->autocontour)
289                 return hdl->error;
290
291         r = pwc_get_u8_ctrl(pdev, GET_LUM_CTL, PRESET_CONTOUR_FORMATTER, &def);
292         if (r || def > 63)
293                 def = 31;
294         cfg = pwc_contour_cfg;
295         cfg.def = def;
296         pdev->contour = v4l2_ctrl_new_custom(hdl, &cfg, NULL);
297
298         v4l2_ctrl_auto_cluster(2, &pdev->autocontour, 0, false);
299
300         /* backlight */
301         r = pwc_get_u8_ctrl(pdev, GET_LUM_CTL,
302                             BACK_LIGHT_COMPENSATION_FORMATTER, &def);
303         if (r || (def != 0 && def != 0xff))
304                 def = 0;
305         cfg = pwc_backlight_cfg;
306         cfg.name = v4l2_ctrl_get_name(cfg.id);
307         cfg.def = def == 0;
308         pdev->backlight = v4l2_ctrl_new_custom(hdl, &cfg, NULL);
309
310         /* flikker rediction */
311         r = pwc_get_u8_ctrl(pdev, GET_LUM_CTL,
312                             FLICKERLESS_MODE_FORMATTER, &def);
313         if (r || (def != 0 && def != 0xff))
314                 def = 0;
315         cfg = pwc_flicker_cfg;
316         cfg.name = v4l2_ctrl_get_name(cfg.id);
317         cfg.def = def == 0;
318         pdev->flicker = v4l2_ctrl_new_custom(hdl, &cfg, NULL);
319
320         /* Dynamic noise reduction */
321         r = pwc_get_u8_ctrl(pdev, GET_LUM_CTL,
322                             DYNAMIC_NOISE_CONTROL_FORMATTER, &def);
323         if (r || def > 3)
324                 def = 2;
325         cfg = pwc_noise_reduction_cfg;
326         cfg.def = def;
327         pdev->noise_reduction = v4l2_ctrl_new_custom(hdl, &cfg, NULL);
328
329         /* Save / Restore User / Factory Settings */
330         pdev->save_user = v4l2_ctrl_new_custom(hdl, &pwc_save_user_cfg, NULL);
331         pdev->restore_user = v4l2_ctrl_new_custom(hdl, &pwc_restore_user_cfg,
332                                                   NULL);
333         if (pdev->restore_user)
334                 pdev->restore_user->flags = V4L2_CTRL_FLAG_UPDATE;
335         pdev->restore_factory = v4l2_ctrl_new_custom(hdl,
336                                                      &pwc_restore_factory_cfg,
337                                                      NULL);
338         if (pdev->restore_factory)
339                 pdev->restore_factory->flags = V4L2_CTRL_FLAG_UPDATE;
340
341         if (!(pdev->features & FEATURE_MOTOR_PANTILT))
342                 return hdl->error;
343
344         /* Motor pan / tilt / reset */
345         pdev->motor_pan = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops,
346                                 V4L2_CID_PAN_RELATIVE, -4480, 4480, 64, 0);
347         if (!pdev->motor_pan)
348                 return hdl->error;
349         pdev->motor_tilt = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops,
350                                 V4L2_CID_TILT_RELATIVE, -1920, 1920, 64, 0);
351         pdev->motor_pan_reset = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops,
352                                 V4L2_CID_PAN_RESET, 0, 0, 0, 0);
353         pdev->motor_tilt_reset = v4l2_ctrl_new_std(hdl, &pwc_ctrl_ops,
354                                 V4L2_CID_TILT_RESET, 0, 0, 0, 0);
355         v4l2_ctrl_cluster(4, &pdev->motor_pan);
356
357         return hdl->error;
358 }
359
360 static void pwc_vidioc_fill_fmt(const struct pwc_device *pdev, struct v4l2_format *f)
361 {
362         memset(&f->fmt.pix, 0, sizeof(struct v4l2_pix_format));
363         f->fmt.pix.width        = pdev->view.x;
364         f->fmt.pix.height       = pdev->view.y;
365         f->fmt.pix.field        = V4L2_FIELD_NONE;
366         if (pdev->pixfmt == V4L2_PIX_FMT_YUV420) {
367                 f->fmt.pix.pixelformat  = V4L2_PIX_FMT_YUV420;
368                 f->fmt.pix.bytesperline = (f->fmt.pix.width * 3)/2;
369                 f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
370         } else {
371                 /* vbandlength contains 4 lines ...  */
372                 f->fmt.pix.bytesperline = pdev->vbandlength/4;
373                 f->fmt.pix.sizeimage = pdev->frame_size + sizeof(struct pwc_raw_frame);
374                 if (DEVICE_USE_CODEC1(pdev->type))
375                         f->fmt.pix.pixelformat  = V4L2_PIX_FMT_PWC1;
376                 else
377                         f->fmt.pix.pixelformat  = V4L2_PIX_FMT_PWC2;
378         }
379         PWC_DEBUG_IOCTL("pwc_vidioc_fill_fmt() "
380                         "width=%d, height=%d, bytesperline=%d, sizeimage=%d, pixelformat=%c%c%c%c\n",
381                         f->fmt.pix.width,
382                         f->fmt.pix.height,
383                         f->fmt.pix.bytesperline,
384                         f->fmt.pix.sizeimage,
385                         (f->fmt.pix.pixelformat)&255,
386                         (f->fmt.pix.pixelformat>>8)&255,
387                         (f->fmt.pix.pixelformat>>16)&255,
388                         (f->fmt.pix.pixelformat>>24)&255);
389 }
390
391 /* ioctl(VIDIOC_TRY_FMT) */
392 static int pwc_vidioc_try_fmt(struct pwc_device *pdev, struct v4l2_format *f)
393 {
394         if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
395                 PWC_DEBUG_IOCTL("Bad video type must be V4L2_BUF_TYPE_VIDEO_CAPTURE\n");
396                 return -EINVAL;
397         }
398
399         switch (f->fmt.pix.pixelformat) {
400                 case V4L2_PIX_FMT_YUV420:
401                         break;
402                 case V4L2_PIX_FMT_PWC1:
403                         if (DEVICE_USE_CODEC23(pdev->type)) {
404                                 PWC_DEBUG_IOCTL("codec1 is only supported for old pwc webcam\n");
405                                 return -EINVAL;
406                         }
407                         break;
408                 case V4L2_PIX_FMT_PWC2:
409                         if (DEVICE_USE_CODEC1(pdev->type)) {
410                                 PWC_DEBUG_IOCTL("codec23 is only supported for new pwc webcam\n");
411                                 return -EINVAL;
412                         }
413                         break;
414                 default:
415                         PWC_DEBUG_IOCTL("Unsupported pixel format\n");
416                         return -EINVAL;
417
418         }
419
420         if (f->fmt.pix.width > pdev->view_max.x)
421                 f->fmt.pix.width = pdev->view_max.x;
422         else if (f->fmt.pix.width < pdev->view_min.x)
423                 f->fmt.pix.width = pdev->view_min.x;
424
425         if (f->fmt.pix.height > pdev->view_max.y)
426                 f->fmt.pix.height = pdev->view_max.y;
427         else if (f->fmt.pix.height < pdev->view_min.y)
428                 f->fmt.pix.height = pdev->view_min.y;
429
430         return 0;
431 }
432
433 /* ioctl(VIDIOC_SET_FMT) */
434
435 static int pwc_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f)
436 {
437         struct pwc_device *pdev = video_drvdata(file);
438         int ret, fps, snapshot, compression, pixelformat;
439
440         if (!pdev->udev)
441                 return -ENODEV;
442
443         if (pdev->capt_file != NULL &&
444             pdev->capt_file != file)
445                 return -EBUSY;
446
447         pdev->capt_file = file;
448
449         ret = pwc_vidioc_try_fmt(pdev, f);
450         if (ret<0)
451                 return ret;
452
453         pixelformat = f->fmt.pix.pixelformat;
454         compression = pdev->vcompression;
455         snapshot = 0;
456         fps = pdev->vframes;
457         if (f->fmt.pix.priv) {
458                 compression = (f->fmt.pix.priv & PWC_QLT_MASK) >> PWC_QLT_SHIFT;
459                 snapshot = !!(f->fmt.pix.priv & PWC_FPS_SNAPSHOT);
460                 fps = (f->fmt.pix.priv & PWC_FPS_FRMASK) >> PWC_FPS_SHIFT;
461                 if (fps == 0)
462                         fps = pdev->vframes;
463         }
464
465         if (pixelformat != V4L2_PIX_FMT_YUV420 &&
466             pixelformat != V4L2_PIX_FMT_PWC1 &&
467             pixelformat != V4L2_PIX_FMT_PWC2)
468                 return -EINVAL;
469
470         if (vb2_is_streaming(&pdev->vb_queue))
471                 return -EBUSY;
472
473         PWC_DEBUG_IOCTL("Trying to set format to: width=%d height=%d fps=%d "
474                         "compression=%d snapshot=%d format=%c%c%c%c\n",
475                         f->fmt.pix.width, f->fmt.pix.height, fps,
476                         compression, snapshot,
477                         (pixelformat)&255,
478                         (pixelformat>>8)&255,
479                         (pixelformat>>16)&255,
480                         (pixelformat>>24)&255);
481
482         ret = pwc_set_video_mode(pdev,
483                                  f->fmt.pix.width,
484                                  f->fmt.pix.height,
485                                  fps,
486                                  compression,
487                                  snapshot);
488
489         PWC_DEBUG_IOCTL("pwc_set_video_mode(), return=%d\n", ret);
490
491         if (ret)
492                 return ret;
493
494         pdev->pixfmt = pixelformat;
495
496         pwc_vidioc_fill_fmt(pdev, f);
497
498         return 0;
499
500 }
501
502 static int pwc_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
503 {
504         struct pwc_device *pdev = video_drvdata(file);
505
506         if (!pdev->udev)
507                 return -ENODEV;
508
509         strcpy(cap->driver, PWC_NAME);
510         strlcpy(cap->card, pdev->vdev.name, sizeof(cap->card));
511         usb_make_path(pdev->udev, cap->bus_info, sizeof(cap->bus_info));
512         cap->capabilities =
513                 V4L2_CAP_VIDEO_CAPTURE  |
514                 V4L2_CAP_STREAMING      |
515                 V4L2_CAP_READWRITE;
516         return 0;
517 }
518
519 static int pwc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
520 {
521         if (i->index)   /* Only one INPUT is supported */
522                 return -EINVAL;
523
524         strcpy(i->name, "usb");
525         return 0;
526 }
527
528 static int pwc_g_input(struct file *file, void *fh, unsigned int *i)
529 {
530         *i = 0;
531         return 0;
532 }
533
534 static int pwc_s_input(struct file *file, void *fh, unsigned int i)
535 {
536         return i ? -EINVAL : 0;
537 }
538
539 static int pwc_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
540 {
541         struct pwc_device *pdev =
542                 container_of(ctrl->handler, struct pwc_device, ctrl_handler);
543         int ret = 0;
544
545         /*
546          * Sometimes it can take quite long for the pwc to complete usb control
547          * transfers, so release the modlock to give streaming by another
548          * process / thread the chance to continue with a dqbuf.
549          */
550         mutex_unlock(&pdev->modlock);
551
552         /*
553          * Take the udev-lock to protect against the disconnect handler
554          * completing and setting dev->udev to NULL underneath us. Other code
555          * does not need to do this since it is protected by the modlock.
556          */
557         mutex_lock(&pdev->udevlock);
558
559         if (!pdev->udev) {
560                 ret = -ENODEV;
561                 goto leave;
562         }
563
564         switch (ctrl->id) {
565         case V4L2_CID_AUTO_WHITE_BALANCE:
566                 if (pdev->color_bal_valid && time_before(jiffies,
567                                 pdev->last_color_bal_update + HZ / 4)) {
568                         pdev->red_balance->val  = pdev->last_red_balance;
569                         pdev->blue_balance->val = pdev->last_blue_balance;
570                         break;
571                 }
572                 ret = pwc_get_u8_ctrl(pdev, GET_STATUS_CTL,
573                                       READ_RED_GAIN_FORMATTER,
574                                       &pdev->red_balance->val);
575                 if (ret)
576                         break;
577                 ret = pwc_get_u8_ctrl(pdev, GET_STATUS_CTL,
578                                       READ_BLUE_GAIN_FORMATTER,
579                                       &pdev->blue_balance->val);
580                 if (ret)
581                         break;
582                 pdev->last_red_balance  = pdev->red_balance->val;
583                 pdev->last_blue_balance = pdev->blue_balance->val;
584                 pdev->last_color_bal_update = jiffies;
585                 pdev->color_bal_valid = true;
586                 break;
587         case V4L2_CID_AUTOGAIN:
588                 if (pdev->gain_valid && time_before(jiffies,
589                                 pdev->last_gain_update + HZ / 4)) {
590                         pdev->gain->val = pdev->last_gain;
591                         break;
592                 }
593                 ret = pwc_get_u8_ctrl(pdev, GET_STATUS_CTL,
594                                       READ_AGC_FORMATTER, &pdev->gain->val);
595                 if (ret)
596                         break;
597                 pdev->last_gain = pdev->gain->val;
598                 pdev->last_gain_update = jiffies;
599                 pdev->gain_valid = true;
600                 if (!DEVICE_USE_CODEC3(pdev->type))
601                         break;
602                 /* Fall through for CODEC3 where autogain also controls expo */
603         case V4L2_CID_EXPOSURE_AUTO:
604                 if (pdev->exposure_valid && time_before(jiffies,
605                                 pdev->last_exposure_update + HZ / 4)) {
606                         pdev->exposure->val = pdev->last_exposure;
607                         break;
608                 }
609                 ret = pwc_get_u16_ctrl(pdev, GET_STATUS_CTL,
610                                        READ_SHUTTER_FORMATTER,
611                                        &pdev->exposure->val);
612                 if (ret)
613                         break;
614                 pdev->last_exposure = pdev->exposure->val;
615                 pdev->last_exposure_update = jiffies;
616                 pdev->exposure_valid = true;
617                 break;
618         default:
619                 ret = -EINVAL;
620         }
621
622         if (ret)
623                 PWC_ERROR("g_ctrl %s error %d\n", ctrl->name, ret);
624
625 leave:
626         mutex_unlock(&pdev->udevlock);
627         mutex_lock(&pdev->modlock);
628         return ret;
629 }
630
631 static int pwc_set_awb(struct pwc_device *pdev)
632 {
633         int ret = 0;
634
635         if (pdev->auto_white_balance->is_new) {
636                 ret = pwc_set_u8_ctrl(pdev, SET_CHROM_CTL,
637                                       WB_MODE_FORMATTER,
638                                       pdev->auto_white_balance->val);
639                 if (ret)
640                         return ret;
641
642                 /* Update val when coming from auto or going to a preset */
643                 if (pdev->red_balance->is_volatile ||
644                     pdev->auto_white_balance->val == awb_indoor ||
645                     pdev->auto_white_balance->val == awb_outdoor ||
646                     pdev->auto_white_balance->val == awb_fl) {
647                         if (!pdev->red_balance->is_new)
648                                 pwc_get_u8_ctrl(pdev, GET_STATUS_CTL,
649                                         READ_RED_GAIN_FORMATTER,
650                                         &pdev->red_balance->val);
651                         if (!pdev->blue_balance->is_new)
652                                 pwc_get_u8_ctrl(pdev, GET_STATUS_CTL,
653                                         READ_BLUE_GAIN_FORMATTER,
654                                         &pdev->blue_balance->val);
655                 }
656                 if (pdev->auto_white_balance->val == awb_auto) {
657                         pdev->red_balance->is_volatile = true;
658                         pdev->blue_balance->is_volatile = true;
659                         pdev->color_bal_valid = false; /* Force cache update */
660                 } else {
661                         pdev->red_balance->is_volatile = false;
662                         pdev->blue_balance->is_volatile = false;
663                 }
664         }
665
666         if (ret == 0 && pdev->red_balance->is_new) {
667                 if (pdev->auto_white_balance->val != awb_manual)
668                         return -EBUSY;
669                 ret = pwc_set_u8_ctrl(pdev, SET_CHROM_CTL,
670                                       PRESET_MANUAL_RED_GAIN_FORMATTER,
671                                       pdev->red_balance->val);
672         }
673
674         if (ret == 0 && pdev->blue_balance->is_new) {
675                 if (pdev->auto_white_balance->val != awb_manual)
676                         return -EBUSY;
677                 ret = pwc_set_u8_ctrl(pdev, SET_CHROM_CTL,
678                                       PRESET_MANUAL_BLUE_GAIN_FORMATTER,
679                                       pdev->blue_balance->val);
680         }
681         return ret;
682 }
683
684 /* For CODEC2 models which have separate autogain and auto exposure */
685 static int pwc_set_autogain(struct pwc_device *pdev)
686 {
687         int ret = 0;
688
689         if (pdev->autogain->is_new) {
690                 ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL,
691                                       AGC_MODE_FORMATTER,
692                                       pdev->autogain->val ? 0 : 0xff);
693                 if (ret)
694                         return ret;
695                 if (pdev->autogain->val)
696                         pdev->gain_valid = false; /* Force cache update */
697                 else if (!pdev->gain->is_new)
698                         pwc_get_u8_ctrl(pdev, GET_STATUS_CTL,
699                                         READ_AGC_FORMATTER,
700                                         &pdev->gain->val);
701         }
702         if (ret == 0 && pdev->gain->is_new) {
703                 if (pdev->autogain->val)
704                         return -EBUSY;
705                 ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL,
706                                       PRESET_AGC_FORMATTER,
707                                       pdev->gain->val);
708         }
709         return ret;
710 }
711
712 /* For CODEC2 models which have separate autogain and auto exposure */
713 static int pwc_set_exposure_auto(struct pwc_device *pdev)
714 {
715         int ret = 0;
716         int is_auto = pdev->exposure_auto->val == V4L2_EXPOSURE_AUTO;
717
718         if (pdev->exposure_auto->is_new) {
719                 ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL,
720                                       SHUTTER_MODE_FORMATTER,
721                                       is_auto ? 0 : 0xff);
722                 if (ret)
723                         return ret;
724                 if (is_auto)
725                         pdev->exposure_valid = false; /* Force cache update */
726                 else if (!pdev->exposure->is_new)
727                         pwc_get_u16_ctrl(pdev, GET_STATUS_CTL,
728                                          READ_SHUTTER_FORMATTER,
729                                          &pdev->exposure->val);
730         }
731         if (ret == 0 && pdev->exposure->is_new) {
732                 if (is_auto)
733                         return -EBUSY;
734                 ret = pwc_set_u16_ctrl(pdev, SET_LUM_CTL,
735                                        PRESET_SHUTTER_FORMATTER,
736                                        pdev->exposure->val);
737         }
738         return ret;
739 }
740
741 /* For CODEC3 models which have autogain controlling both gain and exposure */
742 static int pwc_set_autogain_expo(struct pwc_device *pdev)
743 {
744         int ret = 0;
745
746         if (pdev->autogain->is_new) {
747                 ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL,
748                                       AGC_MODE_FORMATTER,
749                                       pdev->autogain->val ? 0 : 0xff);
750                 if (ret)
751                         return ret;
752                 if (pdev->autogain->val) {
753                         pdev->gain_valid     = false; /* Force cache update */
754                         pdev->exposure_valid = false; /* Force cache update */
755                 } else {
756                         if (!pdev->gain->is_new)
757                                 pwc_get_u8_ctrl(pdev, GET_STATUS_CTL,
758                                                 READ_AGC_FORMATTER,
759                                                 &pdev->gain->val);
760                         if (!pdev->exposure->is_new)
761                                 pwc_get_u16_ctrl(pdev, GET_STATUS_CTL,
762                                                  READ_SHUTTER_FORMATTER,
763                                                  &pdev->exposure->val);
764                 }
765         }
766         if (ret == 0 && pdev->gain->is_new) {
767                 if (pdev->autogain->val)
768                         return -EBUSY;
769                 ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL,
770                                       PRESET_AGC_FORMATTER,
771                                       pdev->gain->val);
772         }
773         if (ret == 0 && pdev->exposure->is_new) {
774                 if (pdev->autogain->val)
775                         return -EBUSY;
776                 ret = pwc_set_u16_ctrl(pdev, SET_LUM_CTL,
777                                        PRESET_SHUTTER_FORMATTER,
778                                        pdev->exposure->val);
779         }
780         return ret;
781 }
782
783 static int pwc_set_motor(struct pwc_device *pdev)
784 {
785         int ret;
786         u8 buf[4];
787
788         buf[0] = 0;
789         if (pdev->motor_pan_reset->is_new)
790                 buf[0] |= 0x01;
791         if (pdev->motor_tilt_reset->is_new)
792                 buf[0] |= 0x02;
793         if (pdev->motor_pan_reset->is_new || pdev->motor_tilt_reset->is_new) {
794                 ret = send_control_msg(pdev, SET_MPT_CTL,
795                                        PT_RESET_CONTROL_FORMATTER, buf, 1);
796                 if (ret < 0)
797                         return ret;
798         }
799
800         memset(buf, 0, sizeof(buf));
801         if (pdev->motor_pan->is_new) {
802                 buf[0] = pdev->motor_pan->val & 0xFF;
803                 buf[1] = (pdev->motor_pan->val >> 8);
804         }
805         if (pdev->motor_tilt->is_new) {
806                 buf[2] = pdev->motor_tilt->val & 0xFF;
807                 buf[3] = (pdev->motor_tilt->val >> 8);
808         }
809         if (pdev->motor_pan->is_new || pdev->motor_tilt->is_new) {
810                 ret = send_control_msg(pdev, SET_MPT_CTL,
811                                        PT_RELATIVE_CONTROL_FORMATTER,
812                                        buf, sizeof(buf));
813                 if (ret < 0)
814                         return ret;
815         }
816
817         return 0;
818 }
819
820 static int pwc_s_ctrl(struct v4l2_ctrl *ctrl)
821 {
822         struct pwc_device *pdev =
823                 container_of(ctrl->handler, struct pwc_device, ctrl_handler);
824         int ret = 0;
825
826         /* See the comments on locking in pwc_g_volatile_ctrl */
827         mutex_unlock(&pdev->modlock);
828         mutex_lock(&pdev->udevlock);
829
830         if (!pdev->udev) {
831                 ret = -ENODEV;
832                 goto leave;
833         }
834
835         switch (ctrl->id) {
836         case V4L2_CID_BRIGHTNESS:
837                 ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL,
838                                       BRIGHTNESS_FORMATTER, ctrl->val);
839                 break;
840         case V4L2_CID_CONTRAST:
841                 ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL,
842                                       CONTRAST_FORMATTER, ctrl->val);
843                 break;
844         case V4L2_CID_SATURATION:
845                 ret = pwc_set_s8_ctrl(pdev, SET_CHROM_CTL,
846                                       pdev->saturation_fmt, ctrl->val);
847                 break;
848         case V4L2_CID_GAMMA:
849                 ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL,
850                                       GAMMA_FORMATTER, ctrl->val);
851                 break;
852         case V4L2_CID_AUTO_WHITE_BALANCE:
853                 ret = pwc_set_awb(pdev);
854                 break;
855         case V4L2_CID_AUTOGAIN:
856                 if (DEVICE_USE_CODEC2(pdev->type))
857                         ret = pwc_set_autogain(pdev);
858                 else if (DEVICE_USE_CODEC3(pdev->type))
859                         ret = pwc_set_autogain_expo(pdev);
860                 else
861                         ret = -EINVAL;
862                 break;
863         case V4L2_CID_EXPOSURE_AUTO:
864                 if (DEVICE_USE_CODEC2(pdev->type))
865                         ret = pwc_set_exposure_auto(pdev);
866                 else
867                         ret = -EINVAL;
868                 break;
869         case V4L2_CID_COLORFX:
870                 ret = pwc_set_u8_ctrl(pdev, SET_CHROM_CTL,
871                                       COLOUR_MODE_FORMATTER,
872                                       ctrl->val ? 0 : 0xff);
873                 break;
874         case PWC_CID_CUSTOM(autocontour):
875                 if (pdev->autocontour->is_new) {
876                         ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL,
877                                         AUTO_CONTOUR_FORMATTER,
878                                         pdev->autocontour->val ? 0 : 0xff);
879                 }
880                 if (ret == 0 && pdev->contour->is_new) {
881                         if (pdev->autocontour->val) {
882                                 ret = -EBUSY;
883                                 break;
884                         }
885                         ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL,
886                                               PRESET_CONTOUR_FORMATTER,
887                                               pdev->contour->val);
888                 }
889                 break;
890         case V4L2_CID_BACKLIGHT_COMPENSATION:
891                 ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL,
892                                       BACK_LIGHT_COMPENSATION_FORMATTER,
893                                       ctrl->val ? 0 : 0xff);
894                 break;
895         case V4L2_CID_BAND_STOP_FILTER:
896                 ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL,
897                                       FLICKERLESS_MODE_FORMATTER,
898                                       ctrl->val ? 0 : 0xff);
899                 break;
900         case PWC_CID_CUSTOM(noise_reduction):
901                 ret = pwc_set_u8_ctrl(pdev, SET_LUM_CTL,
902                                       DYNAMIC_NOISE_CONTROL_FORMATTER,
903                                       ctrl->val);
904                 break;
905         case PWC_CID_CUSTOM(save_user):
906                 ret = pwc_button_ctrl(pdev, SAVE_USER_DEFAULTS_FORMATTER);
907                 break;
908         case PWC_CID_CUSTOM(restore_user):
909                 ret = pwc_button_ctrl(pdev, RESTORE_USER_DEFAULTS_FORMATTER);
910                 break;
911         case PWC_CID_CUSTOM(restore_factory):
912                 ret = pwc_button_ctrl(pdev,
913                                       RESTORE_FACTORY_DEFAULTS_FORMATTER);
914                 break;
915         case V4L2_CID_PAN_RELATIVE:
916                 ret = pwc_set_motor(pdev);
917                 break;
918         default:
919                 ret = -EINVAL;
920         }
921
922         if (ret)
923                 PWC_ERROR("s_ctrl %s error %d\n", ctrl->name, ret);
924
925 leave:
926         mutex_unlock(&pdev->udevlock);
927         mutex_lock(&pdev->modlock);
928         return ret;
929 }
930
931 static int pwc_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f)
932 {
933         struct pwc_device *pdev = video_drvdata(file);
934
935         /* We only support two format: the raw format, and YUV */
936         switch (f->index) {
937         case 0:
938                 /* RAW format */
939                 f->pixelformat = pdev->type <= 646 ? V4L2_PIX_FMT_PWC1 : V4L2_PIX_FMT_PWC2;
940                 f->flags = V4L2_FMT_FLAG_COMPRESSED;
941                 strlcpy(f->description, "Raw Philips Webcam", sizeof(f->description));
942                 break;
943         case 1:
944                 f->pixelformat = V4L2_PIX_FMT_YUV420;
945                 strlcpy(f->description, "4:2:0, planar, Y-Cb-Cr", sizeof(f->description));
946                 break;
947         default:
948                 return -EINVAL;
949         }
950         return 0;
951 }
952
953 static int pwc_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f)
954 {
955         struct pwc_device *pdev = video_drvdata(file);
956
957         PWC_DEBUG_IOCTL("ioctl(VIDIOC_G_FMT) return size %dx%d\n",
958                         pdev->image.x, pdev->image.y);
959         pwc_vidioc_fill_fmt(pdev, f);
960         return 0;
961 }
962
963 static int pwc_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f)
964 {
965         struct pwc_device *pdev = video_drvdata(file);
966
967         return pwc_vidioc_try_fmt(pdev, f);
968 }
969
970 static int pwc_reqbufs(struct file *file, void *fh,
971                        struct v4l2_requestbuffers *rb)
972 {
973         struct pwc_device *pdev = video_drvdata(file);
974
975         if (pdev->capt_file != NULL &&
976             pdev->capt_file != file)
977                 return -EBUSY;
978
979         pdev->capt_file = file;
980
981         return vb2_reqbufs(&pdev->vb_queue, rb);
982 }
983
984 static int pwc_querybuf(struct file *file, void *fh, struct v4l2_buffer *buf)
985 {
986         struct pwc_device *pdev = video_drvdata(file);
987
988         return vb2_querybuf(&pdev->vb_queue, buf);
989 }
990
991 static int pwc_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
992 {
993         struct pwc_device *pdev = video_drvdata(file);
994
995         if (!pdev->udev)
996                 return -ENODEV;
997
998         if (pdev->capt_file != file)
999                 return -EBUSY;
1000
1001         return vb2_qbuf(&pdev->vb_queue, buf);
1002 }
1003
1004 static int pwc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
1005 {
1006         struct pwc_device *pdev = video_drvdata(file);
1007
1008         if (!pdev->udev)
1009                 return -ENODEV;
1010
1011         if (pdev->capt_file != file)
1012                 return -EBUSY;
1013
1014         return vb2_dqbuf(&pdev->vb_queue, buf, file->f_flags & O_NONBLOCK);
1015 }
1016
1017 static int pwc_streamon(struct file *file, void *fh, enum v4l2_buf_type i)
1018 {
1019         struct pwc_device *pdev = video_drvdata(file);
1020
1021         if (!pdev->udev)
1022                 return -ENODEV;
1023
1024         if (pdev->capt_file != file)
1025                 return -EBUSY;
1026
1027         return vb2_streamon(&pdev->vb_queue, i);
1028 }
1029
1030 static int pwc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i)
1031 {
1032         struct pwc_device *pdev = video_drvdata(file);
1033
1034         if (!pdev->udev)
1035                 return -ENODEV;
1036
1037         if (pdev->capt_file != file)
1038                 return -EBUSY;
1039
1040         return vb2_streamoff(&pdev->vb_queue, i);
1041 }
1042
1043 static int pwc_enum_framesizes(struct file *file, void *fh,
1044                                          struct v4l2_frmsizeenum *fsize)
1045 {
1046         struct pwc_device *pdev = video_drvdata(file);
1047         unsigned int i = 0, index = fsize->index;
1048
1049         if (fsize->pixel_format == V4L2_PIX_FMT_YUV420) {
1050                 for (i = 0; i < PSZ_MAX; i++) {
1051                         if (pdev->image_mask & (1UL << i)) {
1052                                 if (!index--) {
1053                                         fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
1054                                         fsize->discrete.width = pwc_image_sizes[i].x;
1055                                         fsize->discrete.height = pwc_image_sizes[i].y;
1056                                         return 0;
1057                                 }
1058                         }
1059                 }
1060         } else if (fsize->index == 0 &&
1061                         ((fsize->pixel_format == V4L2_PIX_FMT_PWC1 && DEVICE_USE_CODEC1(pdev->type)) ||
1062                          (fsize->pixel_format == V4L2_PIX_FMT_PWC2 && DEVICE_USE_CODEC23(pdev->type)))) {
1063
1064                 fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
1065                 fsize->discrete.width = pdev->abs_max.x;
1066                 fsize->discrete.height = pdev->abs_max.y;
1067                 return 0;
1068         }
1069         return -EINVAL;
1070 }
1071
1072 static int pwc_enum_frameintervals(struct file *file, void *fh,
1073                                            struct v4l2_frmivalenum *fival)
1074 {
1075         struct pwc_device *pdev = video_drvdata(file);
1076         int size = -1;
1077         unsigned int i;
1078
1079         for (i = 0; i < PSZ_MAX; i++) {
1080                 if (pwc_image_sizes[i].x == fival->width &&
1081                                 pwc_image_sizes[i].y == fival->height) {
1082                         size = i;
1083                         break;
1084                 }
1085         }
1086
1087         /* TODO: Support raw format */
1088         if (size < 0 || fival->pixel_format != V4L2_PIX_FMT_YUV420)
1089                 return -EINVAL;
1090
1091         i = pwc_get_fps(pdev, fival->index, size);
1092         if (!i)
1093                 return -EINVAL;
1094
1095         fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
1096         fival->discrete.numerator = 1;
1097         fival->discrete.denominator = i;
1098
1099         return 0;
1100 }
1101
1102 static long pwc_default(struct file *file, void *fh, bool valid_prio,
1103                         int cmd, void *arg)
1104 {
1105         struct pwc_device *pdev = video_drvdata(file);
1106
1107         return pwc_ioctl(pdev, cmd, arg);
1108 }
1109
1110 const struct v4l2_ioctl_ops pwc_ioctl_ops = {
1111         .vidioc_querycap                    = pwc_querycap,
1112         .vidioc_enum_input                  = pwc_enum_input,
1113         .vidioc_g_input                     = pwc_g_input,
1114         .vidioc_s_input                     = pwc_s_input,
1115         .vidioc_enum_fmt_vid_cap            = pwc_enum_fmt_vid_cap,
1116         .vidioc_g_fmt_vid_cap               = pwc_g_fmt_vid_cap,
1117         .vidioc_s_fmt_vid_cap               = pwc_s_fmt_vid_cap,
1118         .vidioc_try_fmt_vid_cap             = pwc_try_fmt_vid_cap,
1119         .vidioc_reqbufs                     = pwc_reqbufs,
1120         .vidioc_querybuf                    = pwc_querybuf,
1121         .vidioc_qbuf                        = pwc_qbuf,
1122         .vidioc_dqbuf                       = pwc_dqbuf,
1123         .vidioc_streamon                    = pwc_streamon,
1124         .vidioc_streamoff                   = pwc_streamoff,
1125         .vidioc_enum_framesizes             = pwc_enum_framesizes,
1126         .vidioc_enum_frameintervals         = pwc_enum_frameintervals,
1127         .vidioc_default             = pwc_default,
1128 };
1129
1130
1131 /* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */