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