diff options
author | Laurent Pinchart <laurent.pinchart@skynet.be> | 2008-12-28 20:32:29 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2008-12-30 06:40:32 -0500 |
commit | ff924203c9e4a5bc218143bc37182851185f4e5f (patch) | |
tree | 11ed46e7426ffc00bf016c3b67b26ba26f338c54 /drivers/media/video/uvc/uvc_video.c | |
parent | 538e7a004bf960c96c7e9eb836b59989eb5f5b7f (diff) |
V4L/DVB (10104): uvcvideo: Add support for video output devices
Extend the range of supported UVC devices by allowing video output devices
matching the following structure:
TT_STREAMING -> VC_PROCESSING_UNIT -> VC_EXTENSION_UNIT{0,n} -> OTT_*
Video output devices are reported with the V4L2_CAP_VIDEO_OUTPUT capability
flag and are subject to the same restrictions as video input devices.
Signed-off-by: Laurent Pinchart <laurent.pinchart@skynet.be>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video/uvc/uvc_video.c')
-rw-r--r-- | drivers/media/video/uvc/uvc_video.c | 102 |
1 files changed, 95 insertions, 7 deletions
diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c index 6d0ac3be8191..e7c31995527f 100644 --- a/drivers/media/video/uvc/uvc_video.c +++ b/drivers/media/video/uvc/uvc_video.c | |||
@@ -453,6 +453,34 @@ static void uvc_video_decode_end(struct uvc_video_device *video, | |||
453 | } | 453 | } |
454 | } | 454 | } |
455 | 455 | ||
456 | static int uvc_video_encode_header(struct uvc_video_device *video, | ||
457 | struct uvc_buffer *buf, __u8 *data, int len) | ||
458 | { | ||
459 | data[0] = 2; /* Header length */ | ||
460 | data[1] = UVC_STREAM_EOH | UVC_STREAM_EOF | ||
461 | | (video->last_fid & UVC_STREAM_FID); | ||
462 | return 2; | ||
463 | } | ||
464 | |||
465 | static int uvc_video_encode_data(struct uvc_video_device *video, | ||
466 | struct uvc_buffer *buf, __u8 *data, int len) | ||
467 | { | ||
468 | struct uvc_video_queue *queue = &video->queue; | ||
469 | unsigned int nbytes; | ||
470 | void *mem; | ||
471 | |||
472 | /* Copy video data to the URB buffer. */ | ||
473 | mem = queue->mem + buf->buf.m.offset + queue->buf_used; | ||
474 | nbytes = min((unsigned int)len, buf->buf.bytesused - queue->buf_used); | ||
475 | nbytes = min(video->bulk.max_payload_size - video->bulk.payload_size, | ||
476 | nbytes); | ||
477 | memcpy(data, mem, nbytes); | ||
478 | |||
479 | queue->buf_used += nbytes; | ||
480 | |||
481 | return nbytes; | ||
482 | } | ||
483 | |||
456 | /* ------------------------------------------------------------------------ | 484 | /* ------------------------------------------------------------------------ |
457 | * URB handling | 485 | * URB handling |
458 | */ | 486 | */ |
@@ -559,6 +587,48 @@ static void uvc_video_decode_bulk(struct urb *urb, | |||
559 | } | 587 | } |
560 | } | 588 | } |
561 | 589 | ||
590 | static void uvc_video_encode_bulk(struct urb *urb, | ||
591 | struct uvc_video_device *video, struct uvc_buffer *buf) | ||
592 | { | ||
593 | u8 *mem = urb->transfer_buffer; | ||
594 | int len = video->urb_size, ret; | ||
595 | |||
596 | if (buf == NULL) { | ||
597 | urb->transfer_buffer_length = 0; | ||
598 | return; | ||
599 | } | ||
600 | |||
601 | /* If the URB is the first of its payload, add the header. */ | ||
602 | if (video->bulk.header_size == 0) { | ||
603 | ret = uvc_video_encode_header(video, buf, mem, len); | ||
604 | video->bulk.header_size = ret; | ||
605 | video->bulk.payload_size += ret; | ||
606 | mem += ret; | ||
607 | len -= ret; | ||
608 | } | ||
609 | |||
610 | /* Process video data. */ | ||
611 | ret = uvc_video_encode_data(video, buf, mem, len); | ||
612 | |||
613 | video->bulk.payload_size += ret; | ||
614 | len -= ret; | ||
615 | |||
616 | if (buf->buf.bytesused == video->queue.buf_used || | ||
617 | video->bulk.payload_size == video->bulk.max_payload_size) { | ||
618 | if (buf->buf.bytesused == video->queue.buf_used) { | ||
619 | video->queue.buf_used = 0; | ||
620 | buf->state = UVC_BUF_STATE_DONE; | ||
621 | uvc_queue_next_buffer(&video->queue, buf); | ||
622 | video->last_fid ^= UVC_STREAM_FID; | ||
623 | } | ||
624 | |||
625 | video->bulk.header_size = 0; | ||
626 | video->bulk.payload_size = 0; | ||
627 | } | ||
628 | |||
629 | urb->transfer_buffer_length = video->urb_size - len; | ||
630 | } | ||
631 | |||
562 | static void uvc_video_complete(struct urb *urb) | 632 | static void uvc_video_complete(struct urb *urb) |
563 | { | 633 | { |
564 | struct uvc_video_device *video = urb->context; | 634 | struct uvc_video_device *video = urb->context; |
@@ -756,7 +826,15 @@ static int uvc_init_video_bulk(struct uvc_video_device *video, | |||
756 | if (uvc_alloc_urb_buffers(video, size) < 0) | 826 | if (uvc_alloc_urb_buffers(video, size) < 0) |
757 | return -ENOMEM; | 827 | return -ENOMEM; |
758 | 828 | ||
759 | pipe = usb_rcvbulkpipe(video->dev->udev, ep->desc.bEndpointAddress); | 829 | if (usb_endpoint_dir_in(&ep->desc)) |
830 | pipe = usb_rcvbulkpipe(video->dev->udev, | ||
831 | ep->desc.bEndpointAddress); | ||
832 | else | ||
833 | pipe = usb_sndbulkpipe(video->dev->udev, | ||
834 | ep->desc.bEndpointAddress); | ||
835 | |||
836 | if (video->streaming->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) | ||
837 | size = 0; | ||
760 | 838 | ||
761 | for (i = 0; i < UVC_URBS; ++i) { | 839 | for (i = 0; i < UVC_URBS; ++i) { |
762 | urb = usb_alloc_urb(0, gfp_flags); | 840 | urb = usb_alloc_urb(0, gfp_flags); |
@@ -977,12 +1055,22 @@ int uvc_video_init(struct uvc_video_device *video) | |||
977 | atomic_set(&video->active, 0); | 1055 | atomic_set(&video->active, 0); |
978 | 1056 | ||
979 | /* Select the video decoding function */ | 1057 | /* Select the video decoding function */ |
980 | if (video->dev->quirks & UVC_QUIRK_BUILTIN_ISIGHT) | 1058 | if (video->streaming->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { |
981 | video->decode = uvc_video_decode_isight; | 1059 | if (video->dev->quirks & UVC_QUIRK_BUILTIN_ISIGHT) |
982 | else if (video->streaming->intf->num_altsetting > 1) | 1060 | video->decode = uvc_video_decode_isight; |
983 | video->decode = uvc_video_decode_isoc; | 1061 | else if (video->streaming->intf->num_altsetting > 1) |
984 | else | 1062 | video->decode = uvc_video_decode_isoc; |
985 | video->decode = uvc_video_decode_bulk; | 1063 | else |
1064 | video->decode = uvc_video_decode_bulk; | ||
1065 | } else { | ||
1066 | if (video->streaming->intf->num_altsetting == 1) | ||
1067 | video->decode = uvc_video_encode_bulk; | ||
1068 | else { | ||
1069 | uvc_printk(KERN_INFO, "Isochronous endpoints are not " | ||
1070 | "supported for video output devices.\n"); | ||
1071 | return -EINVAL; | ||
1072 | } | ||
1073 | } | ||
986 | 1074 | ||
987 | return 0; | 1075 | return 0; |
988 | } | 1076 | } |