blob: 32fbe1ae62519c30d595b545c53e3320a8621f44 [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
340int 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
Trent Piepho05ad3902007-01-30 23:26:01 -0300353#ifdef CONFIG_USB_PWC_DEBUG
Luc Saillard2b455db2006-04-24 10:29:46 -0300354 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
Trent Piepho657de3c2006-06-20 00:30:57 -0300679 /* V4L2 Layer */
680 case VIDIOC_QUERYCAP:
681 {
Luc Saillard2b455db2006-04-24 10:29:46 -0300682 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
Trent Piepho657de3c2006-06-20 00:30:57 -0300697 case VIDIOC_ENUMINPUT:
698 {
Luc Saillard2b455db2006-04-24 10:29:46 -0300699 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
Trent Piepho657de3c2006-06-20 00:30:57 -0300709 case VIDIOC_G_INPUT:
Luc Saillard2b455db2006-04-24 10:29:46 -0300710 {
711 int *i = arg;
712 *i = 0; /* Only one INPUT is supported */
713 return 0;
714 }
Trent Piepho657de3c2006-06-20 00:30:57 -0300715 case VIDIOC_S_INPUT:
716 {
Luc Saillard2b455db2006-04-24 10:29:46 -0300717 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: */
Trent Piepho657de3c2006-06-20 00:30:57 -0300728 case VIDIOC_QUERYCTRL:
Luc Saillard2b455db2006-04-24 10:29:46 -0300729 {
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 {
Trent Piepho657de3c2006-06-20 00:30:57 -0300966 struct v4l2_fmtdesc *f = arg;
Luc Saillard2b455db2006-04-24 10:29:46 -0300967 int index;
968
969 if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
970 return -EINVAL;
971
Trent Piepho657de3c2006-06-20 00:30:57 -0300972 /* We only support two format: the raw format, and YUV */
Luc Saillard2b455db2006-04-24 10:29:46 -0300973 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 */
Trent Piepho657de3c2006-06-20 00:30:57 -0300981 f->pixelformat = pdev->type<=646?V4L2_PIX_FMT_PWC1:V4L2_PIX_FMT_PWC2;
Luc Saillard2b455db2006-04-24 10:29:46 -0300982 f->flags = V4L2_FMT_FLAG_COMPRESSED;
Trent Piepho657de3c2006-06-20 00:30:57 -0300983 strlcpy(f->description,"Raw Philips Webcam",sizeof(f->description));
Luc Saillard2b455db2006-04-24 10:29:46 -0300984 break;
985 case 1:
Trent Piepho657de3c2006-06-20 00:30:57 -0300986 f->pixelformat = V4L2_PIX_FMT_YUV420;
987 strlcpy(f->description,"4:2:0, planar, Y-Cb-Cr",sizeof(f->description));
Luc Saillard2b455db2006-04-24 10:29:46 -0300988 break;
Trent Piepho657de3c2006-06-20 00:30:57 -0300989 default:
Luc Saillard2b455db2006-04-24 10:29:46 -0300990 return -EINVAL;
991 }
992 return 0;
993 }
994
Trent Piepho657de3c2006-06-20 00:30:57 -0300995 case VIDIOC_G_FMT:
Luc Saillard2b455db2006-04-24 10:29:46 -0300996 {
Trent Piepho657de3c2006-06-20 00:30:57 -0300997 struct v4l2_format *f = arg;
Luc Saillard2b455db2006-04-24 10:29:46 -0300998
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
Trent Piepho657de3c2006-06-20 00:30:57 -03001011 case VIDIOC_S_FMT:
Luc Saillard2b455db2006-04-24 10:29:46 -03001012 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;
Luc Saillard288bb0e2007-04-22 23:55:10 -03001171 buf->length = pdev->len_per_image;
Luc Saillard2b455db2006-04-24 10:29:46 -03001172 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
Luc Saillard9ee6d782007-04-22 23:54:36 -03001196 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
Luc Saillard2b455db2006-04-24 10:29:46 -03001254 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: */