Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 124573
b: refs/heads/master
c: ff92420
h: refs/heads/master
i:
  124571: 7ca1a31
v: v3
  • Loading branch information
Laurent Pinchart authored and Mauro Carvalho Chehab committed Dec 30, 2008
1 parent 6e1bc2c commit aa7194d
Show file tree
Hide file tree
Showing 6 changed files with 248 additions and 81 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 538e7a004bf960c96c7e9eb836b59989eb5f5b7f
refs/heads/master: ff924203c9e4a5bc218143bc37182851185f4e5f
109 changes: 75 additions & 34 deletions trunk/drivers/media/video/uvc/uvc_driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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];

Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
Expand All @@ -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
Expand All @@ -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);
Expand All @@ -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;
Expand All @@ -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.
*/
Expand Down
23 changes: 18 additions & 5 deletions trunk/drivers/media/video/uvc/uvc_queue.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

/*
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand All @@ -249,14 +250,25 @@ 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);
ret = -ENODEV;
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);
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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);
Expand Down
Loading

0 comments on commit aa7194d

Please sign in to comment.