diff options
-rw-r--r-- | drivers/media/video/pwc/pwc-if.c | 22 | ||||
-rw-r--r-- | drivers/media/video/pwc/pwc-v4l.c | 1034 | ||||
-rw-r--r-- | drivers/media/video/pwc/pwc.h | 3 |
3 files changed, 494 insertions, 565 deletions
diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c index 4aa70faaae8c..780af5f81642 100644 --- a/drivers/media/video/pwc/pwc-if.c +++ b/drivers/media/video/pwc/pwc-if.c | |||
@@ -151,8 +151,6 @@ static int pwc_video_close(struct file *file); | |||
151 | static ssize_t pwc_video_read(struct file *file, char __user *buf, | 151 | static ssize_t pwc_video_read(struct file *file, char __user *buf, |
152 | size_t count, loff_t *ppos); | 152 | size_t count, loff_t *ppos); |
153 | static unsigned int pwc_video_poll(struct file *file, poll_table *wait); | 153 | static unsigned int pwc_video_poll(struct file *file, poll_table *wait); |
154 | static long pwc_video_ioctl(struct file *file, | ||
155 | unsigned int ioctlnr, unsigned long arg); | ||
156 | static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma); | 154 | static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma); |
157 | 155 | ||
158 | static const struct v4l2_file_operations pwc_fops = { | 156 | static const struct v4l2_file_operations pwc_fops = { |
@@ -162,7 +160,7 @@ static const struct v4l2_file_operations pwc_fops = { | |||
162 | .read = pwc_video_read, | 160 | .read = pwc_video_read, |
163 | .poll = pwc_video_poll, | 161 | .poll = pwc_video_poll, |
164 | .mmap = pwc_video_mmap, | 162 | .mmap = pwc_video_mmap, |
165 | .unlocked_ioctl = pwc_video_ioctl, | 163 | .unlocked_ioctl = video_ioctl2, |
166 | }; | 164 | }; |
167 | static struct video_device pwc_template = { | 165 | static struct video_device pwc_template = { |
168 | .name = "Philips Webcam", /* Filled in later */ | 166 | .name = "Philips Webcam", /* Filled in later */ |
@@ -1378,23 +1376,6 @@ static unsigned int pwc_video_poll(struct file *file, poll_table *wait) | |||
1378 | return 0; | 1376 | return 0; |
1379 | } | 1377 | } |
1380 | 1378 | ||
1381 | static long pwc_video_ioctl(struct file *file, | ||
1382 | unsigned int cmd, unsigned long arg) | ||
1383 | { | ||
1384 | struct video_device *vdev = file->private_data; | ||
1385 | struct pwc_device *pdev; | ||
1386 | long r = -ENODEV; | ||
1387 | |||
1388 | if (!vdev) | ||
1389 | goto out; | ||
1390 | pdev = video_get_drvdata(vdev); | ||
1391 | |||
1392 | if (!pdev->unplugged) | ||
1393 | r = video_usercopy(file, cmd, arg, pwc_video_do_ioctl); | ||
1394 | out: | ||
1395 | return r; | ||
1396 | } | ||
1397 | |||
1398 | static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma) | 1379 | static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma) |
1399 | { | 1380 | { |
1400 | struct video_device *vdev = file->private_data; | 1381 | struct video_device *vdev = file->private_data; |
@@ -1744,6 +1725,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id | |||
1744 | memcpy(pdev->vdev, &pwc_template, sizeof(pwc_template)); | 1725 | memcpy(pdev->vdev, &pwc_template, sizeof(pwc_template)); |
1745 | pdev->vdev->parent = &intf->dev; | 1726 | pdev->vdev->parent = &intf->dev; |
1746 | pdev->vdev->lock = &pdev->modlock; | 1727 | pdev->vdev->lock = &pdev->modlock; |
1728 | pdev->vdev->ioctl_ops = &pwc_ioctl_ops; | ||
1747 | strcpy(pdev->vdev->name, name); | 1729 | strcpy(pdev->vdev->name, name); |
1748 | video_set_drvdata(pdev->vdev, pdev); | 1730 | video_set_drvdata(pdev->vdev, pdev); |
1749 | 1731 | ||
diff --git a/drivers/media/video/pwc/pwc-v4l.c b/drivers/media/video/pwc/pwc-v4l.c index 8a7e52c3b8f5..68a5313a52d5 100644 --- a/drivers/media/video/pwc/pwc-v4l.c +++ b/drivers/media/video/pwc/pwc-v4l.c | |||
@@ -341,606 +341,554 @@ static int pwc_vidioc_set_fmt(struct pwc_device *pdev, struct v4l2_format *f) | |||
341 | 341 | ||
342 | } | 342 | } |
343 | 343 | ||
344 | long pwc_video_do_ioctl(struct file *file, unsigned int cmd, void *arg) | 344 | static int pwc_querycap(struct file *file, void *fh, struct v4l2_capability *cap) |
345 | { | 345 | { |
346 | struct video_device *vdev = video_devdata(file); | 346 | struct video_device *vdev = video_devdata(file); |
347 | struct pwc_device *pdev; | 347 | struct pwc_device *pdev = video_drvdata(file); |
348 | DECLARE_WAITQUEUE(wait, current); | 348 | |
349 | 349 | strcpy(cap->driver, PWC_NAME); | |
350 | if (vdev == NULL) | 350 | strlcpy(cap->card, vdev->name, sizeof(cap->card)); |
351 | return -EFAULT; | 351 | usb_make_path(pdev->udev, cap->bus_info, sizeof(cap->bus_info)); |
352 | pdev = video_get_drvdata(vdev); | 352 | cap->version = PWC_VERSION_CODE; |
353 | if (pdev == NULL) | 353 | cap->capabilities = |
354 | return -EFAULT; | 354 | V4L2_CAP_VIDEO_CAPTURE | |
355 | V4L2_CAP_STREAMING | | ||
356 | V4L2_CAP_READWRITE; | ||
357 | return 0; | ||
358 | } | ||
355 | 359 | ||
356 | #ifdef CONFIG_USB_PWC_DEBUG | 360 | static int pwc_enum_input(struct file *file, void *fh, struct v4l2_input *i) |
357 | if (PWC_DEBUG_LEVEL_IOCTL & pwc_trace) { | 361 | { |
358 | v4l_printk_ioctl(cmd); | 362 | if (i->index) /* Only one INPUT is supported */ |
359 | printk("\n"); | 363 | return -EINVAL; |
360 | } | ||
361 | #endif | ||
362 | |||
363 | |||
364 | switch (cmd) { | ||
365 | /* V4L2 Layer */ | ||
366 | case VIDIOC_QUERYCAP: | ||
367 | { | ||
368 | struct v4l2_capability *cap = arg; | ||
369 | |||
370 | PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCAP) This application "\ | ||
371 | "try to use the v4l2 layer\n"); | ||
372 | strcpy(cap->driver,PWC_NAME); | ||
373 | strlcpy(cap->card, vdev->name, sizeof(cap->card)); | ||
374 | usb_make_path(pdev->udev,cap->bus_info,sizeof(cap->bus_info)); | ||
375 | cap->version = PWC_VERSION_CODE; | ||
376 | cap->capabilities = | ||
377 | V4L2_CAP_VIDEO_CAPTURE | | ||
378 | V4L2_CAP_STREAMING | | ||
379 | V4L2_CAP_READWRITE; | ||
380 | return 0; | ||
381 | } | ||
382 | 364 | ||
383 | case VIDIOC_ENUMINPUT: | 365 | strcpy(i->name, "usb"); |
384 | { | 366 | return 0; |
385 | struct v4l2_input *i = arg; | 367 | } |
386 | 368 | ||
387 | if ( i->index ) /* Only one INPUT is supported */ | 369 | static int pwc_g_input(struct file *file, void *fh, unsigned int *i) |
388 | return -EINVAL; | 370 | { |
371 | *i = 0; | ||
372 | return 0; | ||
373 | } | ||
389 | 374 | ||
390 | memset(i, 0, sizeof(struct v4l2_input)); | 375 | static int pwc_s_input(struct file *file, void *fh, unsigned int i) |
391 | strcpy(i->name, "usb"); | 376 | { |
392 | return 0; | 377 | return i ? -EINVAL : 0; |
393 | } | 378 | } |
394 | 379 | ||
395 | case VIDIOC_G_INPUT: | 380 | static int pwc_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *c) |
396 | { | 381 | { |
397 | int *i = arg; | 382 | int i; |
398 | *i = 0; /* Only one INPUT is supported */ | ||
399 | return 0; | ||
400 | } | ||
401 | case VIDIOC_S_INPUT: | ||
402 | { | ||
403 | int *i = arg; | ||
404 | 383 | ||
405 | if ( *i ) { /* Only one INPUT is supported */ | 384 | for (i = 0; i < sizeof(pwc_controls) / sizeof(struct v4l2_queryctrl); i++) { |
406 | PWC_DEBUG_IOCTL("Only one input source is"\ | 385 | if (pwc_controls[i].id == c->id) { |
407 | " supported with this webcam.\n"); | 386 | PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) found\n"); |
408 | return -EINVAL; | 387 | memcpy(c, &pwc_controls[i], sizeof(struct v4l2_queryctrl)); |
409 | } | ||
410 | return 0; | 388 | return 0; |
411 | } | 389 | } |
390 | } | ||
391 | return -EINVAL; | ||
392 | } | ||
412 | 393 | ||
413 | /* TODO: */ | 394 | static int pwc_g_ctrl(struct file *file, void *fh, struct v4l2_control *c) |
414 | case VIDIOC_QUERYCTRL: | 395 | { |
415 | { | 396 | struct pwc_device *pdev = video_drvdata(file); |
416 | struct v4l2_queryctrl *c = arg; | 397 | int ret; |
417 | int i; | ||
418 | |||
419 | PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) query id=%d\n", c->id); | ||
420 | for (i=0; i<sizeof(pwc_controls)/sizeof(struct v4l2_queryctrl); i++) { | ||
421 | if (pwc_controls[i].id == c->id) { | ||
422 | PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) found\n"); | ||
423 | memcpy(c,&pwc_controls[i],sizeof(struct v4l2_queryctrl)); | ||
424 | return 0; | ||
425 | } | ||
426 | } | ||
427 | PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYCTRL) not found\n"); | ||
428 | 398 | ||
399 | switch (c->id) { | ||
400 | case V4L2_CID_BRIGHTNESS: | ||
401 | c->value = pwc_get_brightness(pdev); | ||
402 | if (c->value < 0) | ||
429 | return -EINVAL; | 403 | return -EINVAL; |
430 | } | 404 | return 0; |
431 | case VIDIOC_G_CTRL: | 405 | case V4L2_CID_CONTRAST: |
432 | { | 406 | c->value = pwc_get_contrast(pdev); |
433 | struct v4l2_control *c = arg; | 407 | if (c->value < 0) |
434 | int ret; | ||
435 | |||
436 | switch (c->id) | ||
437 | { | ||
438 | case V4L2_CID_BRIGHTNESS: | ||
439 | c->value = pwc_get_brightness(pdev); | ||
440 | if (c->value<0) | ||
441 | return -EINVAL; | ||
442 | return 0; | ||
443 | case V4L2_CID_CONTRAST: | ||
444 | c->value = pwc_get_contrast(pdev); | ||
445 | if (c->value<0) | ||
446 | return -EINVAL; | ||
447 | return 0; | ||
448 | case V4L2_CID_SATURATION: | ||
449 | ret = pwc_get_saturation(pdev, &c->value); | ||
450 | if (ret<0) | ||
451 | return -EINVAL; | ||
452 | return 0; | ||
453 | case V4L2_CID_GAMMA: | ||
454 | c->value = pwc_get_gamma(pdev); | ||
455 | if (c->value<0) | ||
456 | return -EINVAL; | ||
457 | return 0; | ||
458 | case V4L2_CID_RED_BALANCE: | ||
459 | ret = pwc_get_red_gain(pdev, &c->value); | ||
460 | if (ret<0) | ||
461 | return -EINVAL; | ||
462 | c->value >>= 8; | ||
463 | return 0; | ||
464 | case V4L2_CID_BLUE_BALANCE: | ||
465 | ret = pwc_get_blue_gain(pdev, &c->value); | ||
466 | if (ret<0) | ||
467 | return -EINVAL; | ||
468 | c->value >>= 8; | ||
469 | return 0; | ||
470 | case V4L2_CID_AUTO_WHITE_BALANCE: | ||
471 | ret = pwc_get_awb(pdev); | ||
472 | if (ret<0) | ||
473 | return -EINVAL; | ||
474 | c->value = (ret == PWC_WB_MANUAL)?0:1; | ||
475 | return 0; | ||
476 | case V4L2_CID_GAIN: | ||
477 | ret = pwc_get_agc(pdev, &c->value); | ||
478 | if (ret<0) | ||
479 | return -EINVAL; | ||
480 | c->value >>= 8; | ||
481 | return 0; | ||
482 | case V4L2_CID_AUTOGAIN: | ||
483 | ret = pwc_get_agc(pdev, &c->value); | ||
484 | if (ret<0) | ||
485 | return -EINVAL; | ||
486 | c->value = (c->value < 0)?1:0; | ||
487 | return 0; | ||
488 | case V4L2_CID_EXPOSURE: | ||
489 | ret = pwc_get_shutter_speed(pdev, &c->value); | ||
490 | if (ret<0) | ||
491 | return -EINVAL; | ||
492 | return 0; | ||
493 | case V4L2_CID_PRIVATE_COLOUR_MODE: | ||
494 | ret = pwc_get_colour_mode(pdev, &c->value); | ||
495 | if (ret < 0) | ||
496 | return -EINVAL; | ||
497 | return 0; | ||
498 | case V4L2_CID_PRIVATE_AUTOCONTOUR: | ||
499 | ret = pwc_get_contour(pdev, &c->value); | ||
500 | if (ret < 0) | ||
501 | return -EINVAL; | ||
502 | c->value=(c->value == -1?1:0); | ||
503 | return 0; | ||
504 | case V4L2_CID_PRIVATE_CONTOUR: | ||
505 | ret = pwc_get_contour(pdev, &c->value); | ||
506 | if (ret < 0) | ||
507 | return -EINVAL; | ||
508 | c->value >>= 10; | ||
509 | return 0; | ||
510 | case V4L2_CID_PRIVATE_BACKLIGHT: | ||
511 | ret = pwc_get_backlight(pdev, &c->value); | ||
512 | if (ret < 0) | ||
513 | return -EINVAL; | ||
514 | return 0; | ||
515 | case V4L2_CID_PRIVATE_FLICKERLESS: | ||
516 | ret = pwc_get_flicker(pdev, &c->value); | ||
517 | if (ret < 0) | ||
518 | return -EINVAL; | ||
519 | c->value=(c->value?1:0); | ||
520 | return 0; | ||
521 | case V4L2_CID_PRIVATE_NOISE_REDUCTION: | ||
522 | ret = pwc_get_dynamic_noise(pdev, &c->value); | ||
523 | if (ret < 0) | ||
524 | return -EINVAL; | ||
525 | return 0; | ||
526 | |||
527 | case V4L2_CID_PRIVATE_SAVE_USER: | ||
528 | case V4L2_CID_PRIVATE_RESTORE_USER: | ||
529 | case V4L2_CID_PRIVATE_RESTORE_FACTORY: | ||
530 | return -EINVAL; | ||
531 | } | ||
532 | return -EINVAL; | 408 | return -EINVAL; |
533 | } | 409 | return 0; |
534 | case VIDIOC_S_CTRL: | 410 | case V4L2_CID_SATURATION: |
535 | { | 411 | ret = pwc_get_saturation(pdev, &c->value); |
536 | struct v4l2_control *c = arg; | 412 | if (ret < 0) |
537 | int ret; | ||
538 | |||
539 | switch (c->id) | ||
540 | { | ||
541 | case V4L2_CID_BRIGHTNESS: | ||
542 | c->value <<= 9; | ||
543 | ret = pwc_set_brightness(pdev, c->value); | ||
544 | if (ret<0) | ||
545 | return -EINVAL; | ||
546 | return 0; | ||
547 | case V4L2_CID_CONTRAST: | ||
548 | c->value <<= 10; | ||
549 | ret = pwc_set_contrast(pdev, c->value); | ||
550 | if (ret<0) | ||
551 | return -EINVAL; | ||
552 | return 0; | ||
553 | case V4L2_CID_SATURATION: | ||
554 | ret = pwc_set_saturation(pdev, c->value); | ||
555 | if (ret<0) | ||
556 | return -EINVAL; | ||
557 | return 0; | ||
558 | case V4L2_CID_GAMMA: | ||
559 | c->value <<= 11; | ||
560 | ret = pwc_set_gamma(pdev, c->value); | ||
561 | if (ret<0) | ||
562 | return -EINVAL; | ||
563 | return 0; | ||
564 | case V4L2_CID_RED_BALANCE: | ||
565 | c->value <<= 8; | ||
566 | ret = pwc_set_red_gain(pdev, c->value); | ||
567 | if (ret<0) | ||
568 | return -EINVAL; | ||
569 | return 0; | ||
570 | case V4L2_CID_BLUE_BALANCE: | ||
571 | c->value <<= 8; | ||
572 | ret = pwc_set_blue_gain(pdev, c->value); | ||
573 | if (ret<0) | ||
574 | return -EINVAL; | ||
575 | return 0; | ||
576 | case V4L2_CID_AUTO_WHITE_BALANCE: | ||
577 | c->value = (c->value == 0)?PWC_WB_MANUAL:PWC_WB_AUTO; | ||
578 | ret = pwc_set_awb(pdev, c->value); | ||
579 | if (ret<0) | ||
580 | return -EINVAL; | ||
581 | return 0; | ||
582 | case V4L2_CID_EXPOSURE: | ||
583 | c->value <<= 8; | ||
584 | ret = pwc_set_shutter_speed(pdev, c->value?0:1, c->value); | ||
585 | if (ret<0) | ||
586 | return -EINVAL; | ||
587 | return 0; | ||
588 | case V4L2_CID_AUTOGAIN: | ||
589 | /* autogain off means nothing without a gain */ | ||
590 | if (c->value == 0) | ||
591 | return 0; | ||
592 | ret = pwc_set_agc(pdev, c->value, 0); | ||
593 | if (ret<0) | ||
594 | return -EINVAL; | ||
595 | return 0; | ||
596 | case V4L2_CID_GAIN: | ||
597 | c->value <<= 8; | ||
598 | ret = pwc_set_agc(pdev, 0, c->value); | ||
599 | if (ret<0) | ||
600 | return -EINVAL; | ||
601 | return 0; | ||
602 | case V4L2_CID_PRIVATE_SAVE_USER: | ||
603 | if (pwc_save_user(pdev)) | ||
604 | return -EINVAL; | ||
605 | return 0; | ||
606 | case V4L2_CID_PRIVATE_RESTORE_USER: | ||
607 | if (pwc_restore_user(pdev)) | ||
608 | return -EINVAL; | ||
609 | return 0; | ||
610 | case V4L2_CID_PRIVATE_RESTORE_FACTORY: | ||
611 | if (pwc_restore_factory(pdev)) | ||
612 | return -EINVAL; | ||
613 | return 0; | ||
614 | case V4L2_CID_PRIVATE_COLOUR_MODE: | ||
615 | ret = pwc_set_colour_mode(pdev, c->value); | ||
616 | if (ret < 0) | ||
617 | return -EINVAL; | ||
618 | return 0; | ||
619 | case V4L2_CID_PRIVATE_AUTOCONTOUR: | ||
620 | c->value=(c->value == 1)?-1:0; | ||
621 | ret = pwc_set_contour(pdev, c->value); | ||
622 | if (ret < 0) | ||
623 | return -EINVAL; | ||
624 | return 0; | ||
625 | case V4L2_CID_PRIVATE_CONTOUR: | ||
626 | c->value <<= 10; | ||
627 | ret = pwc_set_contour(pdev, c->value); | ||
628 | if (ret < 0) | ||
629 | return -EINVAL; | ||
630 | return 0; | ||
631 | case V4L2_CID_PRIVATE_BACKLIGHT: | ||
632 | ret = pwc_set_backlight(pdev, c->value); | ||
633 | if (ret < 0) | ||
634 | return -EINVAL; | ||
635 | return 0; | ||
636 | case V4L2_CID_PRIVATE_FLICKERLESS: | ||
637 | ret = pwc_set_flicker(pdev, c->value); | ||
638 | if (ret < 0) | ||
639 | return -EINVAL; | ||
640 | case V4L2_CID_PRIVATE_NOISE_REDUCTION: | ||
641 | ret = pwc_set_dynamic_noise(pdev, c->value); | ||
642 | if (ret < 0) | ||
643 | return -EINVAL; | ||
644 | return 0; | ||
645 | |||
646 | } | ||
647 | return -EINVAL; | 413 | return -EINVAL; |
648 | } | 414 | return 0; |
415 | case V4L2_CID_GAMMA: | ||
416 | c->value = pwc_get_gamma(pdev); | ||
417 | if (c->value < 0) | ||
418 | return -EINVAL; | ||
419 | return 0; | ||
420 | case V4L2_CID_RED_BALANCE: | ||
421 | ret = pwc_get_red_gain(pdev, &c->value); | ||
422 | if (ret < 0) | ||
423 | return -EINVAL; | ||
424 | c->value >>= 8; | ||
425 | return 0; | ||
426 | case V4L2_CID_BLUE_BALANCE: | ||
427 | ret = pwc_get_blue_gain(pdev, &c->value); | ||
428 | if (ret < 0) | ||
429 | return -EINVAL; | ||
430 | c->value >>= 8; | ||
431 | return 0; | ||
432 | case V4L2_CID_AUTO_WHITE_BALANCE: | ||
433 | ret = pwc_get_awb(pdev); | ||
434 | if (ret < 0) | ||
435 | return -EINVAL; | ||
436 | c->value = (ret == PWC_WB_MANUAL) ? 0 : 1; | ||
437 | return 0; | ||
438 | case V4L2_CID_GAIN: | ||
439 | ret = pwc_get_agc(pdev, &c->value); | ||
440 | if (ret < 0) | ||
441 | return -EINVAL; | ||
442 | c->value >>= 8; | ||
443 | return 0; | ||
444 | case V4L2_CID_AUTOGAIN: | ||
445 | ret = pwc_get_agc(pdev, &c->value); | ||
446 | if (ret < 0) | ||
447 | return -EINVAL; | ||
448 | c->value = (c->value < 0) ? 1 : 0; | ||
449 | return 0; | ||
450 | case V4L2_CID_EXPOSURE: | ||
451 | ret = pwc_get_shutter_speed(pdev, &c->value); | ||
452 | if (ret < 0) | ||
453 | return -EINVAL; | ||
454 | return 0; | ||
455 | case V4L2_CID_PRIVATE_COLOUR_MODE: | ||
456 | ret = pwc_get_colour_mode(pdev, &c->value); | ||
457 | if (ret < 0) | ||
458 | return -EINVAL; | ||
459 | return 0; | ||
460 | case V4L2_CID_PRIVATE_AUTOCONTOUR: | ||
461 | ret = pwc_get_contour(pdev, &c->value); | ||
462 | if (ret < 0) | ||
463 | return -EINVAL; | ||
464 | c->value = (c->value == -1 ? 1 : 0); | ||
465 | return 0; | ||
466 | case V4L2_CID_PRIVATE_CONTOUR: | ||
467 | ret = pwc_get_contour(pdev, &c->value); | ||
468 | if (ret < 0) | ||
469 | return -EINVAL; | ||
470 | c->value >>= 10; | ||
471 | return 0; | ||
472 | case V4L2_CID_PRIVATE_BACKLIGHT: | ||
473 | ret = pwc_get_backlight(pdev, &c->value); | ||
474 | if (ret < 0) | ||
475 | return -EINVAL; | ||
476 | return 0; | ||
477 | case V4L2_CID_PRIVATE_FLICKERLESS: | ||
478 | ret = pwc_get_flicker(pdev, &c->value); | ||
479 | if (ret < 0) | ||
480 | return -EINVAL; | ||
481 | c->value = (c->value ? 1 : 0); | ||
482 | return 0; | ||
483 | case V4L2_CID_PRIVATE_NOISE_REDUCTION: | ||
484 | ret = pwc_get_dynamic_noise(pdev, &c->value); | ||
485 | if (ret < 0) | ||
486 | return -EINVAL; | ||
487 | return 0; | ||
649 | 488 | ||
650 | case VIDIOC_ENUM_FMT: | 489 | case V4L2_CID_PRIVATE_SAVE_USER: |
651 | { | 490 | case V4L2_CID_PRIVATE_RESTORE_USER: |
652 | struct v4l2_fmtdesc *f = arg; | 491 | case V4L2_CID_PRIVATE_RESTORE_FACTORY: |
653 | int index; | 492 | return -EINVAL; |
654 | 493 | } | |
655 | if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 494 | return -EINVAL; |
656 | return -EINVAL; | 495 | } |
657 | |||
658 | /* We only support two format: the raw format, and YUV */ | ||
659 | index = f->index; | ||
660 | memset(f,0,sizeof(struct v4l2_fmtdesc)); | ||
661 | f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
662 | f->index = index; | ||
663 | switch(index) | ||
664 | { | ||
665 | case 0: | ||
666 | /* RAW format */ | ||
667 | f->pixelformat = pdev->type<=646?V4L2_PIX_FMT_PWC1:V4L2_PIX_FMT_PWC2; | ||
668 | f->flags = V4L2_FMT_FLAG_COMPRESSED; | ||
669 | strlcpy(f->description,"Raw Philips Webcam",sizeof(f->description)); | ||
670 | break; | ||
671 | case 1: | ||
672 | f->pixelformat = V4L2_PIX_FMT_YUV420; | ||
673 | strlcpy(f->description,"4:2:0, planar, Y-Cb-Cr",sizeof(f->description)); | ||
674 | break; | ||
675 | default: | ||
676 | return -EINVAL; | ||
677 | } | ||
678 | return 0; | ||
679 | } | ||
680 | 496 | ||
681 | case VIDIOC_G_FMT: | 497 | static int pwc_s_ctrl(struct file *file, void *fh, struct v4l2_control *c) |
682 | { | 498 | { |
683 | struct v4l2_format *f = arg; | 499 | struct pwc_device *pdev = video_drvdata(file); |
500 | int ret; | ||
501 | |||
502 | switch (c->id) { | ||
503 | case V4L2_CID_BRIGHTNESS: | ||
504 | c->value <<= 9; | ||
505 | ret = pwc_set_brightness(pdev, c->value); | ||
506 | if (ret < 0) | ||
507 | return -EINVAL; | ||
508 | return 0; | ||
509 | case V4L2_CID_CONTRAST: | ||
510 | c->value <<= 10; | ||
511 | ret = pwc_set_contrast(pdev, c->value); | ||
512 | if (ret < 0) | ||
513 | return -EINVAL; | ||
514 | return 0; | ||
515 | case V4L2_CID_SATURATION: | ||
516 | ret = pwc_set_saturation(pdev, c->value); | ||
517 | if (ret < 0) | ||
518 | return -EINVAL; | ||
519 | return 0; | ||
520 | case V4L2_CID_GAMMA: | ||
521 | c->value <<= 11; | ||
522 | ret = pwc_set_gamma(pdev, c->value); | ||
523 | if (ret < 0) | ||
524 | return -EINVAL; | ||
525 | return 0; | ||
526 | case V4L2_CID_RED_BALANCE: | ||
527 | c->value <<= 8; | ||
528 | ret = pwc_set_red_gain(pdev, c->value); | ||
529 | if (ret < 0) | ||
530 | return -EINVAL; | ||
531 | return 0; | ||
532 | case V4L2_CID_BLUE_BALANCE: | ||
533 | c->value <<= 8; | ||
534 | ret = pwc_set_blue_gain(pdev, c->value); | ||
535 | if (ret < 0) | ||
536 | return -EINVAL; | ||
537 | return 0; | ||
538 | case V4L2_CID_AUTO_WHITE_BALANCE: | ||
539 | c->value = (c->value == 0) ? PWC_WB_MANUAL : PWC_WB_AUTO; | ||
540 | ret = pwc_set_awb(pdev, c->value); | ||
541 | if (ret < 0) | ||
542 | return -EINVAL; | ||
543 | return 0; | ||
544 | case V4L2_CID_EXPOSURE: | ||
545 | c->value <<= 8; | ||
546 | ret = pwc_set_shutter_speed(pdev, c->value ? 0 : 1, c->value); | ||
547 | if (ret < 0) | ||
548 | return -EINVAL; | ||
549 | return 0; | ||
550 | case V4L2_CID_AUTOGAIN: | ||
551 | /* autogain off means nothing without a gain */ | ||
552 | if (c->value == 0) | ||
553 | return 0; | ||
554 | ret = pwc_set_agc(pdev, c->value, 0); | ||
555 | if (ret < 0) | ||
556 | return -EINVAL; | ||
557 | return 0; | ||
558 | case V4L2_CID_GAIN: | ||
559 | c->value <<= 8; | ||
560 | ret = pwc_set_agc(pdev, 0, c->value); | ||
561 | if (ret < 0) | ||
562 | return -EINVAL; | ||
563 | return 0; | ||
564 | case V4L2_CID_PRIVATE_SAVE_USER: | ||
565 | if (pwc_save_user(pdev)) | ||
566 | return -EINVAL; | ||
567 | return 0; | ||
568 | case V4L2_CID_PRIVATE_RESTORE_USER: | ||
569 | if (pwc_restore_user(pdev)) | ||
570 | return -EINVAL; | ||
571 | return 0; | ||
572 | case V4L2_CID_PRIVATE_RESTORE_FACTORY: | ||
573 | if (pwc_restore_factory(pdev)) | ||
574 | return -EINVAL; | ||
575 | return 0; | ||
576 | case V4L2_CID_PRIVATE_COLOUR_MODE: | ||
577 | ret = pwc_set_colour_mode(pdev, c->value); | ||
578 | if (ret < 0) | ||
579 | return -EINVAL; | ||
580 | return 0; | ||
581 | case V4L2_CID_PRIVATE_AUTOCONTOUR: | ||
582 | c->value = (c->value == 1) ? -1 : 0; | ||
583 | ret = pwc_set_contour(pdev, c->value); | ||
584 | if (ret < 0) | ||
585 | return -EINVAL; | ||
586 | return 0; | ||
587 | case V4L2_CID_PRIVATE_CONTOUR: | ||
588 | c->value <<= 10; | ||
589 | ret = pwc_set_contour(pdev, c->value); | ||
590 | if (ret < 0) | ||
591 | return -EINVAL; | ||
592 | return 0; | ||
593 | case V4L2_CID_PRIVATE_BACKLIGHT: | ||
594 | ret = pwc_set_backlight(pdev, c->value); | ||
595 | if (ret < 0) | ||
596 | return -EINVAL; | ||
597 | return 0; | ||
598 | case V4L2_CID_PRIVATE_FLICKERLESS: | ||
599 | ret = pwc_set_flicker(pdev, c->value); | ||
600 | if (ret < 0) | ||
601 | return -EINVAL; | ||
602 | case V4L2_CID_PRIVATE_NOISE_REDUCTION: | ||
603 | ret = pwc_set_dynamic_noise(pdev, c->value); | ||
604 | if (ret < 0) | ||
605 | return -EINVAL; | ||
606 | return 0; | ||
684 | 607 | ||
685 | PWC_DEBUG_IOCTL("ioctl(VIDIOC_G_FMT) return size %dx%d\n",pdev->image.x,pdev->image.y); | 608 | } |
686 | if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 609 | return -EINVAL; |
687 | return -EINVAL; | 610 | } |
688 | 611 | ||
689 | pwc_vidioc_fill_fmt(pdev, f); | 612 | static int pwc_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *f) |
613 | { | ||
614 | struct pwc_device *pdev = video_drvdata(file); | ||
615 | |||
616 | /* We only support two format: the raw format, and YUV */ | ||
617 | switch (f->index) { | ||
618 | case 0: | ||
619 | /* RAW format */ | ||
620 | f->pixelformat = pdev->type <= 646 ? V4L2_PIX_FMT_PWC1 : V4L2_PIX_FMT_PWC2; | ||
621 | f->flags = V4L2_FMT_FLAG_COMPRESSED; | ||
622 | strlcpy(f->description, "Raw Philips Webcam", sizeof(f->description)); | ||
623 | break; | ||
624 | case 1: | ||
625 | f->pixelformat = V4L2_PIX_FMT_YUV420; | ||
626 | strlcpy(f->description, "4:2:0, planar, Y-Cb-Cr", sizeof(f->description)); | ||
627 | break; | ||
628 | default: | ||
629 | return -EINVAL; | ||
630 | } | ||
631 | return 0; | ||
632 | } | ||
690 | 633 | ||
691 | return 0; | 634 | static int pwc_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f) |
692 | } | 635 | { |
636 | struct pwc_device *pdev = video_drvdata(file); | ||
693 | 637 | ||
694 | case VIDIOC_TRY_FMT: | 638 | PWC_DEBUG_IOCTL("ioctl(VIDIOC_G_FMT) return size %dx%d\n", |
695 | return pwc_vidioc_try_fmt(pdev, arg); | 639 | pdev->image.x, pdev->image.y); |
640 | pwc_vidioc_fill_fmt(pdev, f); | ||
641 | return 0; | ||
642 | } | ||
696 | 643 | ||
697 | case VIDIOC_S_FMT: | 644 | static int pwc_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f) |
698 | return pwc_vidioc_set_fmt(pdev, arg); | 645 | { |
646 | struct pwc_device *pdev = video_drvdata(file); | ||
699 | 647 | ||
700 | case VIDIOC_G_STD: | 648 | return pwc_vidioc_try_fmt(pdev, f); |
701 | { | 649 | } |
702 | v4l2_std_id *std = arg; | ||
703 | *std = V4L2_STD_UNKNOWN; | ||
704 | return 0; | ||
705 | } | ||
706 | 650 | ||
707 | case VIDIOC_S_STD: | 651 | static int pwc_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f) |
708 | { | 652 | { |
709 | v4l2_std_id *std = arg; | 653 | struct pwc_device *pdev = video_drvdata(file); |
710 | if (*std != V4L2_STD_UNKNOWN) | ||
711 | return -EINVAL; | ||
712 | return 0; | ||
713 | } | ||
714 | 654 | ||
715 | case VIDIOC_ENUMSTD: | 655 | return pwc_vidioc_set_fmt(pdev, f); |
716 | { | 656 | } |
717 | struct v4l2_standard *std = arg; | ||
718 | if (std->index != 0) | ||
719 | return -EINVAL; | ||
720 | std->id = V4L2_STD_UNKNOWN; | ||
721 | strlcpy(std->name, "webcam", sizeof(std->name)); | ||
722 | return 0; | ||
723 | } | ||
724 | 657 | ||
725 | case VIDIOC_REQBUFS: | 658 | static int pwc_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *rb) |
726 | { | 659 | { |
727 | struct v4l2_requestbuffers *rb = arg; | 660 | int nbuffers; |
728 | int nbuffers; | ||
729 | 661 | ||
730 | PWC_DEBUG_IOCTL("ioctl(VIDIOC_REQBUFS) count=%d\n",rb->count); | 662 | PWC_DEBUG_IOCTL("ioctl(VIDIOC_REQBUFS) count=%d\n", rb->count); |
731 | if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 663 | if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
732 | return -EINVAL; | 664 | return -EINVAL; |
733 | if (rb->memory != V4L2_MEMORY_MMAP) | 665 | if (rb->memory != V4L2_MEMORY_MMAP) |
734 | return -EINVAL; | 666 | return -EINVAL; |
735 | 667 | ||
736 | nbuffers = rb->count; | 668 | nbuffers = rb->count; |
737 | if (nbuffers < 2) | 669 | if (nbuffers < 2) |
738 | nbuffers = 2; | 670 | nbuffers = 2; |
739 | else if (nbuffers > pwc_mbufs) | 671 | else if (nbuffers > pwc_mbufs) |
740 | nbuffers = pwc_mbufs; | 672 | nbuffers = pwc_mbufs; |
741 | /* Force to use our # of buffers */ | 673 | /* Force to use our # of buffers */ |
742 | rb->count = pwc_mbufs; | 674 | rb->count = pwc_mbufs; |
743 | return 0; | 675 | return 0; |
744 | } | 676 | } |
745 | 677 | ||
746 | case VIDIOC_QUERYBUF: | 678 | static int pwc_querybuf(struct file *file, void *fh, struct v4l2_buffer *buf) |
747 | { | 679 | { |
748 | struct v4l2_buffer *buf = arg; | 680 | struct pwc_device *pdev = video_drvdata(file); |
749 | int index; | 681 | int index; |
750 | 682 | ||
751 | PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) index=%d\n",buf->index); | 683 | PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) index=%d\n", buf->index); |
752 | if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { | 684 | if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) { |
753 | PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad type\n"); | 685 | PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad type\n"); |
754 | return -EINVAL; | 686 | return -EINVAL; |
755 | } | 687 | } |
756 | if (buf->memory != V4L2_MEMORY_MMAP) { | 688 | index = buf->index; |
757 | PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad memory type\n"); | 689 | if (index < 0 || index >= pwc_mbufs) { |
758 | return -EINVAL; | 690 | PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad index %d\n", buf->index); |
759 | } | 691 | return -EINVAL; |
760 | index = buf->index; | 692 | } |
761 | if (index < 0 || index >= pwc_mbufs) { | ||
762 | PWC_DEBUG_IOCTL("ioctl(VIDIOC_QUERYBUF) Bad index %d\n", buf->index); | ||
763 | return -EINVAL; | ||
764 | } | ||
765 | 693 | ||
766 | memset(buf, 0, sizeof(struct v4l2_buffer)); | 694 | buf->m.offset = index * pdev->len_per_image; |
767 | buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 695 | if (pdev->pixfmt != V4L2_PIX_FMT_YUV420) |
768 | buf->index = index; | 696 | buf->bytesused = pdev->frame_size + sizeof(struct pwc_raw_frame); |
769 | buf->m.offset = index * pdev->len_per_image; | 697 | else |
770 | if (pdev->pixfmt != V4L2_PIX_FMT_YUV420) | 698 | buf->bytesused = pdev->view.size; |
771 | buf->bytesused = pdev->frame_size + sizeof(struct pwc_raw_frame); | 699 | buf->field = V4L2_FIELD_NONE; |
772 | else | 700 | buf->memory = V4L2_MEMORY_MMAP; |
773 | buf->bytesused = pdev->view.size; | 701 | /*buf->flags = V4L2_BUF_FLAG_MAPPED;*/ |
774 | buf->field = V4L2_FIELD_NONE; | 702 | buf->length = pdev->len_per_image; |
775 | buf->memory = V4L2_MEMORY_MMAP; | ||
776 | //buf->flags = V4L2_BUF_FLAG_MAPPED; | ||
777 | buf->length = pdev->len_per_image; | ||
778 | |||
779 | PWC_DEBUG_READ("VIDIOC_QUERYBUF: index=%d\n",buf->index); | ||
780 | PWC_DEBUG_READ("VIDIOC_QUERYBUF: m.offset=%d\n",buf->m.offset); | ||
781 | PWC_DEBUG_READ("VIDIOC_QUERYBUF: bytesused=%d\n",buf->bytesused); | ||
782 | 703 | ||
783 | return 0; | 704 | PWC_DEBUG_READ("VIDIOC_QUERYBUF: index=%d\n", buf->index); |
784 | } | 705 | PWC_DEBUG_READ("VIDIOC_QUERYBUF: m.offset=%d\n", buf->m.offset); |
706 | PWC_DEBUG_READ("VIDIOC_QUERYBUF: bytesused=%d\n", buf->bytesused); | ||
785 | 707 | ||
786 | case VIDIOC_QBUF: | 708 | return 0; |
787 | { | 709 | } |
788 | struct v4l2_buffer *buf = arg; | ||
789 | 710 | ||
790 | PWC_DEBUG_IOCTL("ioctl(VIDIOC_QBUF) index=%d\n",buf->index); | 711 | static int pwc_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf) |
791 | if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 712 | { |
792 | return -EINVAL; | 713 | PWC_DEBUG_IOCTL("ioctl(VIDIOC_QBUF) index=%d\n", buf->index); |
793 | if (buf->memory != V4L2_MEMORY_MMAP) | 714 | if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
794 | return -EINVAL; | 715 | return -EINVAL; |
795 | if (buf->index >= pwc_mbufs) | 716 | if (buf->memory != V4L2_MEMORY_MMAP) |
796 | return -EINVAL; | 717 | return -EINVAL; |
718 | if (buf->index >= pwc_mbufs) | ||
719 | return -EINVAL; | ||
797 | 720 | ||
798 | buf->flags |= V4L2_BUF_FLAG_QUEUED; | 721 | buf->flags |= V4L2_BUF_FLAG_QUEUED; |
799 | buf->flags &= ~V4L2_BUF_FLAG_DONE; | 722 | buf->flags &= ~V4L2_BUF_FLAG_DONE; |
800 | 723 | ||
801 | return 0; | 724 | return 0; |
802 | } | 725 | } |
803 | 726 | ||
804 | case VIDIOC_DQBUF: | 727 | static int pwc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf) |
805 | { | 728 | { |
806 | struct v4l2_buffer *buf = arg; | 729 | DECLARE_WAITQUEUE(wait, current); |
807 | int ret; | 730 | struct pwc_device *pdev = video_drvdata(file); |
731 | int ret; | ||
808 | 732 | ||
809 | PWC_DEBUG_IOCTL("ioctl(VIDIOC_DQBUF)\n"); | 733 | PWC_DEBUG_IOCTL("ioctl(VIDIOC_DQBUF)\n"); |
810 | 734 | ||
811 | if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 735 | if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) |
812 | return -EINVAL; | 736 | return -EINVAL; |
813 | 737 | ||
814 | /* Add ourselves to the frame wait-queue. | 738 | add_wait_queue(&pdev->frameq, &wait); |
815 | 739 | while (pdev->full_frames == NULL) { | |
816 | FIXME: needs auditing for safety. | 740 | if (pdev->error_status) { |
817 | QUESTION: In what respect? I think that using the | 741 | remove_wait_queue(&pdev->frameq, &wait); |
818 | frameq is safe now. | 742 | set_current_state(TASK_RUNNING); |
819 | */ | 743 | return -pdev->error_status; |
820 | add_wait_queue(&pdev->frameq, &wait); | 744 | } |
821 | while (pdev->full_frames == NULL) { | ||
822 | if (pdev->error_status) { | ||
823 | remove_wait_queue(&pdev->frameq, &wait); | ||
824 | set_current_state(TASK_RUNNING); | ||
825 | return -pdev->error_status; | ||
826 | } | ||
827 | 745 | ||
828 | if (signal_pending(current)) { | 746 | if (signal_pending(current)) { |
829 | remove_wait_queue(&pdev->frameq, &wait); | ||
830 | set_current_state(TASK_RUNNING); | ||
831 | return -ERESTARTSYS; | ||
832 | } | ||
833 | mutex_unlock(&pdev->modlock); | ||
834 | schedule(); | ||
835 | set_current_state(TASK_INTERRUPTIBLE); | ||
836 | mutex_lock(&pdev->modlock); | ||
837 | } | ||
838 | remove_wait_queue(&pdev->frameq, &wait); | 747 | remove_wait_queue(&pdev->frameq, &wait); |
839 | set_current_state(TASK_RUNNING); | 748 | set_current_state(TASK_RUNNING); |
749 | return -ERESTARTSYS; | ||
750 | } | ||
751 | mutex_unlock(&pdev->modlock); | ||
752 | schedule(); | ||
753 | set_current_state(TASK_INTERRUPTIBLE); | ||
754 | mutex_lock(&pdev->modlock); | ||
755 | } | ||
756 | remove_wait_queue(&pdev->frameq, &wait); | ||
757 | set_current_state(TASK_RUNNING); | ||
840 | 758 | ||
841 | PWC_DEBUG_IOCTL("VIDIOC_DQBUF: frame ready.\n"); | 759 | PWC_DEBUG_IOCTL("VIDIOC_DQBUF: frame ready.\n"); |
842 | /* Decompress data in pdev->images[pdev->fill_image] */ | 760 | /* Decompress data in pdev->images[pdev->fill_image] */ |
843 | ret = pwc_handle_frame(pdev); | 761 | ret = pwc_handle_frame(pdev); |
844 | if (ret) | 762 | if (ret) |
845 | return -EFAULT; | 763 | return -EFAULT; |
846 | PWC_DEBUG_IOCTL("VIDIOC_DQBUF: after pwc_handle_frame\n"); | 764 | PWC_DEBUG_IOCTL("VIDIOC_DQBUF: after pwc_handle_frame\n"); |
847 | 765 | ||
848 | buf->index = pdev->fill_image; | 766 | buf->index = pdev->fill_image; |
849 | if (pdev->pixfmt != V4L2_PIX_FMT_YUV420) | 767 | if (pdev->pixfmt != V4L2_PIX_FMT_YUV420) |
850 | buf->bytesused = pdev->frame_size + sizeof(struct pwc_raw_frame); | 768 | buf->bytesused = pdev->frame_size + sizeof(struct pwc_raw_frame); |
851 | else | 769 | else |
852 | buf->bytesused = pdev->view.size; | 770 | buf->bytesused = pdev->view.size; |
853 | buf->flags = V4L2_BUF_FLAG_MAPPED; | 771 | buf->flags = V4L2_BUF_FLAG_MAPPED; |
854 | buf->field = V4L2_FIELD_NONE; | 772 | buf->field = V4L2_FIELD_NONE; |
855 | do_gettimeofday(&buf->timestamp); | 773 | do_gettimeofday(&buf->timestamp); |
856 | buf->sequence = 0; | 774 | buf->sequence = 0; |
857 | buf->memory = V4L2_MEMORY_MMAP; | 775 | buf->memory = V4L2_MEMORY_MMAP; |
858 | buf->m.offset = pdev->fill_image * pdev->len_per_image; | 776 | buf->m.offset = pdev->fill_image * pdev->len_per_image; |
859 | buf->length = pdev->len_per_image; | 777 | buf->length = pdev->len_per_image; |
860 | pwc_next_image(pdev); | 778 | pwc_next_image(pdev); |
861 | 779 | ||
862 | PWC_DEBUG_IOCTL("VIDIOC_DQBUF: buf->index=%d\n",buf->index); | 780 | PWC_DEBUG_IOCTL("VIDIOC_DQBUF: buf->index=%d\n", buf->index); |
863 | PWC_DEBUG_IOCTL("VIDIOC_DQBUF: buf->length=%d\n",buf->length); | 781 | PWC_DEBUG_IOCTL("VIDIOC_DQBUF: buf->length=%d\n", buf->length); |
864 | PWC_DEBUG_IOCTL("VIDIOC_DQBUF: m.offset=%d\n",buf->m.offset); | 782 | PWC_DEBUG_IOCTL("VIDIOC_DQBUF: m.offset=%d\n", buf->m.offset); |
865 | PWC_DEBUG_IOCTL("VIDIOC_DQBUF: bytesused=%d\n",buf->bytesused); | 783 | PWC_DEBUG_IOCTL("VIDIOC_DQBUF: bytesused=%d\n", buf->bytesused); |
866 | PWC_DEBUG_IOCTL("VIDIOC_DQBUF: leaving\n"); | 784 | PWC_DEBUG_IOCTL("VIDIOC_DQBUF: leaving\n"); |
867 | return 0; | 785 | return 0; |
868 | 786 | ||
869 | } | 787 | } |
870 | 788 | ||
871 | case VIDIOC_STREAMON: | 789 | static int pwc_streamon(struct file *file, void *fh, enum v4l2_buf_type i) |
872 | { | 790 | { |
873 | return pwc_isoc_init(pdev); | 791 | struct pwc_device *pdev = video_drvdata(file); |
874 | } | ||
875 | 792 | ||
876 | case VIDIOC_STREAMOFF: | 793 | return pwc_isoc_init(pdev); |
877 | { | 794 | } |
878 | pwc_isoc_cleanup(pdev); | ||
879 | return 0; | ||
880 | } | ||
881 | 795 | ||
882 | case VIDIOC_ENUM_FRAMESIZES: | 796 | static int pwc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i) |
883 | { | 797 | { |
884 | struct v4l2_frmsizeenum *fsize = arg; | 798 | struct pwc_device *pdev = video_drvdata(file); |
885 | unsigned int i = 0, index = fsize->index; | ||
886 | |||
887 | if (fsize->pixel_format == V4L2_PIX_FMT_YUV420) { | ||
888 | for (i = 0; i < PSZ_MAX; i++) { | ||
889 | if (pdev->image_mask & (1UL << i)) { | ||
890 | if (!index--) { | ||
891 | fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; | ||
892 | fsize->discrete.width = pwc_image_sizes[i].x; | ||
893 | fsize->discrete.height = pwc_image_sizes[i].y; | ||
894 | return 0; | ||
895 | } | ||
896 | } | ||
897 | } | ||
898 | } else if (fsize->index == 0 && | ||
899 | ((fsize->pixel_format == V4L2_PIX_FMT_PWC1 && DEVICE_USE_CODEC1(pdev->type)) || | ||
900 | (fsize->pixel_format == V4L2_PIX_FMT_PWC2 && DEVICE_USE_CODEC23(pdev->type)))) { | ||
901 | |||
902 | fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; | ||
903 | fsize->discrete.width = pdev->abs_max.x; | ||
904 | fsize->discrete.height = pdev->abs_max.y; | ||
905 | return 0; | ||
906 | } | ||
907 | return -EINVAL; | ||
908 | } | ||
909 | 799 | ||
910 | case VIDIOC_ENUM_FRAMEINTERVALS: | 800 | pwc_isoc_cleanup(pdev); |
911 | { | 801 | return 0; |
912 | struct v4l2_frmivalenum *fival = arg; | 802 | } |
913 | int size = -1; | 803 | |
914 | unsigned int i; | 804 | static int pwc_enum_framesizes(struct file *file, void *fh, |
915 | 805 | struct v4l2_frmsizeenum *fsize) | |
916 | for (i = 0; i < PSZ_MAX; i++) { | 806 | { |
917 | if (pwc_image_sizes[i].x == fival->width && | 807 | struct pwc_device *pdev = video_drvdata(file); |
918 | pwc_image_sizes[i].y == fival->height) { | 808 | unsigned int i = 0, index = fsize->index; |
919 | size = i; | 809 | |
920 | break; | 810 | if (fsize->pixel_format == V4L2_PIX_FMT_YUV420) { |
811 | for (i = 0; i < PSZ_MAX; i++) { | ||
812 | if (pdev->image_mask & (1UL << i)) { | ||
813 | if (!index--) { | ||
814 | fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; | ||
815 | fsize->discrete.width = pwc_image_sizes[i].x; | ||
816 | fsize->discrete.height = pwc_image_sizes[i].y; | ||
817 | return 0; | ||
921 | } | 818 | } |
922 | } | 819 | } |
820 | } | ||
821 | } else if (fsize->index == 0 && | ||
822 | ((fsize->pixel_format == V4L2_PIX_FMT_PWC1 && DEVICE_USE_CODEC1(pdev->type)) || | ||
823 | (fsize->pixel_format == V4L2_PIX_FMT_PWC2 && DEVICE_USE_CODEC23(pdev->type)))) { | ||
824 | |||
825 | fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE; | ||
826 | fsize->discrete.width = pdev->abs_max.x; | ||
827 | fsize->discrete.height = pdev->abs_max.y; | ||
828 | return 0; | ||
829 | } | ||
830 | return -EINVAL; | ||
831 | } | ||
923 | 832 | ||
924 | /* TODO: Support raw format */ | 833 | static int pwc_enum_frameintervals(struct file *file, void *fh, |
925 | if (size < 0 || fival->pixel_format != V4L2_PIX_FMT_YUV420) { | 834 | struct v4l2_frmivalenum *fival) |
926 | return -EINVAL; | 835 | { |
927 | } | 836 | struct pwc_device *pdev = video_drvdata(file); |
837 | int size = -1; | ||
838 | unsigned int i; | ||
839 | |||
840 | for (i = 0; i < PSZ_MAX; i++) { | ||
841 | if (pwc_image_sizes[i].x == fival->width && | ||
842 | pwc_image_sizes[i].y == fival->height) { | ||
843 | size = i; | ||
844 | break; | ||
845 | } | ||
846 | } | ||
928 | 847 | ||
929 | i = pwc_get_fps(pdev, fival->index, size); | 848 | /* TODO: Support raw format */ |
930 | if (!i) | 849 | if (size < 0 || fival->pixel_format != V4L2_PIX_FMT_YUV420) |
931 | return -EINVAL; | 850 | return -EINVAL; |
932 | 851 | ||
933 | fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; | 852 | i = pwc_get_fps(pdev, fival->index, size); |
934 | fival->discrete.numerator = 1; | 853 | if (!i) |
935 | fival->discrete.denominator = i; | 854 | return -EINVAL; |
936 | 855 | ||
937 | return 0; | 856 | fival->type = V4L2_FRMIVAL_TYPE_DISCRETE; |
938 | } | 857 | fival->discrete.numerator = 1; |
858 | fival->discrete.denominator = i; | ||
939 | 859 | ||
940 | default: | ||
941 | return pwc_ioctl(pdev, cmd, arg); | ||
942 | } /* ..switch */ | ||
943 | return 0; | 860 | return 0; |
944 | } | 861 | } |
945 | 862 | ||
863 | static long pwc_default(struct file *file, void *fh, int cmd, void *arg) | ||
864 | { | ||
865 | struct pwc_device *pdev = video_drvdata(file); | ||
866 | |||
867 | return pwc_ioctl(pdev, cmd, arg); | ||
868 | } | ||
869 | |||
870 | const struct v4l2_ioctl_ops pwc_ioctl_ops = { | ||
871 | .vidioc_querycap = pwc_querycap, | ||
872 | .vidioc_enum_input = pwc_enum_input, | ||
873 | .vidioc_g_input = pwc_g_input, | ||
874 | .vidioc_s_input = pwc_s_input, | ||
875 | .vidioc_enum_fmt_vid_cap = pwc_enum_fmt_vid_cap, | ||
876 | .vidioc_g_fmt_vid_cap = pwc_g_fmt_vid_cap, | ||
877 | .vidioc_s_fmt_vid_cap = pwc_s_fmt_vid_cap, | ||
878 | .vidioc_try_fmt_vid_cap = pwc_try_fmt_vid_cap, | ||
879 | .vidioc_queryctrl = pwc_queryctrl, | ||
880 | .vidioc_g_ctrl = pwc_g_ctrl, | ||
881 | .vidioc_s_ctrl = pwc_s_ctrl, | ||
882 | .vidioc_reqbufs = pwc_reqbufs, | ||
883 | .vidioc_querybuf = pwc_querybuf, | ||
884 | .vidioc_qbuf = pwc_qbuf, | ||
885 | .vidioc_dqbuf = pwc_dqbuf, | ||
886 | .vidioc_streamon = pwc_streamon, | ||
887 | .vidioc_streamoff = pwc_streamoff, | ||
888 | .vidioc_enum_framesizes = pwc_enum_framesizes, | ||
889 | .vidioc_enum_frameintervals = pwc_enum_frameintervals, | ||
890 | .vidioc_default = pwc_default, | ||
891 | }; | ||
892 | |||
893 | |||
946 | /* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */ | 894 | /* vim: set cino= formatoptions=croql cindent shiftwidth=8 tabstop=8: */ |
diff --git a/drivers/media/video/pwc/pwc.h b/drivers/media/video/pwc/pwc.h index 16bbc6df9b07..e947766337d6 100644 --- a/drivers/media/video/pwc/pwc.h +++ b/drivers/media/video/pwc/pwc.h | |||
@@ -339,8 +339,7 @@ extern int pwc_camera_power(struct pwc_device *pdev, int power); | |||
339 | /* Private ioctl()s; see pwc-ioctl.h */ | 339 | /* Private ioctl()s; see pwc-ioctl.h */ |
340 | extern long pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg); | 340 | extern long pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg); |
341 | 341 | ||
342 | /** Functions in pwc-v4l.c */ | 342 | extern const struct v4l2_ioctl_ops pwc_ioctl_ops; |
343 | extern long pwc_video_do_ioctl(struct file *file, unsigned int cmd, void *arg); | ||
344 | 343 | ||
345 | /** pwc-uncompress.c */ | 344 | /** pwc-uncompress.c */ |
346 | /* Expand frame to image, possibly including decompression. Uses read_frame and fill_image */ | 345 | /* Expand frame to image, possibly including decompression. Uses read_frame and fill_image */ |