1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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 {
131 .id = V4L2_CID_PRIVATE_SAVE_USER,
132 .type = V4L2_CTRL_TYPE_BUTTON,
133 .name = "Save User Settings",
134 .minimum = 0,
135 .maximum = 0,
136 .step = 0,
137 .default_value = 0,
138 },
139 {
140 .id = V4L2_CID_PRIVATE_RESTORE_USER,
141 .type = V4L2_CTRL_TYPE_BUTTON,
142 .name = "Restore User Settings",
143 .minimum = 0,
144 .maximum = 0,
145 .step = 0,
146 .default_value = 0,
147 },
148 {
149 .id = V4L2_CID_PRIVATE_RESTORE_FACTORY,
150 .type = V4L2_CTRL_TYPE_BUTTON,
151 .name = "Restore Factory Settings",
152 .minimum = 0,
153 .maximum = 0,
154 .step = 0,
155 .default_value = 0,
156 },
157 {
158 .id = V4L2_CID_PRIVATE_COLOUR_MODE,
159 .type = V4L2_CTRL_TYPE_BOOLEAN,
160 .name = "Colour mode",
161 .minimum = 0,
162 .maximum = 1,
163 .step = 1,
164 .default_value = 0,
165 },
166 {
167 .id = V4L2_CID_PRIVATE_AUTOCONTOUR,
168 .type = V4L2_CTRL_TYPE_BOOLEAN,
169 .name = "Auto contour",
170 .minimum = 0,
171 .maximum = 1,
172 .step = 1,
173 .default_value = 0,
174 },
175 {
176 .id = V4L2_CID_PRIVATE_CONTOUR,
177 .type = V4L2_CTRL_TYPE_INTEGER,
178 .name = "Contour",
179 .minimum = 0,
180 .maximum = 63,
181 .step = 1,
182 .default_value = 0,
183 },
184 {
185 .id = V4L2_CID_PRIVATE_BACKLIGHT,
186 .type = V4L2_CTRL_TYPE_BOOLEAN,
187 .name = "Backlight compensation",
188 .minimum = 0,
189 .maximum = 1,
190 .step = 1,
191 .default_value = 0,
192 },
193 {
194 .id = V4L2_CID_PRIVATE_FLICKERLESS,
195 .type = V4L2_CTRL_TYPE_BOOLEAN,
196 .name = "Flickerless",
197 .minimum = 0,
198 .maximum = 1,
199 .step = 1,
200 .default_value = 0,
201 },
202 {
203 .id = V4L2_CID_PRIVATE_NOISE_REDUCTION,
204 .type = V4L2_CTRL_TYPE_INTEGER,
205 .name = "Noise reduction",
206 .minimum = 0,
207 .maximum = 3,
208 .step = 1,
209 .default_value = 0,
210 },
211};
212
213
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
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
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
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
340long pwc_video_do_ioctl(struct file *file, unsigned int cmd, void *arg)
341{
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;
348 pdev = video_get_drvdata(vdev);
349 if (pdev == NULL)
350 return -EFAULT;
351
352#ifdef CONFIG_USB_PWC_DEBUG
353 if (PWC_DEBUG_LEVEL_IOCTL & pwc_trace) {
354 v4l_printk_ioctl(cmd);
355 printk("\n");
356 }
357#endif
358
359
360 switch (cmd) {
361
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
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
394
395
396
397 struct video_channel *v = arg;
398 if (v->channel != 0)
399 return -EINVAL;
400 return 0;
401 }
402
403
404
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
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;
433 break;
434 }
435
436 case VIDIOCSPICT:
437 {
438 struct video_picture *p = arg;
439
440
441
442
443
444
445
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
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
499 case VIDIOCGFBUF:
500 {
501 struct video_buffer *vb = arg;
502
503 memset(vb,0,sizeof(*vb));
504 break;
505 }
506
507
508 case VIDIOCGMBUF:
509 {
510
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;
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
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
532
533
534
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 }
558
559
560 if (pdev->image_used[vm->frame])
561 return -EBUSY;
562 pdev->image_used[vm->frame] = 1;
563
564
565
566
567
568
569
570
571
572 PWC_DEBUG_READ("VIDIOCMCAPTURE done.\n");
573 break;
574 }
575
576 case VIDIOCSYNC:
577 {
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592 int *mbuf = arg;
593 int ret;
594
595 PWC_DEBUG_READ("VIDIOCSYNC called (%d).\n", *mbuf);
596
597
598 if (*mbuf < 0 || *mbuf >= pwc_mbufs)
599 return -EINVAL;
600
601 if (pdev->image_used[*mbuf] == 0)
602 return -EINVAL;
603
604
605
606
607
608
609
610 add_wait_queue(&pdev->frameq, &wait);
611 while (pdev->full_frames == NULL) {
612
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
631
632
633
634
635
636 PWC_DEBUG_READ("VIDIOCSYNC: frame ready.\n");
637 pdev->fill_image = *mbuf;
638
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;
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
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;
674 vu->vbi = -1;
675 vu->radio = -1;
676 vu->teletext = -1;
677 break;
678 }
679
680
681 case VIDIOC_QUERYCAP:
682 {
683 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
698 case VIDIOC_ENUMINPUT:
699 {
700 struct v4l2_input *i = arg;
701
702 if ( i->index )
703 return -EINVAL;
704
705 memset(i, 0, sizeof(struct v4l2_input));
706 strcpy(i->name, "usb");
707 return 0;
708 }
709
710 case VIDIOC_G_INPUT:
711 {
712 int *i = arg;
713 *i = 0;
714 return 0;
715 }
716 case VIDIOC_S_INPUT:
717 {
718 int *i = arg;
719
720 if ( *i ) {
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
729 case VIDIOC_QUERYCTRL:
730 {
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
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 {
967 struct v4l2_fmtdesc *f = arg;
968 int index;
969
970 if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
971 return -EINVAL;
972
973
974 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
982 f->pixelformat = pdev->type<=646?V4L2_PIX_FMT_PWC1:V4L2_PIX_FMT_PWC2;
983 f->flags = V4L2_FMT_FLAG_COMPRESSED;
984 strlcpy(f->description,"Raw Philips Webcam",sizeof(f->description));
985 break;
986 case 1:
987 f->pixelformat = V4L2_PIX_FMT_YUV420;
988 strlcpy(f->description,"4:2:0, planar, Y-Cb-Cr",sizeof(f->description));
989 break;
990 default:
991 return -EINVAL;
992 }
993 return 0;
994 }
995
996 case VIDIOC_G_FMT:
997 {
998 struct v4l2_format *f = arg;
999
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
1012 case VIDIOC_S_FMT:
1013 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 strlcpy(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
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
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 >= 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
1130
1131
1132
1133
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
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;
1172 buf->length = pdev->len_per_image;
1173 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
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
1197 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
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
1255 default:
1256 return pwc_ioctl(pdev, cmd, arg);
1257 }
1258 return 0;
1259}
1260
1261
1262