diff options
author | Laurent Pinchart <laurent.pinchart@skynet.be> | 2008-12-28 22:32:29 -0300 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2008-12-30 09:40:32 -0200 |
commit | ff924203c9e4a5bc218143bc37182851185f4e5f (patch) | |
tree | 11ed46e7426ffc00bf016c3b67b26ba26f338c54 | |
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>
-rw-r--r-- | drivers/media/video/uvc/uvc_driver.c | 109 | ||||
-rw-r--r-- | drivers/media/video/uvc/uvc_queue.c | 23 | ||||
-rw-r--r-- | drivers/media/video/uvc/uvc_v4l2.c | 81 | ||||
-rw-r--r-- | drivers/media/video/uvc/uvc_video.c | 102 | ||||
-rw-r--r-- | drivers/media/video/uvc/uvcvideo.h | 12 |
5 files changed, 247 insertions, 80 deletions
diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c index 18a61928f4f..89d8bd10a85 100644 --- a/drivers/media/video/uvc/uvc_driver.c +++ b/drivers/media/video/uvc/uvc_driver.c @@ -12,8 +12,8 @@ */ /* - * This driver aims to support video input devices compliant with the 'USB - * Video Class' specification. + * This driver aims to support video input and ouput devices compliant with the + * 'USB Video Class' specification. * * The driver doesn't support the deprecated v4l1 interface. It implements the * mmap capture method only, and doesn't do any image format conversion in @@ -609,46 +609,55 @@ static int uvc_parse_streaming(struct uvc_device *dev, } /* Parse the header descriptor. */ - if (buffer[2] == VS_OUTPUT_HEADER) { + switch (buffer[2]) { + case VS_OUTPUT_HEADER: + streaming->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; + size = 9; + break; + + case VS_INPUT_HEADER: + streaming->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + size = 13; + break; + + default: uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming interface " - "%d OUTPUT HEADER descriptor is not supported.\n", - dev->udev->devnum, alts->desc.bInterfaceNumber); + "%d HEADER descriptor not found.\n", dev->udev->devnum, + alts->desc.bInterfaceNumber); goto error; - } else if (buffer[2] == VS_INPUT_HEADER) { - p = buflen >= 5 ? buffer[3] : 0; - n = buflen >= 12 ? buffer[12] : 0; + } - if (buflen < 13 + p*n || buffer[2] != VS_INPUT_HEADER) { - uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming " - "interface %d INPUT HEADER descriptor is " - "invalid.\n", dev->udev->devnum, - alts->desc.bInterfaceNumber); - goto error; - } + p = buflen >= 4 ? buffer[3] : 0; + n = buflen >= size ? buffer[size-1] : 0; + + if (buflen < size + p*n) { + uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming " + "interface %d HEADER descriptor is invalid.\n", + dev->udev->devnum, alts->desc.bInterfaceNumber); + goto error; + } - streaming->header.bNumFormats = p; - streaming->header.bEndpointAddress = buffer[6]; + streaming->header.bNumFormats = p; + streaming->header.bEndpointAddress = buffer[6]; + if (buffer[2] == VS_INPUT_HEADER) { streaming->header.bmInfo = buffer[7]; streaming->header.bTerminalLink = buffer[8]; streaming->header.bStillCaptureMethod = buffer[9]; streaming->header.bTriggerSupport = buffer[10]; streaming->header.bTriggerUsage = buffer[11]; - streaming->header.bControlSize = n; - - streaming->header.bmaControls = kmalloc(p*n, GFP_KERNEL); - if (streaming->header.bmaControls == NULL) { - ret = -ENOMEM; - goto error; - } - - memcpy(streaming->header.bmaControls, &buffer[13], p*n); } else { - uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming interface " - "%d HEADER descriptor not found.\n", dev->udev->devnum, - alts->desc.bInterfaceNumber); + streaming->header.bTerminalLink = buffer[7]; + } + streaming->header.bControlSize = n; + + streaming->header.bmaControls = kmalloc(p*n, GFP_KERNEL); + if (streaming->header.bmaControls == NULL) { + ret = -ENOMEM; goto error; } + memcpy(streaming->header.bmaControls, &buffer[size], p*n); + buflen -= buffer[0]; buffer += buffer[0]; @@ -1258,6 +1267,26 @@ static int uvc_scan_chain_entity(struct uvc_video_device *video, list_add_tail(&entity->chain, &video->iterms); break; + case TT_STREAMING: + if (uvc_trace_param & UVC_TRACE_PROBE) + printk(" <- IT %d\n", entity->id); + + if (!UVC_ENTITY_IS_ITERM(entity)) { + uvc_trace(UVC_TRACE_DESCR, "Unsupported input " + "terminal %u.\n", entity->id); + return -1; + } + + if (video->sterm != NULL) { + uvc_trace(UVC_TRACE_DESCR, "Found multiple streaming " + "entities in chain.\n"); + return -1; + } + + list_add_tail(&entity->chain, &video->iterms); + video->sterm = entity; + break; + default: uvc_trace(UVC_TRACE_DESCR, "Unsupported entity type " "0x%04x found in chain.\n", UVC_ENTITY_TYPE(entity)); @@ -1368,6 +1397,10 @@ static int uvc_scan_chain(struct uvc_video_device *video) entity = video->oterm; uvc_trace(UVC_TRACE_PROBE, "Scanning UVC chain: OT %d", entity->id); + + if (UVC_ENTITY_TYPE(entity) == TT_STREAMING) + video->sterm = entity; + id = entity->output.bSourceID; while (id != 0) { prev = entity; @@ -1396,8 +1429,11 @@ static int uvc_scan_chain(struct uvc_video_device *video) return id; } - /* Initialize the video buffers queue. */ - uvc_queue_init(&video->queue); + if (video->sterm == NULL) { + uvc_trace(UVC_TRACE_DESCR, "No streaming entity found in " + "chain.\n"); + return -1; + } return 0; } @@ -1408,7 +1444,8 @@ static int uvc_scan_chain(struct uvc_video_device *video) * The driver currently supports a single video device per control interface * only. The terminal and units must match the following structure: * - * ITT_CAMERA -> VC_PROCESSING_UNIT -> VC_EXTENSION_UNIT{0,n} -> TT_STREAMING + * ITT_* -> VC_PROCESSING_UNIT -> VC_EXTENSION_UNIT{0,n} -> TT_STREAMING + * TT_STREAMING -> VC_PROCESSING_UNIT -> VC_EXTENSION_UNIT{0,n} -> OTT_* * * The Extension Units, if present, must have a single input pin. The * Processing Unit and Extension Units can be in any order. Additional @@ -1425,7 +1462,7 @@ static int uvc_register_video(struct uvc_device *dev) list_for_each_entry(term, &dev->entities, list) { struct uvc_streaming *streaming; - if (UVC_ENTITY_TYPE(term) != TT_STREAMING) + if (!UVC_ENTITY_IS_TERM(term) || !UVC_ENTITY_IS_OTERM(term)) continue; memset(&dev->video, 0, sizeof dev->video); @@ -1438,7 +1475,8 @@ static int uvc_register_video(struct uvc_device *dev) continue; list_for_each_entry(streaming, &dev->streaming, list) { - if (streaming->header.bTerminalLink == term->id) { + if (streaming->header.bTerminalLink == + dev->video.sterm->id) { dev->video.streaming = streaming; found = 1; break; @@ -1464,6 +1502,9 @@ static int uvc_register_video(struct uvc_device *dev) printk(" -> %d).\n", dev->video.oterm->id); } + /* Initialize the video buffers queue. */ + uvc_queue_init(&dev->video.queue, dev->video.streaming->type); + /* Initialize the streaming interface with default streaming * parameters. */ diff --git a/drivers/media/video/uvc/uvc_queue.c b/drivers/media/video/uvc/uvc_queue.c index 5646a6a3293..42546342e97 100644 --- a/drivers/media/video/uvc/uvc_queue.c +++ b/drivers/media/video/uvc/uvc_queue.c @@ -79,12 +79,13 @@ * */ -void uvc_queue_init(struct uvc_video_queue *queue) +void uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type) { mutex_init(&queue->mutex); spin_lock_init(&queue->irqlock); INIT_LIST_HEAD(&queue->mainqueue); INIT_LIST_HEAD(&queue->irqqueue); + queue->type = type; } /* @@ -132,7 +133,7 @@ int uvc_alloc_buffers(struct uvc_video_queue *queue, unsigned int nbuffers, queue->buffer[i].buf.index = i; queue->buffer[i].buf.m.offset = i * bufsize; queue->buffer[i].buf.length = buflength; - queue->buffer[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + queue->buffer[i].buf.type = queue->type; queue->buffer[i].buf.sequence = 0; queue->buffer[i].buf.field = V4L2_FIELD_NONE; queue->buffer[i].buf.memory = V4L2_MEMORY_MMAP; @@ -226,7 +227,7 @@ int uvc_queue_buffer(struct uvc_video_queue *queue, uvc_trace(UVC_TRACE_CAPTURE, "Queuing buffer %u.\n", v4l2_buf->index); - if (v4l2_buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || + if (v4l2_buf->type != queue->type || v4l2_buf->memory != V4L2_MEMORY_MMAP) { uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer type (%u) " "and/or memory (%u).\n", v4l2_buf->type, @@ -249,6 +250,13 @@ int uvc_queue_buffer(struct uvc_video_queue *queue, goto done; } + if (v4l2_buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT && + v4l2_buf->bytesused > buf->buf.length) { + uvc_trace(UVC_TRACE_CAPTURE, "[E] Bytes used out of bounds.\n"); + ret = -EINVAL; + goto done; + } + spin_lock_irqsave(&queue->irqlock, flags); if (queue->flags & UVC_QUEUE_DISCONNECTED) { spin_unlock_irqrestore(&queue->irqlock, flags); @@ -256,7 +264,11 @@ int uvc_queue_buffer(struct uvc_video_queue *queue, goto done; } buf->state = UVC_BUF_STATE_QUEUED; - buf->buf.bytesused = 0; + if (v4l2_buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + buf->buf.bytesused = 0; + else + buf->buf.bytesused = v4l2_buf->bytesused; + list_add_tail(&buf->stream, &queue->mainqueue); list_add_tail(&buf->queue, &queue->irqqueue); spin_unlock_irqrestore(&queue->irqlock, flags); @@ -289,7 +301,7 @@ int uvc_dequeue_buffer(struct uvc_video_queue *queue, struct uvc_buffer *buf; int ret = 0; - if (v4l2_buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || + if (v4l2_buf->type != queue->type || v4l2_buf->memory != V4L2_MEMORY_MMAP) { uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer type (%u) " "and/or memory (%u).\n", v4l2_buf->type, @@ -397,6 +409,7 @@ int uvc_queue_enable(struct uvc_video_queue *queue, int enable) } queue->sequence = 0; queue->flags |= UVC_QUEUE_STREAMING; + queue->buf_used = 0; } else { uvc_queue_cancel(queue, 0); INIT_LIST_HEAD(&queue->mainqueue); diff --git a/drivers/media/video/uvc/uvc_v4l2.c b/drivers/media/video/uvc/uvc_v4l2.c index 2e1fd1b2a61..afcc6934559 100644 --- a/drivers/media/video/uvc/uvc_v4l2.c +++ b/drivers/media/video/uvc/uvc_v4l2.c @@ -110,7 +110,7 @@ static int uvc_v4l2_try_format(struct uvc_video_device *video, int ret = 0; __u8 *fcc; - if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + if (fmt->type != video->streaming->type) return -EINVAL; fcc = (__u8 *)&fmt->fmt.pix.pixelformat; @@ -216,7 +216,7 @@ static int uvc_v4l2_get_format(struct uvc_video_device *video, struct uvc_format *format = video->streaming->cur_format; struct uvc_frame *frame = video->streaming->cur_frame; - if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + if (fmt->type != video->streaming->type) return -EINVAL; if (format == NULL || frame == NULL) @@ -242,7 +242,7 @@ static int uvc_v4l2_set_format(struct uvc_video_device *video, struct uvc_frame *frame; int ret; - if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + if (fmt->type != video->streaming->type) return -EINVAL; if (uvc_queue_streaming(&video->queue)) @@ -264,7 +264,7 @@ static int uvc_v4l2_get_streamparm(struct uvc_video_device *video, { uint32_t numerator, denominator; - if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + if (parm->type != video->streaming->type) return -EINVAL; numerator = video->streaming->ctrl.dwFrameInterval; @@ -272,13 +272,21 @@ static int uvc_v4l2_get_streamparm(struct uvc_video_device *video, uvc_simplify_fraction(&numerator, &denominator, 8, 333); memset(parm, 0, sizeof *parm); - parm->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; - parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; - parm->parm.capture.capturemode = 0; - parm->parm.capture.timeperframe.numerator = numerator; - parm->parm.capture.timeperframe.denominator = denominator; - parm->parm.capture.extendedmode = 0; - parm->parm.capture.readbuffers = 0; + parm->type = video->streaming->type; + + if (video->streaming->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; + parm->parm.capture.capturemode = 0; + parm->parm.capture.timeperframe.numerator = numerator; + parm->parm.capture.timeperframe.denominator = denominator; + parm->parm.capture.extendedmode = 0; + parm->parm.capture.readbuffers = 0; + } else { + parm->parm.output.capability = V4L2_CAP_TIMEPERFRAME; + parm->parm.output.outputmode = 0; + parm->parm.output.timeperframe.numerator = numerator; + parm->parm.output.timeperframe.denominator = denominator; + } return 0; } @@ -288,24 +296,27 @@ static int uvc_v4l2_set_streamparm(struct uvc_video_device *video, { struct uvc_frame *frame = video->streaming->cur_frame; struct uvc_streaming_control probe; + struct v4l2_fract timeperframe; uint32_t interval; int ret; - if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + if (parm->type != video->streaming->type) return -EINVAL; if (uvc_queue_streaming(&video->queue)) return -EBUSY; + if (parm->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + timeperframe = parm->parm.capture.timeperframe; + else + timeperframe = parm->parm.output.timeperframe; + memcpy(&probe, &video->streaming->ctrl, sizeof probe); - interval = uvc_fraction_to_interval( - parm->parm.capture.timeperframe.numerator, - parm->parm.capture.timeperframe.denominator); + interval = uvc_fraction_to_interval(timeperframe.numerator, + timeperframe.denominator); uvc_trace(UVC_TRACE_FORMAT, "Setting frame interval to %u/%u (%u).\n", - parm->parm.capture.timeperframe.numerator, - parm->parm.capture.timeperframe.denominator, - interval); + timeperframe.numerator, timeperframe.denominator, interval); probe.dwFrameInterval = uvc_try_frame_interval(frame, interval); /* Probe the device with the new settings. */ @@ -315,11 +326,15 @@ static int uvc_v4l2_set_streamparm(struct uvc_video_device *video, memcpy(&video->streaming->ctrl, &probe, sizeof probe); /* Return the actual frame period. */ - parm->parm.capture.timeperframe.numerator = probe.dwFrameInterval; - parm->parm.capture.timeperframe.denominator = 10000000; - uvc_simplify_fraction(&parm->parm.capture.timeperframe.numerator, - &parm->parm.capture.timeperframe.denominator, - 8, 333); + timeperframe.numerator = probe.dwFrameInterval; + timeperframe.denominator = 10000000; + uvc_simplify_fraction(&timeperframe.numerator, + &timeperframe.denominator, 8, 333); + + if (parm->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + parm->parm.capture.timeperframe = timeperframe; + else + parm->parm.output.timeperframe = timeperframe; return 0; } @@ -476,8 +491,12 @@ static int uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) strncpy(cap->bus_info, video->dev->udev->bus->bus_name, sizeof cap->bus_info); cap->version = DRIVER_VERSION_NUMBER; - cap->capabilities = V4L2_CAP_VIDEO_CAPTURE - | V4L2_CAP_STREAMING; + if (video->streaming->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + cap->capabilities = V4L2_CAP_VIDEO_CAPTURE + | V4L2_CAP_STREAMING; + else + cap->capabilities = V4L2_CAP_VIDEO_OUTPUT + | V4L2_CAP_STREAMING; break; } @@ -655,7 +674,7 @@ static int uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) struct v4l2_fmtdesc *fmt = arg; struct uvc_format *format; - if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || + if (fmt->type != video->streaming->type || fmt->index >= video->streaming->nformats) return -EINVAL; @@ -794,7 +813,7 @@ static int uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) struct v4l2_cropcap *ccap = arg; struct uvc_frame *frame = video->streaming->cur_frame; - if (ccap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + if (ccap->type != video->streaming->type) return -EINVAL; ccap->bounds.left = 0; @@ -820,7 +839,7 @@ static int uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) unsigned int bufsize = video->streaming->ctrl.dwMaxVideoFrameSize; - if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || + if (rb->type != video->streaming->type || rb->memory != V4L2_MEMORY_MMAP) return -EINVAL; @@ -840,7 +859,7 @@ static int uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) { struct v4l2_buffer *buf = arg; - if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + if (buf->type != video->streaming->type) return -EINVAL; if (!uvc_has_privileges(handle)) @@ -866,7 +885,7 @@ static int uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) { int *type = arg; - if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + if (*type != video->streaming->type) return -EINVAL; if (!uvc_has_privileges(handle)) @@ -881,7 +900,7 @@ static int uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) { int *type = arg; - if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + if (*type != video->streaming->type) return -EINVAL; if (!uvc_has_privileges(handle)) diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c index 6d0ac3be819..e7c31995527 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, } } +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; +} + static void uvc_video_complete(struct urb *urb) { struct uvc_video_device *video = urb->context; @@ -756,7 +826,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); @@ -977,12 +1055,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; } diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h index 2a5bdacbaf2..731cf795165 100644 --- a/drivers/media/video/uvc/uvcvideo.h +++ b/drivers/media/video/uvc/uvcvideo.h @@ -529,6 +529,7 @@ struct uvc_streaming { __u16 maxpsize; struct uvc_streaming_header header; + enum v4l2_buf_type type; unsigned int nformats; struct uvc_format *format; @@ -564,12 +565,15 @@ struct uvc_buffer { #define UVC_QUEUE_DROP_INCOMPLETE (1 << 2) struct uvc_video_queue { + enum v4l2_buf_type type; + void *mem; unsigned int flags; __u32 sequence; unsigned int count; unsigned int buf_size; + unsigned int buf_used; struct uvc_buffer buffer[UVC_MAX_VIDEO_BUFFERS]; struct mutex mutex; /* protects buffers and mainqueue */ spinlock_t irqlock; /* protects irqqueue */ @@ -584,8 +588,9 @@ struct uvc_video_device { atomic_t active; unsigned int frozen : 1; - struct list_head iterms; - struct uvc_entity *oterm; + struct list_head iterms; /* Input terminals */ + struct uvc_entity *oterm; /* Output terminal */ + struct uvc_entity *sterm; /* USB streaming terminal */ struct uvc_entity *processing; struct uvc_entity *selector; struct list_head extensions; @@ -726,7 +731,8 @@ extern struct uvc_driver uvc_driver; extern void uvc_delete(struct kref *kref); /* Video buffers queue management. */ -extern void uvc_queue_init(struct uvc_video_queue *queue); +extern void uvc_queue_init(struct uvc_video_queue *queue, + enum v4l2_buf_type type); extern int uvc_alloc_buffers(struct uvc_video_queue *queue, unsigned int nbuffers, unsigned int buflength); extern int uvc_free_buffers(struct uvc_video_queue *queue); |