aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/pwc/pwc-v4l.c
diff options
context:
space:
mode:
authorLuc Saillard <luc@saillard.org>2006-04-24 09:29:46 -0400
committerMauro Carvalho Chehab <mchehab@infradead.org>2006-06-25 00:58:20 -0400
commit2b455db6d456ef2d44808a8377fd3bc832e08317 (patch)
treeb7b7bcabd53f9bb58d7f69eb6d012735dacd31c7 /drivers/media/video/pwc/pwc-v4l.c
parentd9e12f25cf538d103426946121d214dff332efbb (diff)
V4L/DVB (3835): [PATCH] update pwc driver
Add v4l2 compatibility Include the decompressor (legal problem has been resolv by Alan Cox) Faster decoder and easier to maintain, optimize, ... Can export to userland compressed stream Support more cameras, lot of bugs are fixed. Signed-off-by: Luc Saillard <luc@saillard.org> Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Diffstat (limited to 'drivers/media/video/pwc/pwc-v4l.c')
-rw-r--r--drivers/media/video/pwc/pwc-v4l.c1208
1 files changed, 1208 insertions, 0 deletions
diff --git a/drivers/media/video/pwc/pwc-v4l.c b/drivers/media/video/pwc/pwc-v4l.c
new file mode 100644
index 000000000000..68e7573c8ef2
--- /dev/null
+++ b/drivers/media/video/pwc/pwc-v4l.c
@@ -0,0 +1,1208 @@
1/* Linux driver for Philips webcam
2 USB and Video4Linux interface part.
3 (C) 1999-2004 Nemosoft Unv.
4 (C) 2004-2006 Luc Saillard (luc@saillard.org)
5
6 NOTE: this version of pwc is an unofficial (modified) release of pwc & pcwx
7 driver and thus may have bugs that are not present in the original version.
8 Please send bug reports and support requests to <luc@saillard.org>.
9 The decompression routines have been implemented by reverse-engineering the
10 Nemosoft binary pwcx module. Caveat emptor.
11
12 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by
14 the Free Software Foundation; either version 2 of the License, or
15 (at your option) any later version.
16
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
21
22 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to the Free Software
24 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25
26*/
27
28#include <linux/errno.h>
29#include <linux/init.h>
30#include <linux/mm.h>
31#include <linux/module.h>
32#include <linux/poll.h>
33#include <linux/slab.h>
34#include <linux/vmalloc.h>
35#include <asm/io.h>
36
37#include "pwc.h"
38
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 },
130#if XAWTV_HAS_BEEN_FIXED
131 {
132 .id = V4L2_CID_PRIVATE_SAVE_USER,
133 .type = V4L2_CTRL_TYPE_BUTTON,
134 .name = "Save User Settings",
135 .minimum = 0,
136 .maximum = 0,
137 .step = 0,
138 .default_value = 0,
139 },
140 {
141 .id = V4L2_CID_PRIVATE_RESTORE_USER,
142 .type = V4L2_CTRL_TYPE_BUTTON,
143 .name = "Restore User Settings",
144 .minimum = 0,
145 .maximum = 0,
146 .step = 0,
147 .default_value = 0,
148 },
149 {
150 .id = V4L2_CID_PRIVATE_RESTORE_FACTORY,
151 .type = V4L2_CTRL_TYPE_BUTTON,
152 .name = "Restore Factory Settings",
153 .minimum = 0,
154 .maximum = 0,
155 .step = 0,
156 .default_value = 0,
157 },
158 {
159 .id = V4L2_CID_PRIVATE_COLOUR_MODE,
160 .type = V4L2_CTRL_TYPE_BOOLEAN,
161 .name = "Colour mode",
162 .minimum = 0,
163 .maximum = 1,
164 .step = 1,
165 .default_value = 0,
166 },
167 {
168 .id = V4L2_CID_PRIVATE_AUTOCONTOUR,
169 .type = V4L2_CTRL_TYPE_BOOLEAN,
170 .name = "Auto contour",
171 .minimum = 0,
172 .maximum = 1,
173 .step = 1,
174 .default_value = 0,
175 },
176 {
177 .id = V4L2_CID_PRIVATE_CONTOUR,
178 .type = V4L2_CTRL_TYPE_INTEGER,
179 .name = "Contour",
180 .minimum = 0,
181 .maximum = 63,
182 .step = 1,
183 .default_value = 0,
184 },
185 {
186 .id = V4L2_CID_PRIVATE_BACKLIGHT,
187 .type = V4L2_CTRL_TYPE_BOOLEAN,
188 .name = "Backlight compensation",
189 .minimum = 0,
190 .maximum = 1,
191 .step = 1,
192 .default_value = 0,
193 },
194 {
195 .id = V4L2_CID_PRIVATE_FLICKERLESS,
196 .type = V4L2_CTRL_TYPE_BOOLEAN,
197 .name = "Flickerless",
198 .minimum = 0,
199 .maximum = 1,
200 .step = 1,
201 .default_value = 0,
202 },
203 {
204 .id = V4L2_CID_PRIVATE_NOISE_REDUCTION,
205 .type = V4L2_CTRL_TYPE_INTEGER,
206 .name = "Noise reduction",
207 .minimum = 0,
208 .maximum = 3,
209 .step = 1,
210 .default_value = 0,
211 },
212#endif
213};
214
215#if CONFIG_PWC_DEBUG
216/* In 2.6.16-rc1 v4l_printk_ioctl is not defined but exported */
217extern void v4l_printk_ioctl(unsigned int cmd);
218#endif
219
220static void pwc_vidioc_fill_fmt(const struct pwc_device *pdev, struct v4l2_format *f)
221{
222 memset(&f->fmt.pix, 0, sizeof(struct v4l2_pix_format));
223 f->fmt.pix.width = pdev->view.x;
224 f->fmt.pix.height = pdev->view.y;
225 f->fmt.pix.field = V4L2_FIELD_NONE;
226 if (pdev->vpalette == VIDEO_PALETTE_YUV420P) {
227 f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420;
228 f->fmt.pix.bytesperline = (f->fmt.pix.width * 3)/2;
229 f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
230 } else {
231 /* vbandlength contains 4 lines ... */
232 f->fmt.pix.bytesperline = pdev->vbandlength/4;
233 f->fmt.pix.sizeimage = pdev->frame_size + sizeof(struct pwc_raw_frame);
234 if (DEVICE_USE_CODEC1(pdev->type))
235 f->fmt.pix.pixelformat = V4L2_PIX_FMT_PWC1;
236 else
237 f->fmt.pix.pixelformat = V4L2_PIX_FMT_PWC2;
238 }
239 PWC_DEBUG_IOCTL("pwc_vidioc_fill_fmt() "
240 "width=%d, height=%d, bytesperline=%d, sizeimage=%d, pixelformat=%c%c%c%c\n",
241 f->fmt.pix.width,
242 f->fmt.pix.height,
243 f->fmt.pix.bytesperline,
244 f->fmt.pix.sizeimage,
245 (f->fmt.pix.pixelformat)&255,
246 (f->fmt.pix.pixelformat>>8)&255,
247 (f->fmt.pix.pixelformat>>16)&255,
248 (f->fmt.pix.pixelformat>>24)&255);
249}
250
251/* ioctl(VIDIOC_TRY_FMT) */
252static int pwc_vidioc_try_fmt(struct pwc_device *pdev, struct v4l2_format *f)
253{
254 if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
255 PWC_DEBUG_IOCTL("Bad video type must be V4L2_BUF_TYPE_VIDEO_CAPTURE\n");
256 return -EINVAL;
257 }
258
259 switch (f->fmt.pix.pixelformat) {
260 case V4L2_PIX_FMT_YUV420:
261 break;
262 case V4L2_PIX_FMT_PWC1:
263 if (DEVICE_USE_CODEC23(pdev->type)) {
264 PWC_DEBUG_IOCTL("codec1 is only supported for old pwc webcam\n");
265 return -EINVAL;
266 }
267 break;
268 case V4L2_PIX_FMT_PWC2:
269 if (DEVICE_USE_CODEC1(pdev->type)) {
270 PWC_DEBUG_IOCTL("codec23 is only supported for new pwc webcam\n");
271 return -EINVAL;
272 }
273 break;
274 default:
275 PWC_DEBUG_IOCTL("Unsupported pixel format\n");
276 return -EINVAL;
277
278 }
279
280 if (f->fmt.pix.width > pdev->view_max.x)
281 f->fmt.pix.width = pdev->view_max.x;
282 else if (f->fmt.pix.width < pdev->view_min.x)
283 f->fmt.pix.width = pdev->view_min.x;
284
285 if (f->fmt.pix.height > pdev->view_max.y)
286 f->fmt.pix.height = pdev->view_max.y;
287 else if (f->fmt.pix.height < pdev->view_min.y)
288 f->fmt.pix.height = pdev->view_min.y;
289
290 return 0;
291}
292
293/* ioctl(VIDIOC_SET_FMT) */
294static int pwc_vidioc_set_fmt(struct pwc_device *pdev, struct v4l2_format *f)
295{
296 int ret, fps, snapshot, compression, pixelformat;
297
298 ret = pwc_vidioc_try_fmt(pdev, f);
299 if (ret<0)
300 return ret;
301
302 pixelformat = f->fmt.pix.pixelformat;
303 compression = pdev->vcompression;
304 snapshot = 0;
305 fps = pdev->vframes;
306 if (f->fmt.pix.priv) {
307 compression = (f->fmt.pix.priv & PWC_QLT_MASK) >> PWC_QLT_SHIFT;
308 snapshot = !!(f->fmt.pix.priv & PWC_FPS_SNAPSHOT);
309 fps = (f->fmt.pix.priv & PWC_FPS_FRMASK) >> PWC_FPS_SHIFT;
310 if (fps == 0)
311 fps = pdev->vframes;
312 }
313
314 if (pixelformat == V4L2_PIX_FMT_YUV420)
315 pdev->vpalette = VIDEO_PALETTE_YUV420P;
316 else
317 pdev->vpalette = VIDEO_PALETTE_RAW;
318
319 PWC_DEBUG_IOCTL("Try to change format to: width=%d height=%d fps=%d "
320 "compression=%d snapshot=%d format=%c%c%c%c\n",
321 f->fmt.pix.width, f->fmt.pix.height, fps,
322 compression, snapshot,
323 (pixelformat)&255,
324 (pixelformat>>8)&255,
325 (pixelformat>>16)&255,
326 (pixelformat>>24)&255);
327
328 ret = pwc_try_video_mode(pdev,
329 f->fmt.pix.width,
330 f->fmt.pix.height,
331 fps,
332 compression,
333 snapshot);
334
335 PWC_DEBUG_IOCTL("pwc_try_video_mode(), return=%d\n", ret);
336
337 if (ret)
338 return ret;
339
340 pwc_vidioc_fill_fmt(pdev, f);
341
342 return 0;
343
344}
345
346int pwc_video_do_ioctl(struct inode *inode, struct file *file,
347 unsigned int cmd, void *arg)
348{
349 struct video_device *vdev = video_devdata(file);
350 struct pwc_device *pdev;
351 DECLARE_WAITQUEUE(wait, current);
352
353 if (vdev == NULL)
354 return -EFAULT;
355 pdev = vdev->priv;
356 if (pdev == NULL)
357 return -EFAULT;
358
359#if CONFIG_PWC_DEBUG
360 if (PWC_DEBUG_LEVEL_IOCTL & pwc_trace)
361 v4l_printk_ioctl(cmd);
362#endif
363
364
365 switch (cmd) {
366 /* Query cabapilities */
367 case VIDIOCGCAP:
368 {
369 struct video_capability *caps = arg;
370
371 strcpy(caps->name, vdev->name);
372 caps->type = VID_TYPE_CAPTURE;
373 caps->channels = 1;
374 caps->audios = 1;
375 caps->minwidth = pdev->view_min.x;
376 caps->minheight = pdev->view_min.y;
377 caps->maxwidth = pdev->view_max.x;
378 caps->maxheight = pdev->view_max.y;
379 break;
380 }
381
382 /* Channel functions (simulate 1 channel) */
383 case VIDIOCGCHAN:
384 {
385 struct video_channel *v = arg;
386
387 if (v->channel != 0)
388 return -EINVAL;
389 v->flags = 0;
390 v->tuners = 0;
391 v->type = VIDEO_TYPE_CAMERA;
392 strcpy(v->name, "Webcam");
393 return 0;
394 }
395
396 case VIDIOCSCHAN:
397 {
398 /* The spec says the argument is an integer, but
399 the bttv driver uses a video_channel arg, which
400 makes sense becasue it also has the norm flag.
401 */
402 struct video_channel *v = arg;
403 if (v->channel != 0)
404 return -EINVAL;
405 return 0;
406 }
407
408
409 /* Picture functions; contrast etc. */
410 case VIDIOCGPICT:
411 {
412 struct video_picture *p = arg;
413 int val;
414
415 val = pwc_get_brightness(pdev);
416 if (val >= 0)
417 p->brightness = (val<<9);
418 else
419 p->brightness = 0xffff;
420 val = pwc_get_contrast(pdev);
421 if (val >= 0)
422 p->contrast = (val<<10);
423 else
424 p->contrast = 0xffff;
425 /* Gamma, Whiteness, what's the difference? :) */
426 val = pwc_get_gamma(pdev);
427 if (val >= 0)
428 p->whiteness = (val<<11);
429 else
430 p->whiteness = 0xffff;
431 if (pwc_get_saturation(pdev, &val)<0)
432 p->colour = 0xffff;
433 else
434 p->colour = 32768 + val * 327;
435 p->depth = 24;
436 p->palette = pdev->vpalette;
437 p->hue = 0xFFFF; /* N/A */
438 break;
439 }
440
441 case VIDIOCSPICT:
442 {
443 struct video_picture *p = arg;
444 /*
445 * FIXME: Suppose we are mid read
446 ANSWER: No problem: the firmware of the camera
447 can handle brightness/contrast/etc
448 changes at _any_ time, and the palette
449 is used exactly once in the uncompress
450 routine.
451 */
452 pwc_set_brightness(pdev, p->brightness);
453 pwc_set_contrast(pdev, p->contrast);
454 pwc_set_gamma(pdev, p->whiteness);
455 pwc_set_saturation(pdev, (p->colour-32768)/327);
456 if (p->palette && p->palette != pdev->vpalette) {
457 switch (p->palette) {
458 case VIDEO_PALETTE_YUV420P:
459 case VIDEO_PALETTE_RAW:
460 pdev->vpalette = p->palette;
461 return pwc_try_video_mode(pdev, pdev->image.x, pdev->image.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
462 break;
463 default:
464 return -EINVAL;
465 break;
466 }
467 }
468 break;
469 }
470
471 /* Window/size parameters */
472 case VIDIOCGWIN:
473 {
474 struct video_window *vw = arg;
475
476 vw->x = 0;
477 vw->y = 0;
478 vw->width = pdev->view.x;
479 vw->height = pdev->view.y;
480 vw->chromakey = 0;
481 vw->flags = (pdev->vframes << PWC_FPS_SHIFT) |
482 (pdev->vsnapshot ? PWC_FPS_SNAPSHOT : 0);
483 break;
484 }
485
486 case VIDIOCSWIN:
487 {
488 struct video_window *vw = arg;
489 int fps, snapshot, ret;
490
491 fps = (vw->flags & PWC_FPS_FRMASK) >> PWC_FPS_SHIFT;
492 snapshot = vw->flags & PWC_FPS_SNAPSHOT;
493 if (fps == 0)
494 fps = pdev->vframes;
495 if (pdev->view.x == vw->width && pdev->view.y && fps == pdev->vframes && snapshot == pdev->vsnapshot)
496 return 0;
497 ret = pwc_try_video_mode(pdev, vw->width, vw->height, fps, pdev->vcompression, snapshot);
498 if (ret)
499 return ret;
500 break;
501 }
502
503 /* We don't have overlay support (yet) */
504 case VIDIOCGFBUF:
505 {
506 struct video_buffer *vb = arg;
507
508 memset(vb,0,sizeof(*vb));
509 break;
510 }
511
512 /* mmap() functions */
513 case VIDIOCGMBUF:
514 {
515 /* Tell the user program how much memory is needed for a mmap() */
516 struct video_mbuf *vm = arg;
517 int i;
518
519 memset(vm, 0, sizeof(*vm));
520 vm->size = pwc_mbufs * pdev->len_per_image;
521 vm->frames = pwc_mbufs; /* double buffering should be enough for most applications */
522 for (i = 0; i < pwc_mbufs; i++)
523 vm->offsets[i] = i * pdev->len_per_image;
524 break;
525 }
526
527 case VIDIOCMCAPTURE:
528 {
529 /* Start capture into a given image buffer (called 'frame' in video_mmap structure) */
530 struct video_mmap *vm = arg;
531
532 PWC_DEBUG_READ("VIDIOCMCAPTURE: %dx%d, frame %d, format %d\n", vm->width, vm->height, vm->frame, vm->format);
533 if (vm->frame < 0 || vm->frame >= pwc_mbufs)
534 return -EINVAL;
535
536 /* xawtv is nasty. It probes the available palettes
537 by setting a very small image size and trying
538 various palettes... The driver doesn't support
539 such small images, so I'm working around it.
540 */
541 if (vm->format)
542 {
543 switch (vm->format)
544 {
545 case VIDEO_PALETTE_YUV420P:
546 case VIDEO_PALETTE_RAW:
547 break;
548 default:
549 return -EINVAL;
550 break;
551 }
552 }
553
554 if ((vm->width != pdev->view.x || vm->height != pdev->view.y) &&
555 (vm->width >= pdev->view_min.x && vm->height >= pdev->view_min.y)) {
556 int ret;
557
558 PWC_DEBUG_OPEN("VIDIOCMCAPTURE: changing size to please xawtv :-(.\n");
559 ret = pwc_try_video_mode(pdev, vm->width, vm->height, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
560 if (ret)
561 return ret;
562 } /* ... size mismatch */
563
564 /* FIXME: should we lock here? */
565 if (pdev->image_used[vm->frame])
566 return -EBUSY; /* buffer wasn't available. Bummer */
567 pdev->image_used[vm->frame] = 1;
568
569 /* Okay, we're done here. In the SYNC call we wait until a
570 frame comes available, then expand image into the given
571 buffer.
572 In contrast to the CPiA cam the Philips cams deliver a
573 constant stream, almost like a grabber card. Also,
574 we have separate buffers for the rawdata and the image,
575 meaning we can nearly always expand into the requested buffer.
576 */
577 PWC_DEBUG_READ("VIDIOCMCAPTURE done.\n");
578 break;
579 }
580
581 case VIDIOCSYNC:
582 {
583 /* The doc says: "Whenever a buffer is used it should
584 call VIDIOCSYNC to free this frame up and continue."
585
586 The only odd thing about this whole procedure is
587 that MCAPTURE flags the buffer as "in use", and
588 SYNC immediately unmarks it, while it isn't
589 after SYNC that you know that the buffer actually
590 got filled! So you better not start a CAPTURE in
591 the same frame immediately (use double buffering).
592 This is not a problem for this cam, since it has
593 extra intermediate buffers, but a hardware
594 grabber card will then overwrite the buffer
595 you're working on.
596 */
597 int *mbuf = arg;
598 int ret;
599
600 PWC_DEBUG_READ("VIDIOCSYNC called (%d).\n", *mbuf);
601
602 /* bounds check */
603 if (*mbuf < 0 || *mbuf >= pwc_mbufs)
604 return -EINVAL;
605 /* check if this buffer was requested anyway */
606 if (pdev->image_used[*mbuf] == 0)
607 return -EINVAL;
608
609 /* Add ourselves to the frame wait-queue.
610
611 FIXME: needs auditing for safety.
612 QUESTION: In what respect? I think that using the
613 frameq is safe now.
614 */
615 add_wait_queue(&pdev->frameq, &wait);
616 while (pdev->full_frames == NULL) {
617 /* Check for unplugged/etc. here */
618 if (pdev->error_status) {
619 remove_wait_queue(&pdev->frameq, &wait);
620 set_current_state(TASK_RUNNING);
621 return -pdev->error_status;
622 }
623
624 if (signal_pending(current)) {
625 remove_wait_queue(&pdev->frameq, &wait);
626 set_current_state(TASK_RUNNING);
627 return -ERESTARTSYS;
628 }
629 schedule();
630 set_current_state(TASK_INTERRUPTIBLE);
631 }
632 remove_wait_queue(&pdev->frameq, &wait);
633 set_current_state(TASK_RUNNING);
634
635 /* The frame is ready. Expand in the image buffer
636 requested by the user. I don't care if you
637 mmap() 5 buffers and request data in this order:
638 buffer 4 2 3 0 1 2 3 0 4 3 1 . . .
639 Grabber hardware may not be so forgiving.
640 */
641 PWC_DEBUG_READ("VIDIOCSYNC: frame ready.\n");
642 pdev->fill_image = *mbuf; /* tell in which buffer we want the image to be expanded */
643 /* Decompress, etc */
644 ret = pwc_handle_frame(pdev);
645 pdev->image_used[*mbuf] = 0;
646 if (ret)
647 return -EFAULT;
648 break;
649 }
650
651 case VIDIOCGAUDIO:
652 {
653 struct video_audio *v = arg;
654
655 strcpy(v->name, "Microphone");
656 v->audio = -1; /* unknown audio minor */
657 v->flags = 0;
658 v->mode = VIDEO_SOUND_MONO;
659 v->volume = 0;
660 v->bass = 0;
661 v->treble = 0;
662 v->balance = 0x8000;
663 v->step = 1;
664 break;
665 }
666
667 case VIDIOCSAUDIO:
668 {
669 /* Dummy: nothing can be set */
670 break;
671 }
672
673 case VIDIOCGUNIT:
674 {
675 struct video_unit *vu = arg;
676
677 vu->video = pdev->vdev->minor & 0x3F;
678 vu->audio = -1; /* not known yet */
679 vu->vbi = -1;
680 vu->radio = -1;
681 vu->teletext = -1;
682 break;
683 }
684
685 /* V4L2 Layer */
686 case VIDIOC_QUERYCAP:
687 {
688 struct v4l2_capability *cap = arg;
689
690 PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCAP) This application "\
691 "try to use the v4l2 layer\n");
692 strcpy(cap->driver,PWC_NAME);
693 strlcpy(cap->card, vdev->name, sizeof(cap->card));
694 usb_make_path(pdev->udev,cap->bus_info,sizeof(cap->bus_info));
695 cap->version = PWC_VERSION_CODE;
696 cap->capabilities =
697 V4L2_CAP_VIDEO_CAPTURE |
698 V4L2_CAP_STREAMING |
699 V4L2_CAP_READWRITE;
700 return 0;
701 }
702
703 case VIDIOC_ENUMINPUT:
704 {
705 struct v4l2_input *i = arg;
706
707 if ( i->index ) /* Only one INPUT is supported */
708 return -EINVAL;
709
710 memset(i, 0, sizeof(struct v4l2_input));
711 strcpy(i->name, "usb");
712 return 0;
713 }
714
715 case VIDIOC_G_INPUT:
716 {
717 int *i = arg;
718 *i = 0; /* Only one INPUT is supported */
719 return 0;
720 }
721 case VIDIOC_S_INPUT:
722 {
723 int *i = arg;
724
725 if ( *i ) { /* Only one INPUT is supported */
726 PWC_DEBUG_IOCTL("Only one input source is"\
727 " supported with this webcam.\n");
728 return -EINVAL;
729 }
730 return 0;
731 }
732
733 /* TODO: */
734 case VIDIOC_QUERYCTRL:
735 {
736 struct v4l2_queryctrl *c = arg;
737 int i;
738
739 PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) query id=%d\n", c->id);
740 for (i=0; i<sizeof(pwc_controls)/sizeof(struct v4l2_queryctrl); i++) {
741 if (pwc_controls[i].id == c->id) {
742 PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) found\n");
743 memcpy(c,&pwc_controls[i],sizeof(struct v4l2_queryctrl));
744 return 0;
745 }
746 }
747 PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) not found\n");
748
749 return -EINVAL;
750 }
751 case VIDIOC_G_CTRL:
752 {
753 struct v4l2_control *c = arg;
754 int ret;
755
756 switch (c->id)
757 {
758 case V4L2_CID_BRIGHTNESS:
759 c->value = pwc_get_brightness(pdev);
760 if (c->value<0)
761 return -EINVAL;
762 return 0;
763 case V4L2_CID_CONTRAST:
764 c->value = pwc_get_contrast(pdev);
765 if (c->value<0)
766 return -EINVAL;
767 return 0;
768 case V4L2_CID_SATURATION:
769 ret = pwc_get_saturation(pdev, &c->value);
770 if (ret<0)
771 return -EINVAL;
772 return 0;
773 case V4L2_CID_GAMMA:
774 c->value = pwc_get_gamma(pdev);
775 if (c->value<0)
776 return -EINVAL;
777 return 0;
778 case V4L2_CID_RED_BALANCE:
779 ret = pwc_get_red_gain(pdev, &c->value);
780 if (ret<0)
781 return -EINVAL;
782 c->value >>= 8;
783 return 0;
784 case V4L2_CID_BLUE_BALANCE:
785 ret = pwc_get_blue_gain(pdev, &c->value);
786 if (ret<0)
787 return -EINVAL;
788 c->value >>= 8;
789 return 0;
790 case V4L2_CID_AUTO_WHITE_BALANCE:
791 ret = pwc_get_awb(pdev);
792 if (ret<0)
793 return -EINVAL;
794 c->value = (ret == PWC_WB_MANUAL)?0:1;
795 return 0;
796 case V4L2_CID_GAIN:
797 ret = pwc_get_agc(pdev, &c->value);
798 if (ret<0)
799 return -EINVAL;
800 c->value >>= 8;
801 return 0;
802 case V4L2_CID_AUTOGAIN:
803 ret = pwc_get_agc(pdev, &c->value);
804 if (ret<0)
805 return -EINVAL;
806 c->value = (c->value < 0)?1:0;
807 return 0;
808 case V4L2_CID_EXPOSURE:
809 ret = pwc_get_shutter_speed(pdev, &c->value);
810 if (ret<0)
811 return -EINVAL;
812 return 0;
813 case V4L2_CID_PRIVATE_COLOUR_MODE:
814 ret = pwc_get_colour_mode(pdev, &c->value);
815 if (ret < 0)
816 return -EINVAL;
817 return 0;
818 case V4L2_CID_PRIVATE_AUTOCONTOUR:
819 ret = pwc_get_contour(pdev, &c->value);
820 if (ret < 0)
821 return -EINVAL;
822 c->value=(c->value == -1?1:0);
823 return 0;
824 case V4L2_CID_PRIVATE_CONTOUR:
825 ret = pwc_get_contour(pdev, &c->value);
826 if (ret < 0)
827 return -EINVAL;
828 c->value >>= 10;
829 return 0;
830 case V4L2_CID_PRIVATE_BACKLIGHT:
831 ret = pwc_get_backlight(pdev, &c->value);
832 if (ret < 0)
833 return -EINVAL;
834 return 0;
835 case V4L2_CID_PRIVATE_FLICKERLESS:
836 ret = pwc_get_flicker(pdev, &c->value);
837 if (ret < 0)
838 return -EINVAL;
839 c->value=(c->value?1:0);
840 return 0;
841 case V4L2_CID_PRIVATE_NOISE_REDUCTION:
842 ret = pwc_get_dynamic_noise(pdev, &c->value);
843 if (ret < 0)
844 return -EINVAL;
845 return 0;
846
847 case V4L2_CID_PRIVATE_SAVE_USER:
848 case V4L2_CID_PRIVATE_RESTORE_USER:
849 case V4L2_CID_PRIVATE_RESTORE_FACTORY:
850 return -EINVAL;
851 }
852 return -EINVAL;
853 }
854 case VIDIOC_S_CTRL:
855 {
856 struct v4l2_control *c = arg;
857 int ret;
858
859 switch (c->id)
860 {
861 case V4L2_CID_BRIGHTNESS:
862 c->value <<= 9;
863 ret = pwc_set_brightness(pdev, c->value);
864 if (ret<0)
865 return -EINVAL;
866 return 0;
867 case V4L2_CID_CONTRAST:
868 c->value <<= 10;
869 ret = pwc_set_contrast(pdev, c->value);
870 if (ret<0)
871 return -EINVAL;
872 return 0;
873 case V4L2_CID_SATURATION:
874 ret = pwc_set_saturation(pdev, c->value);
875 if (ret<0)
876 return -EINVAL;
877 return 0;
878 case V4L2_CID_GAMMA:
879 c->value <<= 11;
880 ret = pwc_set_gamma(pdev, c->value);
881 if (ret<0)
882 return -EINVAL;
883 return 0;
884 case V4L2_CID_RED_BALANCE:
885 c->value <<= 8;
886 ret = pwc_set_red_gain(pdev, c->value);
887 if (ret<0)
888 return -EINVAL;
889 return 0;
890 case V4L2_CID_BLUE_BALANCE:
891 c->value <<= 8;
892 ret = pwc_set_blue_gain(pdev, c->value);
893 if (ret<0)
894 return -EINVAL;
895 return 0;
896 case V4L2_CID_AUTO_WHITE_BALANCE:
897 c->value = (c->value == 0)?PWC_WB_MANUAL:PWC_WB_AUTO;
898 ret = pwc_set_awb(pdev, c->value);
899 if (ret<0)
900 return -EINVAL;
901 return 0;
902 case V4L2_CID_EXPOSURE:
903 c->value <<= 8;
904 ret = pwc_set_shutter_speed(pdev, c->value?0:1, c->value);
905 if (ret<0)
906 return -EINVAL;
907 return 0;
908 case V4L2_CID_AUTOGAIN:
909 /* autogain off means nothing without a gain */
910 if (c->value == 0)
911 return 0;
912 ret = pwc_set_agc(pdev, c->value, 0);
913 if (ret<0)
914 return -EINVAL;
915 return 0;
916 case V4L2_CID_GAIN:
917 c->value <<= 8;
918 ret = pwc_set_agc(pdev, 0, c->value);
919 if (ret<0)
920 return -EINVAL;
921 return 0;
922 case V4L2_CID_PRIVATE_SAVE_USER:
923 if (pwc_save_user(pdev))
924 return -EINVAL;
925 return 0;
926 case V4L2_CID_PRIVATE_RESTORE_USER:
927 if (pwc_restore_user(pdev))
928 return -EINVAL;
929 return 0;
930 case V4L2_CID_PRIVATE_RESTORE_FACTORY:
931 if (pwc_restore_factory(pdev))
932 return -EINVAL;
933 return 0;
934 case V4L2_CID_PRIVATE_COLOUR_MODE:
935 ret = pwc_set_colour_mode(pdev, c->value);
936 if (ret < 0)
937 return -EINVAL;
938 return 0;
939 case V4L2_CID_PRIVATE_AUTOCONTOUR:
940 c->value=(c->value == 1)?-1:0;
941 ret = pwc_set_contour(pdev, c->value);
942 if (ret < 0)
943 return -EINVAL;
944 return 0;
945 case V4L2_CID_PRIVATE_CONTOUR:
946 c->value <<= 10;
947 ret = pwc_set_contour(pdev, c->value);
948 if (ret < 0)
949 return -EINVAL;
950 return 0;
951 case V4L2_CID_PRIVATE_BACKLIGHT:
952 ret = pwc_set_backlight(pdev, c->value);
953 if (ret < 0)
954 return -EINVAL;
955 return 0;
956 case V4L2_CID_PRIVATE_FLICKERLESS:
957 ret = pwc_set_flicker(pdev, c->value);
958 if (ret < 0)
959 return -EINVAL;
960 case V4L2_CID_PRIVATE_NOISE_REDUCTION:
961 ret = pwc_set_dynamic_noise(pdev, c->value);
962 if (ret < 0)
963 return -EINVAL;
964 return 0;
965
966 }
967 return -EINVAL;
968 }
969
970 case VIDIOC_ENUM_FMT:
971 {
972 struct v4l2_fmtdesc *f = arg;
973 int index;
974
975 if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
976 return -EINVAL;
977
978 /* We only support two format: the raw format, and YUV */
979 index = f->index;
980 memset(f,0,sizeof(struct v4l2_fmtdesc));
981 f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
982 f->index = index;
983 switch(index)
984 {
985 case 0:
986 /* RAW format */
987 f->pixelformat = pdev->type<=646?V4L2_PIX_FMT_PWC1:V4L2_PIX_FMT_PWC2;
988 f->flags = V4L2_FMT_FLAG_COMPRESSED;
989 strlcpy(f->description,"Raw Philips Webcam",sizeof(f->description));
990 break;
991 case 1:
992 f->pixelformat = V4L2_PIX_FMT_YUV420;
993 strlcpy(f->description,"4:2:0, planar, Y-Cb-Cr",sizeof(f->description));
994 break;
995 default:
996 return -EINVAL;
997 }
998 return 0;
999 }
1000
1001 case VIDIOC_G_FMT:
1002 {
1003 struct v4l2_format *f = arg;
1004
1005 PWC_DEBUG_IOCTL("ioctl(VIDIOC_G_FMT) return size %dx%d\n",pdev->image.x,pdev->image.y);
1006 if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1007 return -EINVAL;
1008
1009 pwc_vidioc_fill_fmt(pdev, f);
1010
1011 return 0;
1012 }
1013
1014 case VIDIOC_TRY_FMT:
1015 return pwc_vidioc_try_fmt(pdev, arg);
1016
1017 case VIDIOC_S_FMT:
1018 return pwc_vidioc_set_fmt(pdev, arg);
1019
1020 case VIDIOC_G_STD:
1021 {
1022 v4l2_std_id *std = arg;
1023 *std = V4L2_STD_UNKNOWN;
1024 return 0;
1025 }
1026
1027 case VIDIOC_S_STD:
1028 {
1029 v4l2_std_id *std = arg;
1030 if (*std != V4L2_STD_UNKNOWN)
1031 return -EINVAL;
1032 return 0;
1033 }
1034
1035 case VIDIOC_ENUMSTD:
1036 {
1037 struct v4l2_standard *std = arg;
1038 if (std->index != 0)
1039 return -EINVAL;
1040 std->id = V4L2_STD_UNKNOWN;
1041 strncpy(std->name, "webcam", sizeof(std->name));
1042 return 0;
1043 }
1044
1045 case VIDIOC_REQBUFS:
1046 {
1047 struct v4l2_requestbuffers *rb = arg;
1048 int nbuffers;
1049
1050 PWC_DEBUG_IOCTL("ioctl(VIDIOC_REQBUFS) count=%d\n",rb->count);
1051 if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1052 return -EINVAL;
1053 if (rb->memory != V4L2_MEMORY_MMAP)
1054 return -EINVAL;
1055
1056 nbuffers = rb->count;
1057 if (nbuffers < 2)
1058 nbuffers = 2;
1059 else if (nbuffers > pwc_mbufs)
1060 nbuffers = pwc_mbufs;
1061 /* Force to use our # of buffers */
1062 rb->count = pwc_mbufs;
1063 return 0;
1064 }
1065
1066 case VIDIOC_QUERYBUF:
1067 {
1068 struct v4l2_buffer *buf = arg;
1069 int index;
1070
1071 PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) index=%d\n",buf->index);
1072 if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
1073 PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad type\n");
1074 return -EINVAL;
1075 }
1076 if (buf->memory != V4L2_MEMORY_MMAP) {
1077 PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad memory type\n");
1078 return -EINVAL;
1079 }
1080 index = buf->index;
1081 if (index < 0 || index >= pwc_mbufs) {
1082 PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad index %d\n", buf->index);
1083 return -EINVAL;
1084 }
1085
1086 memset(buf, 0, sizeof(struct v4l2_buffer));
1087 buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
1088 buf->index = index;
1089 buf->m.offset = index * pdev->len_per_image;
1090 if (pdev->vpalette == VIDEO_PALETTE_RAW)
1091 buf->bytesused = pdev->frame_size + sizeof(struct pwc_raw_frame);
1092 else
1093 buf->bytesused = pdev->view.size;
1094 buf->field = V4L2_FIELD_NONE;
1095 buf->memory = V4L2_MEMORY_MMAP;
1096 //buf->flags = V4L2_BUF_FLAG_MAPPED;
1097 buf->length = pdev->len_per_image;
1098
1099 PWC_DEBUG_READ("VIDIOC_QUERYBUF: index=%d\n",buf->index);
1100 PWC_DEBUG_READ("VIDIOC_QUERYBUF: m.offset=%d\n",buf->m.offset);
1101 PWC_DEBUG_READ("VIDIOC_QUERYBUF: bytesused=%d\n",buf->bytesused);
1102
1103 return 0;
1104 }
1105
1106 case VIDIOC_QBUF:
1107 {
1108 struct v4l2_buffer *buf = arg;
1109
1110 PWC_DEBUG_IOCTL("ioctl(VIDIOC_QBUF) index=%d\n",buf->index);
1111 if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1112 return -EINVAL;
1113 if (buf->memory != V4L2_MEMORY_MMAP)
1114 return -EINVAL;
1115 if (buf->index < 0 || buf->index >= pwc_mbufs)
1116 return -EINVAL;
1117
1118 buf->flags |= V4L2_BUF_FLAG_QUEUED;
1119 buf->flags &= ~V4L2_BUF_FLAG_DONE;
1120
1121 return 0;
1122 }
1123
1124 case VIDIOC_DQBUF:
1125 {
1126 struct v4l2_buffer *buf = arg;
1127 int ret;
1128
1129 PWC_DEBUG_IOCTL("ioctl(VIDIOC_DQBUF)\n");
1130
1131 if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
1132 return -EINVAL;
1133
1134 /* Add ourselves to the frame wait-queue.
1135
1136 FIXME: needs auditing for safety.
1137 QUESTION: In what respect? I think that using the
1138 frameq is safe now.
1139 */
1140 add_wait_queue(&pdev->frameq, &wait);
1141 while (pdev->full_frames == NULL) {
1142 if (pdev->error_status) {
1143 remove_wait_queue(&pdev->frameq, &wait);
1144 set_current_state(TASK_RUNNING);
1145 return -pdev->error_status;
1146 }
1147
1148 if (signal_pending(current)) {
1149 remove_wait_queue(&pdev->frameq, &wait);
1150 set_current_state(TASK_RUNNING);
1151 return -ERESTARTSYS;
1152 }
1153 schedule();
1154 set_current_state(TASK_INTERRUPTIBLE);
1155 }
1156 remove_wait_queue(&pdev->frameq, &wait);
1157 set_current_state(TASK_RUNNING);
1158
1159 PWC_DEBUG_IOCTL("VIDIOC_DQBUF: frame ready.\n");
1160 /* Decompress data in pdev->images[pdev->fill_image] */
1161 ret = pwc_handle_frame(pdev);
1162 if (ret)
1163 return -EFAULT;
1164 PWC_DEBUG_IOCTL("VIDIOC_DQBUF: after pwc_handle_frame\n");
1165
1166 buf->index = pdev->fill_image;
1167 if (pdev->vpalette == VIDEO_PALETTE_RAW)
1168 buf->bytesused = pdev->frame_size + sizeof(struct pwc_raw_frame);
1169 else
1170 buf->bytesused = pdev->view.size;
1171 buf->flags = V4L2_BUF_FLAG_MAPPED;
1172 buf->field = V4L2_FIELD_NONE;
1173 do_gettimeofday(&buf->timestamp);
1174 buf->sequence = 0;
1175 buf->memory = V4L2_MEMORY_MMAP;
1176 buf->m.offset = pdev->fill_image * pdev->len_per_image;
1177 buf->length = buf->bytesused;
1178 pwc_next_image(pdev);
1179
1180 PWC_DEBUG_IOCTL("VIDIOC_DQBUF: buf->index=%d\n",buf->index);
1181 PWC_DEBUG_IOCTL("VIDIOC_DQBUF: buf->length=%d\n",buf->length);
1182 PWC_DEBUG_IOCTL("VIDIOC_DQBUF: m.offset=%d\n",buf->m.offset);
1183 PWC_DEBUG_IOCTL("VIDIOC_DQBUF: bytesused=%d\n",buf->bytesused);
1184 PWC_DEBUG_IOCTL("VIDIOC_DQBUF: leaving\n");
1185 return 0;
1186
1187 }
1188
1189 case VIDIOC_STREAMON:
1190 {
1191 /* WARNING: pwc_try_video_mode() called pwc_isoc_init */
1192 pwc_isoc_init(pdev);
1193 return 0;
1194 }
1195
1196 case VIDIOC_STREAMOFF:
1197 {
1198 pwc_isoc_cleanup(pdev);
1199 return 0;
1200 }
1201
1202 default:
1203 return pwc_ioctl(pdev, cmd, arg);
1204 } /* ..switch */
1205 return 0;
1206}
1207
1208/* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */