Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ff924203 authored by Laurent Pinchart's avatar Laurent Pinchart Committed by Mauro Carvalho Chehab
Browse files

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: default avatarLaurent Pinchart <laurent.pinchart@skynet.be>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 538e7a00
Loading
Loading
Loading
Loading
+75 −34
Original line number Diff line number Diff line
@@ -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,30 +609,45 @@ 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;
	}

	p = buflen >= 4 ? buffer[3] : 0;
	n = buflen >= size ? buffer[size-1] : 0;

		if (buflen < 13 + p*n || buffer[2] != VS_INPUT_HEADER) {
	if (buflen < size + p*n) {
		uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming "
				"interface %d INPUT HEADER descriptor is "
				"invalid.\n", dev->udev->devnum,
				alts->desc.bInterfaceNumber);
			"interface %d HEADER descriptor is invalid.\n",
			dev->udev->devnum, alts->desc.bInterfaceNumber);
		goto error;
	}

	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];
	} else {
		streaming->header.bTerminalLink = buffer[7];
	}
	streaming->header.bControlSize = n;

	streaming->header.bmaControls = kmalloc(p*n, GFP_KERNEL);
@@ -641,13 +656,7 @@ static int uvc_parse_streaming(struct uvc_device *dev,
		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);
		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.
	 */
+18 −5
Original line number Diff line number Diff line
@@ -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;
	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);
+50 −31
Original line number Diff line number Diff line
@@ -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->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;
		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))
+95 −7
Original line number Diff line number Diff line
@@ -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->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;
}
+9 −3
Original line number Diff line number Diff line
@@ -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);