The patch number 10105 was added via Mauro Carvalho Chehab <mche...@redhat.com> to http://linuxtv.org/hg/v4l-dvb master development tree.
Kernel patches in this development tree may be modified to be backward compatible with older kernels. Compatibility modifications will be removed before inclusion into the mainstream Kernel If anyone has any objections, please let us know by sending a message to: v4l-dvb-maintai...@linuxtv.org ------ From: Mauro Carvalho Chehab <mche...@redhat.com> merge: http://linuxtv.org/hg/~pinchartl/uvcvideo/ Priority: normal Signed-off-by: Mauro Carvalho Chehab <mche...@redhat.com> --- linux/drivers/media/video/uvc/uvc_driver.c | 120 ++++++++++++++------ linux/drivers/media/video/uvc/uvc_queue.c | 23 +++ linux/drivers/media/video/uvc/uvc_v4l2.c | 81 ++++++++----- linux/drivers/media/video/uvc/uvc_video.c | 123 +++++++++++++++++---- linux/drivers/media/video/uvc/uvcvideo.h | 12 +- 5 files changed, 265 insertions(+), 94 deletions(-) diff -r a847ac651a03 -r 69975eb3364c linux/drivers/media/video/uvc/uvc_driver.c --- a/linux/drivers/media/video/uvc/uvc_driver.c Mon Dec 29 17:35:39 2008 -0200 +++ b/linux/drivers/media/video/uvc/uvc_driver.c Mon Dec 29 17:48:19 2008 -0200 @@ -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,45 +609,54 @@ static int uvc_parse_streaming(struct uv } /* 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", + "%d HEADER descriptor not found.\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; - } 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; - } - - 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]; @@ -1147,8 +1156,13 @@ next_descriptor: buffer += buffer[0]; } - /* Check if the optional status endpoint is present. */ - if (alts->desc.bNumEndpoints == 1) { + /* Check if the optional status endpoint is present. Built-in iSight + * webcams have an interrupt endpoint but spit proprietary data that + * don't conform to the UVC status endpoint messages. Don't try to + * handle the interrupt endpoint for those cameras. + */ + if (alts->desc.bNumEndpoints == 1 && + !(dev->quirks & UVC_QUIRK_BUILTIN_ISIGHT)) { struct usb_host_endpoint *ep = &alts->endpoint[0]; struct usb_endpoint_descriptor *desc = &ep->desc; @@ -1253,6 +1267,26 @@ static int uvc_scan_chain_entity(struct 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)); @@ -1363,6 +1397,10 @@ static int uvc_scan_chain(struct uvc_vid 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; @@ -1391,8 +1429,11 @@ static int uvc_scan_chain(struct uvc_vid 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; } @@ -1403,7 +1444,8 @@ static int uvc_scan_chain(struct uvc_vid * 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 @@ -1420,7 +1462,7 @@ static int uvc_register_video(struct uvc 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); @@ -1433,7 +1475,8 @@ static int uvc_register_video(struct uvc 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; @@ -1458,6 +1501,9 @@ static int uvc_register_video(struct uvc } 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 -r a847ac651a03 -r 69975eb3364c linux/drivers/media/video/uvc/uvc_queue.c --- a/linux/drivers/media/video/uvc/uvc_queue.c Mon Dec 29 17:35:39 2008 -0200 +++ b/linux/drivers/media/video/uvc/uvc_queue.c Mon Dec 29 17:48:19 2008 -0200 @@ -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_q 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_qu 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_qu 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_qu 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_ 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_qu } queue->sequence = 0; queue->flags |= UVC_QUEUE_STREAMING; + queue->buf_used = 0; } else { uvc_queue_cancel(queue, 0); INIT_LIST_HEAD(&queue->mainqueue); diff -r a847ac651a03 -r 69975eb3364c linux/drivers/media/video/uvc/uvc_v4l2.c --- a/linux/drivers/media/video/uvc/uvc_v4l2.c Mon Dec 29 17:35:39 2008 -0200 +++ b/linux/drivers/media/video/uvc/uvc_v4l2.c Mon Dec 29 17:48:19 2008 -0200 @@ -110,7 +110,7 @@ static int uvc_v4l2_try_format(struct uv 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 uv 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 uv 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(struc { 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(struc 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(struc { 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(struc 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; } @@ -482,8 +497,12 @@ static int uvc_v4l2_do_ioctl(struct file 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; } @@ -661,7 +680,7 @@ static int uvc_v4l2_do_ioctl(struct file 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; @@ -800,7 +819,7 @@ static int uvc_v4l2_do_ioctl(struct file 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; @@ -826,7 +845,7 @@ static int uvc_v4l2_do_ioctl(struct file 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; @@ -846,7 +865,7 @@ static int uvc_v4l2_do_ioctl(struct file { 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)) @@ -872,7 +891,7 @@ static int uvc_v4l2_do_ioctl(struct file { int *type = arg; - if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + if (*type != video->streaming->type) return -EINVAL; if (!uvc_has_privileges(handle)) @@ -887,7 +906,7 @@ static int uvc_v4l2_do_ioctl(struct file { int *type = arg; - if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + if (*type != video->streaming->type) return -EINVAL; if (!uvc_has_privileges(handle)) diff -r a847ac651a03 -r 69975eb3364c linux/drivers/media/video/uvc/uvc_video.c --- a/linux/drivers/media/video/uvc/uvc_video.c Mon Dec 29 17:35:39 2008 -0200 +++ b/linux/drivers/media/video/uvc/uvc_video.c Mon Dec 29 17:48:19 2008 -0200 @@ -368,7 +368,7 @@ static int uvc_video_decode_start(struct /* Synchronize to the input stream by waiting for the FID bit to be * toggled when the the buffer state is not UVC_BUF_STATE_ACTIVE. - * queue->last_fid is initialized to -1, so the first isochronous + * video->last_fid is initialized to -1, so the first isochronous * frame will always be in sync. * * If the device doesn't toggle the FID bit, invert video->last_fid @@ -395,7 +395,7 @@ static int uvc_video_decode_start(struct * last payload can be lost anyway). We thus must check if the FID has * been toggled. * - * queue->last_fid is initialized to -1, so the first isochronous + * video->last_fid is initialized to -1, so the first isochronous * frame will never trigger an end of frame detection. * * Empty buffers (bytesused == 0) don't trigger end of frame detection @@ -453,6 +453,34 @@ static void uvc_video_decode_end(struct } } +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 */ @@ -512,7 +540,7 @@ static void uvc_video_decode_bulk(struct /* If the URB is the first of its payload, decode and save the * header. */ - if (video->bulk.header_size == 0) { + if (video->bulk.header_size == 0 && !video->bulk.skip_payload) { do { ret = uvc_video_decode_start(video, buf, mem, len); if (ret == -EAGAIN) @@ -522,14 +550,13 @@ static void uvc_video_decode_bulk(struct /* If an error occured skip the rest of the payload. */ if (ret < 0 || buf == NULL) { video->bulk.skip_payload = 1; - return; - } - - video->bulk.header_size = ret; - memcpy(video->bulk.header, mem, video->bulk.header_size); - - mem += ret; - len -= ret; + } else { + memcpy(video->bulk.header, mem, ret); + video->bulk.header_size = ret; + + mem += ret; + len -= ret; + } } /* The buffer queue might have been cancelled while a bulk transfer @@ -558,6 +585,48 @@ static void uvc_video_decode_bulk(struct video->bulk.skip_payload = 0; video->bulk.payload_size = 0; } +} + +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) @@ -761,7 +830,15 @@ static int uvc_init_video_bulk(struct uv 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); @@ -982,12 +1059,22 @@ int uvc_video_init(struct uvc_video_devi 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 -r a847ac651a03 -r 69975eb3364c linux/drivers/media/video/uvc/uvcvideo.h --- a/linux/drivers/media/video/uvc/uvcvideo.h Mon Dec 29 17:35:39 2008 -0200 +++ b/linux/drivers/media/video/uvc/uvcvideo.h Mon Dec 29 17:48:19 2008 -0200 @@ -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 void uvc_delete(struct kref *kref 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); --- Patch is available at: http://linuxtv.org/hg/v4l-dvb/rev/69975eb3364c0c06da9475516103519a089342bb _______________________________________________ linuxtv-commits mailing list linuxtv-commits@linuxtv.org http://www.linuxtv.org/cgi-bin/mailman/listinfo/linuxtv-commits