diff options
author | Laurent Pinchart <laurent.pinchart@skynet.be> | 2008-12-29 02:32:29 +0100 |
---|---|---|
committer | Laurent Pinchart <laurent.pinchart@skynet.be> | 2008-12-29 02:32:29 +0100 |
commit | 081fc36b5da81564c839d81f79dbe2e75b05c2b7 (patch) | |
tree | 74238628611dbe58f5fbce8707e8e9d59a1cd2c8 /linux/drivers/media/video/uvc/uvc_video.c | |
parent | 0a2cf3a87146a65721f0bd83e4759c7bfec8fdfe (diff) | |
download | mediapointer-dvb-s2-081fc36b5da81564c839d81f79dbe2e75b05c2b7.tar.gz mediapointer-dvb-s2-081fc36b5da81564c839d81f79dbe2e75b05c2b7.tar.bz2 |
uvcvideo: Add support for video output devices
From: Laurent Pinchart <laurent.pinchart@skynet.be>
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.
Priority: normal
Signed-off-by: Laurent Pinchart <laurent.pinchart@skynet.be>
Diffstat (limited to 'linux/drivers/media/video/uvc/uvc_video.c')
-rw-r--r-- | linux/drivers/media/video/uvc/uvc_video.c | 102 |
1 files changed, 95 insertions, 7 deletions
diff --git a/linux/drivers/media/video/uvc/uvc_video.c b/linux/drivers/media/video/uvc/uvc_video.c index 3cb91444e..e6f7c3178 100644 --- a/linux/drivers/media/video/uvc/uvc_video.c +++ b/linux/drivers/media/video/uvc/uvc_video.c @@ -453,6 +453,34 @@ static void uvc_video_decode_end(struct uvc_video_device *video, } } +static int uvc_video_encode_header(struct uvc_video_device *video, + struct uvc_buffer *buf, __u8 *data, int len) +{ + data[0] = 2; /* Header length */ + data[1] = UVC_STREAM_EOH | UVC_STREAM_EOF + | (video->last_fid & UVC_STREAM_FID); + return 2; +} + +static int uvc_video_encode_data(struct uvc_video_device *video, + struct uvc_buffer *buf, __u8 *data, int len) +{ + struct uvc_video_queue *queue = &video->queue; + unsigned int nbytes; + void *mem; + + /* Copy video data to the URB buffer. */ + mem = queue->mem + buf->buf.m.offset + queue->buf_used; + nbytes = min((unsigned int)len, buf->buf.bytesused - queue->buf_used); + nbytes = min(video->bulk.max_payload_size - video->bulk.payload_size, + nbytes); + memcpy(data, mem, nbytes); + + queue->buf_used += nbytes; + + return nbytes; +} + /* ------------------------------------------------------------------------ * URB handling */ @@ -559,6 +587,48 @@ static void uvc_video_decode_bulk(struct urb *urb, } } +static void uvc_video_encode_bulk(struct urb *urb, + struct uvc_video_device *video, struct uvc_buffer *buf) +{ + u8 *mem = urb->transfer_buffer; + int len = video->urb_size, ret; + + if (buf == NULL) { + urb->transfer_buffer_length = 0; + return; + } + + /* If the URB is the first of its payload, add the header. */ + if (video->bulk.header_size == 0) { + ret = uvc_video_encode_header(video, buf, mem, len); + video->bulk.header_size = ret; + video->bulk.payload_size += ret; + mem += ret; + len -= ret; + } + + /* Process video data. */ + ret = uvc_video_encode_data(video, buf, mem, len); + + video->bulk.payload_size += ret; + len -= ret; + + if (buf->buf.bytesused == video->queue.buf_used || + video->bulk.payload_size == video->bulk.max_payload_size) { + if (buf->buf.bytesused == video->queue.buf_used) { + video->queue.buf_used = 0; + buf->state = UVC_BUF_STATE_DONE; + uvc_queue_next_buffer(&video->queue, buf); + video->last_fid ^= UVC_STREAM_FID; + } + + video->bulk.header_size = 0; + video->bulk.payload_size = 0; + } + + urb->transfer_buffer_length = video->urb_size - len; +} + #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) static void uvc_video_complete(struct urb *urb, struct pt_regs *regs) #else @@ -760,7 +830,15 @@ static int uvc_init_video_bulk(struct uvc_video_device *video, if (uvc_alloc_urb_buffers(video, size) < 0) return -ENOMEM; - pipe = usb_rcvbulkpipe(video->dev->udev, ep->desc.bEndpointAddress); + if (usb_endpoint_dir_in(&ep->desc)) + pipe = usb_rcvbulkpipe(video->dev->udev, + ep->desc.bEndpointAddress); + else + pipe = usb_sndbulkpipe(video->dev->udev, + ep->desc.bEndpointAddress); + + if (video->streaming->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) + size = 0; for (i = 0; i < UVC_URBS; ++i) { urb = usb_alloc_urb(0, gfp_flags); @@ -981,12 +1059,22 @@ int uvc_video_init(struct uvc_video_device *video) atomic_set(&video->active, 0); /* Select the video decoding function */ - if (video->dev->quirks & UVC_QUIRK_BUILTIN_ISIGHT) - video->decode = uvc_video_decode_isight; - else if (video->streaming->intf->num_altsetting > 1) - video->decode = uvc_video_decode_isoc; - else - video->decode = uvc_video_decode_bulk; + if (video->streaming->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + if (video->dev->quirks & UVC_QUIRK_BUILTIN_ISIGHT) + video->decode = uvc_video_decode_isight; + else if (video->streaming->intf->num_altsetting > 1) + video->decode = uvc_video_decode_isoc; + else + video->decode = uvc_video_decode_bulk; + } else { + if (video->streaming->intf->num_altsetting == 1) + video->decode = uvc_video_encode_bulk; + else { + uvc_printk(KERN_INFO, "Isochronous endpoints are not " + "supported for video output devices.\n"); + return -EINVAL; + } + } return 0; } |