diff options
author | Laurent Pinchart <laurent.pinchart@skynet.be> | 2008-12-28 20:32:29 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2008-12-30 06:40:32 -0500 |
commit | ff924203c9e4a5bc218143bc37182851185f4e5f (patch) | |
tree | 11ed46e7426ffc00bf016c3b67b26ba26f338c54 /drivers/media | |
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>
Diffstat (limited to 'drivers/media')
-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 18a61928f4f6..89d8bd10a852 100644 --- a/drivers/media/video/uvc/uvc_driver.c +++ b/drivers/media/video/uvc/uvc_driver.c | |||
@@ -12,8 +12,8 @@ | |||
12 | */ | 12 | */ |
13 | 13 | ||
14 | /* | 14 | /* |
15 | * This driver aims to support video input devices compliant with the 'USB | 15 | * This driver aims to support video input and ouput devices compliant with the |
16 | * Video Class' specification. | 16 | * 'USB Video Class' specification. |
17 | * | 17 | * |
18 | * The driver doesn't support the deprecated v4l1 interface. It implements the | 18 | * The driver doesn't support the deprecated v4l1 interface. It implements the |
19 | * mmap capture method only, and doesn't do any image format conversion in | 19 | * 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, | |||
609 | } | 609 | } |
610 | 610 | ||
611 | /* Parse the header descriptor. */ | 611 | /* Parse the header descriptor. */ |
612 | if (buffer[2] == VS_OUTPUT_HEADER) { | 612 | switch (buffer[2]) { |
613 | case VS_OUTPUT_HEADER: | ||
614 | streaming->type = V4L2_BUF_TYPE_VIDEO_OUTPUT; | ||
615 | size = 9; | ||
616 | break; | ||
617 | |||
618 | case VS_INPUT_HEADER: | ||
619 | streaming->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | ||
620 | size = 13; | ||
621 | break; | ||
622 | |||
623 | default: | ||
613 | uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming interface " | 624 | uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming interface " |
614 | "%d OUTPUT HEADER descriptor is not supported.\n", | 625 | "%d HEADER descriptor not found.\n", dev->udev->devnum, |
615 | dev->udev->devnum, alts->desc.bInterfaceNumber); | 626 | alts->desc.bInterfaceNumber); |
616 | goto error; | 627 | goto error; |
617 | } else if (buffer[2] == VS_INPUT_HEADER) { | 628 | } |
618 | p = buflen >= 5 ? buffer[3] : 0; | ||
619 | n = buflen >= 12 ? buffer[12] : 0; | ||
620 | 629 | ||
621 | if (buflen < 13 + p*n || buffer[2] != VS_INPUT_HEADER) { | 630 | p = buflen >= 4 ? buffer[3] : 0; |
622 | uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming " | 631 | n = buflen >= size ? buffer[size-1] : 0; |
623 | "interface %d INPUT HEADER descriptor is " | 632 | |
624 | "invalid.\n", dev->udev->devnum, | 633 | if (buflen < size + p*n) { |
625 | alts->desc.bInterfaceNumber); | 634 | uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming " |
626 | goto error; | 635 | "interface %d HEADER descriptor is invalid.\n", |
627 | } | 636 | dev->udev->devnum, alts->desc.bInterfaceNumber); |
637 | goto error; | ||
638 | } | ||
628 | 639 | ||
629 | streaming->header.bNumFormats = p; | 640 | streaming->header.bNumFormats = p; |
630 | streaming->header.bEndpointAddress = buffer[6]; | 641 | streaming->header.bEndpointAddress = buffer[6]; |
642 | if (buffer[2] == VS_INPUT_HEADER) { | ||
631 | streaming->header.bmInfo = buffer[7]; | 643 | streaming->header.bmInfo = buffer[7]; |
632 | streaming->header.bTerminalLink = buffer[8]; | 644 | streaming->header.bTerminalLink = buffer[8]; |
633 | streaming->header.bStillCaptureMethod = buffer[9]; | 645 | streaming->header.bStillCaptureMethod = buffer[9]; |
634 | streaming->header.bTriggerSupport = buffer[10]; | 646 | streaming->header.bTriggerSupport = buffer[10]; |
635 | streaming->header.bTriggerUsage = buffer[11]; | 647 | streaming->header.bTriggerUsage = buffer[11]; |
636 | streaming->header.bControlSize = n; | ||
637 | |||
638 | streaming->header.bmaControls = kmalloc(p*n, GFP_KERNEL); | ||
639 | if (streaming->header.bmaControls == NULL) { | ||
640 | ret = -ENOMEM; | ||
641 | goto error; | ||
642 | } | ||
643 | |||
644 | memcpy(streaming->header.bmaControls, &buffer[13], p*n); | ||
645 | } else { | 648 | } else { |
646 | uvc_trace(UVC_TRACE_DESCR, "device %d videostreaming interface " | 649 | streaming->header.bTerminalLink = buffer[7]; |
647 | "%d HEADER descriptor not found.\n", dev->udev->devnum, | 650 | } |
648 | alts->desc.bInterfaceNumber); | 651 | streaming->header.bControlSize = n; |
652 | |||
653 | streaming->header.bmaControls = kmalloc(p*n, GFP_KERNEL); | ||
654 | if (streaming->header.bmaControls == NULL) { | ||
655 | ret = -ENOMEM; | ||
649 | goto error; | 656 | goto error; |
650 | } | 657 | } |
651 | 658 | ||
659 | memcpy(streaming->header.bmaControls, &buffer[size], p*n); | ||
660 | |||
652 | buflen -= buffer[0]; | 661 | buflen -= buffer[0]; |
653 | buffer += buffer[0]; | 662 | buffer += buffer[0]; |
654 | 663 | ||
@@ -1258,6 +1267,26 @@ static int uvc_scan_chain_entity(struct uvc_video_device *video, | |||
1258 | list_add_tail(&entity->chain, &video->iterms); | 1267 | list_add_tail(&entity->chain, &video->iterms); |
1259 | break; | 1268 | break; |
1260 | 1269 | ||
1270 | case TT_STREAMING: | ||
1271 | if (uvc_trace_param & UVC_TRACE_PROBE) | ||
1272 | printk(" <- IT %d\n", entity->id); | ||
1273 | |||
1274 | if (!UVC_ENTITY_IS_ITERM(entity)) { | ||
1275 | uvc_trace(UVC_TRACE_DESCR, "Unsupported input " | ||
1276 | "terminal %u.\n", entity->id); | ||
1277 | return -1; | ||
1278 | } | ||
1279 | |||
1280 | if (video->sterm != NULL) { | ||
1281 | uvc_trace(UVC_TRACE_DESCR, "Found multiple streaming " | ||
1282 | "entities in chain.\n"); | ||
1283 | return -1; | ||
1284 | } | ||
1285 | |||
1286 | list_add_tail(&entity->chain, &video->iterms); | ||
1287 | video->sterm = entity; | ||
1288 | break; | ||
1289 | |||
1261 | default: | 1290 | default: |
1262 | uvc_trace(UVC_TRACE_DESCR, "Unsupported entity type " | 1291 | uvc_trace(UVC_TRACE_DESCR, "Unsupported entity type " |
1263 | "0x%04x found in chain.\n", UVC_ENTITY_TYPE(entity)); | 1292 | "0x%04x found in chain.\n", UVC_ENTITY_TYPE(entity)); |
@@ -1368,6 +1397,10 @@ static int uvc_scan_chain(struct uvc_video_device *video) | |||
1368 | 1397 | ||
1369 | entity = video->oterm; | 1398 | entity = video->oterm; |
1370 | uvc_trace(UVC_TRACE_PROBE, "Scanning UVC chain: OT %d", entity->id); | 1399 | uvc_trace(UVC_TRACE_PROBE, "Scanning UVC chain: OT %d", entity->id); |
1400 | |||
1401 | if (UVC_ENTITY_TYPE(entity) == TT_STREAMING) | ||
1402 | video->sterm = entity; | ||
1403 | |||
1371 | id = entity->output.bSourceID; | 1404 | id = entity->output.bSourceID; |
1372 | while (id != 0) { | 1405 | while (id != 0) { |
1373 | prev = entity; | 1406 | prev = entity; |
@@ -1396,8 +1429,11 @@ static int uvc_scan_chain(struct uvc_video_device *video) | |||
1396 | return id; | 1429 | return id; |
1397 | } | 1430 | } |
1398 | 1431 | ||
1399 | /* Initialize the video buffers queue. */ | 1432 | if (video->sterm == NULL) { |
1400 | uvc_queue_init(&video->queue); | 1433 | uvc_trace(UVC_TRACE_DESCR, "No streaming entity found in " |
1434 | "chain.\n"); | ||
1435 | return -1; | ||
1436 | } | ||
1401 | 1437 | ||
1402 | return 0; | 1438 | return 0; |
1403 | } | 1439 | } |
@@ -1408,7 +1444,8 @@ static int uvc_scan_chain(struct uvc_video_device *video) | |||
1408 | * The driver currently supports a single video device per control interface | 1444 | * The driver currently supports a single video device per control interface |
1409 | * only. The terminal and units must match the following structure: | 1445 | * only. The terminal and units must match the following structure: |
1410 | * | 1446 | * |
1411 | * ITT_CAMERA -> VC_PROCESSING_UNIT -> VC_EXTENSION_UNIT{0,n} -> TT_STREAMING | 1447 | * ITT_* -> VC_PROCESSING_UNIT -> VC_EXTENSION_UNIT{0,n} -> TT_STREAMING |
1448 | * TT_STREAMING -> VC_PROCESSING_UNIT -> VC_EXTENSION_UNIT{0,n} -> OTT_* | ||
1412 | * | 1449 | * |
1413 | * The Extension Units, if present, must have a single input pin. The | 1450 | * The Extension Units, if present, must have a single input pin. The |
1414 | * Processing Unit and Extension Units can be in any order. Additional | 1451 | * Processing Unit and Extension Units can be in any order. Additional |
@@ -1425,7 +1462,7 @@ static int uvc_register_video(struct uvc_device *dev) | |||
1425 | list_for_each_entry(term, &dev->entities, list) { | 1462 | list_for_each_entry(term, &dev->entities, list) { |
1426 | struct uvc_streaming *streaming; | 1463 | struct uvc_streaming *streaming; |
1427 | 1464 | ||
1428 | if (UVC_ENTITY_TYPE(term) != TT_STREAMING) | 1465 | if (!UVC_ENTITY_IS_TERM(term) || !UVC_ENTITY_IS_OTERM(term)) |
1429 | continue; | 1466 | continue; |
1430 | 1467 | ||
1431 | memset(&dev->video, 0, sizeof dev->video); | 1468 | memset(&dev->video, 0, sizeof dev->video); |
@@ -1438,7 +1475,8 @@ static int uvc_register_video(struct uvc_device *dev) | |||
1438 | continue; | 1475 | continue; |
1439 | 1476 | ||
1440 | list_for_each_entry(streaming, &dev->streaming, list) { | 1477 | list_for_each_entry(streaming, &dev->streaming, list) { |
1441 | if (streaming->header.bTerminalLink == term->id) { | 1478 | if (streaming->header.bTerminalLink == |
1479 | dev->video.sterm->id) { | ||
1442 | dev->video.streaming = streaming; | 1480 | dev->video.streaming = streaming; |
1443 | found = 1; | 1481 | found = 1; |
1444 | break; | 1482 | break; |
@@ -1464,6 +1502,9 @@ static int uvc_register_video(struct uvc_device *dev) | |||
1464 | printk(" -> %d).\n", dev->video.oterm->id); | 1502 | printk(" -> %d).\n", dev->video.oterm->id); |
1465 | } | 1503 | } |
1466 | 1504 | ||
1505 | /* Initialize the video buffers queue. */ | ||
1506 | uvc_queue_init(&dev->video.queue, dev->video.streaming->type); | ||
1507 | |||
1467 | /* Initialize the streaming interface with default streaming | 1508 | /* Initialize the streaming interface with default streaming |
1468 | * parameters. | 1509 | * parameters. |
1469 | */ | 1510 | */ |
diff --git a/drivers/media/video/uvc/uvc_queue.c b/drivers/media/video/uvc/uvc_queue.c index 5646a6a32939..42546342e97d 100644 --- a/drivers/media/video/uvc/uvc_queue.c +++ b/drivers/media/video/uvc/uvc_queue.c | |||
@@ -79,12 +79,13 @@ | |||
79 | * | 79 | * |
80 | */ | 80 | */ |
81 | 81 | ||
82 | void uvc_queue_init(struct uvc_video_queue *queue) | 82 | void uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type) |
83 | { | 83 | { |
84 | mutex_init(&queue->mutex); | 84 | mutex_init(&queue->mutex); |
85 | spin_lock_init(&queue->irqlock); | 85 | spin_lock_init(&queue->irqlock); |
86 | INIT_LIST_HEAD(&queue->mainqueue); | 86 | INIT_LIST_HEAD(&queue->mainqueue); |
87 | INIT_LIST_HEAD(&queue->irqqueue); | 87 | INIT_LIST_HEAD(&queue->irqqueue); |
88 | queue->type = type; | ||
88 | } | 89 | } |
89 | 90 | ||
90 | /* | 91 | /* |
@@ -132,7 +133,7 @@ int uvc_alloc_buffers(struct uvc_video_queue *queue, unsigned int nbuffers, | |||
132 | queue->buffer[i].buf.index = i; | 133 | queue->buffer[i].buf.index = i; |
133 | queue->buffer[i].buf.m.offset = i * bufsize; | 134 | queue->buffer[i].buf.m.offset = i * bufsize; |
134 | queue->buffer[i].buf.length = buflength; | 135 | queue->buffer[i].buf.length = buflength; |
135 | queue->buffer[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 136 | queue->buffer[i].buf.type = queue->type; |
136 | queue->buffer[i].buf.sequence = 0; | 137 | queue->buffer[i].buf.sequence = 0; |
137 | queue->buffer[i].buf.field = V4L2_FIELD_NONE; | 138 | queue->buffer[i].buf.field = V4L2_FIELD_NONE; |
138 | queue->buffer[i].buf.memory = V4L2_MEMORY_MMAP; | 139 | queue->buffer[i].buf.memory = V4L2_MEMORY_MMAP; |
@@ -226,7 +227,7 @@ int uvc_queue_buffer(struct uvc_video_queue *queue, | |||
226 | 227 | ||
227 | uvc_trace(UVC_TRACE_CAPTURE, "Queuing buffer %u.\n", v4l2_buf->index); | 228 | uvc_trace(UVC_TRACE_CAPTURE, "Queuing buffer %u.\n", v4l2_buf->index); |
228 | 229 | ||
229 | if (v4l2_buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || | 230 | if (v4l2_buf->type != queue->type || |
230 | v4l2_buf->memory != V4L2_MEMORY_MMAP) { | 231 | v4l2_buf->memory != V4L2_MEMORY_MMAP) { |
231 | uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer type (%u) " | 232 | uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer type (%u) " |
232 | "and/or memory (%u).\n", v4l2_buf->type, | 233 | "and/or memory (%u).\n", v4l2_buf->type, |
@@ -249,6 +250,13 @@ int uvc_queue_buffer(struct uvc_video_queue *queue, | |||
249 | goto done; | 250 | goto done; |
250 | } | 251 | } |
251 | 252 | ||
253 | if (v4l2_buf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT && | ||
254 | v4l2_buf->bytesused > buf->buf.length) { | ||
255 | uvc_trace(UVC_TRACE_CAPTURE, "[E] Bytes used out of bounds.\n"); | ||
256 | ret = -EINVAL; | ||
257 | goto done; | ||
258 | } | ||
259 | |||
252 | spin_lock_irqsave(&queue->irqlock, flags); | 260 | spin_lock_irqsave(&queue->irqlock, flags); |
253 | if (queue->flags & UVC_QUEUE_DISCONNECTED) { | 261 | if (queue->flags & UVC_QUEUE_DISCONNECTED) { |
254 | spin_unlock_irqrestore(&queue->irqlock, flags); | 262 | spin_unlock_irqrestore(&queue->irqlock, flags); |
@@ -256,7 +264,11 @@ int uvc_queue_buffer(struct uvc_video_queue *queue, | |||
256 | goto done; | 264 | goto done; |
257 | } | 265 | } |
258 | buf->state = UVC_BUF_STATE_QUEUED; | 266 | buf->state = UVC_BUF_STATE_QUEUED; |
259 | buf->buf.bytesused = 0; | 267 | if (v4l2_buf->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) |
268 | buf->buf.bytesused = 0; | ||
269 | else | ||
270 | buf->buf.bytesused = v4l2_buf->bytesused; | ||
271 | |||
260 | list_add_tail(&buf->stream, &queue->mainqueue); | 272 | list_add_tail(&buf->stream, &queue->mainqueue); |
261 | list_add_tail(&buf->queue, &queue->irqqueue); | 273 | list_add_tail(&buf->queue, &queue->irqqueue); |
262 | spin_unlock_irqrestore(&queue->irqlock, flags); | 274 | spin_unlock_irqrestore(&queue->irqlock, flags); |
@@ -289,7 +301,7 @@ int uvc_dequeue_buffer(struct uvc_video_queue *queue, | |||
289 | struct uvc_buffer *buf; | 301 | struct uvc_buffer *buf; |
290 | int ret = 0; | 302 | int ret = 0; |
291 | 303 | ||
292 | if (v4l2_buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || | 304 | if (v4l2_buf->type != queue->type || |
293 | v4l2_buf->memory != V4L2_MEMORY_MMAP) { | 305 | v4l2_buf->memory != V4L2_MEMORY_MMAP) { |
294 | uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer type (%u) " | 306 | uvc_trace(UVC_TRACE_CAPTURE, "[E] Invalid buffer type (%u) " |
295 | "and/or memory (%u).\n", v4l2_buf->type, | 307 | "and/or memory (%u).\n", v4l2_buf->type, |
@@ -397,6 +409,7 @@ int uvc_queue_enable(struct uvc_video_queue *queue, int enable) | |||
397 | } | 409 | } |
398 | queue->sequence = 0; | 410 | queue->sequence = 0; |
399 | queue->flags |= UVC_QUEUE_STREAMING; | 411 | queue->flags |= UVC_QUEUE_STREAMING; |
412 | queue->buf_used = 0; | ||
400 | } else { | 413 | } else { |
401 | uvc_queue_cancel(queue, 0); | 414 | uvc_queue_cancel(queue, 0); |
402 | INIT_LIST_HEAD(&queue->mainqueue); | 415 | INIT_LIST_HEAD(&queue->mainqueue); |
diff --git a/drivers/media/video/uvc/uvc_v4l2.c b/drivers/media/video/uvc/uvc_v4l2.c index 2e1fd1b2a619..afcc6934559e 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, | |||
110 | int ret = 0; | 110 | int ret = 0; |
111 | __u8 *fcc; | 111 | __u8 *fcc; |
112 | 112 | ||
113 | if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 113 | if (fmt->type != video->streaming->type) |
114 | return -EINVAL; | 114 | return -EINVAL; |
115 | 115 | ||
116 | fcc = (__u8 *)&fmt->fmt.pix.pixelformat; | 116 | fcc = (__u8 *)&fmt->fmt.pix.pixelformat; |
@@ -216,7 +216,7 @@ static int uvc_v4l2_get_format(struct uvc_video_device *video, | |||
216 | struct uvc_format *format = video->streaming->cur_format; | 216 | struct uvc_format *format = video->streaming->cur_format; |
217 | struct uvc_frame *frame = video->streaming->cur_frame; | 217 | struct uvc_frame *frame = video->streaming->cur_frame; |
218 | 218 | ||
219 | if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 219 | if (fmt->type != video->streaming->type) |
220 | return -EINVAL; | 220 | return -EINVAL; |
221 | 221 | ||
222 | if (format == NULL || frame == NULL) | 222 | if (format == NULL || frame == NULL) |
@@ -242,7 +242,7 @@ static int uvc_v4l2_set_format(struct uvc_video_device *video, | |||
242 | struct uvc_frame *frame; | 242 | struct uvc_frame *frame; |
243 | int ret; | 243 | int ret; |
244 | 244 | ||
245 | if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 245 | if (fmt->type != video->streaming->type) |
246 | return -EINVAL; | 246 | return -EINVAL; |
247 | 247 | ||
248 | if (uvc_queue_streaming(&video->queue)) | 248 | if (uvc_queue_streaming(&video->queue)) |
@@ -264,7 +264,7 @@ static int uvc_v4l2_get_streamparm(struct uvc_video_device *video, | |||
264 | { | 264 | { |
265 | uint32_t numerator, denominator; | 265 | uint32_t numerator, denominator; |
266 | 266 | ||
267 | if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 267 | if (parm->type != video->streaming->type) |
268 | return -EINVAL; | 268 | return -EINVAL; |
269 | 269 | ||
270 | numerator = video->streaming->ctrl.dwFrameInterval; | 270 | numerator = video->streaming->ctrl.dwFrameInterval; |
@@ -272,13 +272,21 @@ static int uvc_v4l2_get_streamparm(struct uvc_video_device *video, | |||
272 | uvc_simplify_fraction(&numerator, &denominator, 8, 333); | 272 | uvc_simplify_fraction(&numerator, &denominator, 8, 333); |
273 | 273 | ||
274 | memset(parm, 0, sizeof *parm); | 274 | memset(parm, 0, sizeof *parm); |
275 | parm->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; | 275 | parm->type = video->streaming->type; |
276 | parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; | 276 | |
277 | parm->parm.capture.capturemode = 0; | 277 | if (video->streaming->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { |
278 | parm->parm.capture.timeperframe.numerator = numerator; | 278 | parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME; |
279 | parm->parm.capture.timeperframe.denominator = denominator; | 279 | parm->parm.capture.capturemode = 0; |
280 | parm->parm.capture.extendedmode = 0; | 280 | parm->parm.capture.timeperframe.numerator = numerator; |
281 | parm->parm.capture.readbuffers = 0; | 281 | parm->parm.capture.timeperframe.denominator = denominator; |
282 | parm->parm.capture.extendedmode = 0; | ||
283 | parm->parm.capture.readbuffers = 0; | ||
284 | } else { | ||
285 | parm->parm.output.capability = V4L2_CAP_TIMEPERFRAME; | ||
286 | parm->parm.output.outputmode = 0; | ||
287 | parm->parm.output.timeperframe.numerator = numerator; | ||
288 | parm->parm.output.timeperframe.denominator = denominator; | ||
289 | } | ||
282 | 290 | ||
283 | return 0; | 291 | return 0; |
284 | } | 292 | } |
@@ -288,24 +296,27 @@ static int uvc_v4l2_set_streamparm(struct uvc_video_device *video, | |||
288 | { | 296 | { |
289 | struct uvc_frame *frame = video->streaming->cur_frame; | 297 | struct uvc_frame *frame = video->streaming->cur_frame; |
290 | struct uvc_streaming_control probe; | 298 | struct uvc_streaming_control probe; |
299 | struct v4l2_fract timeperframe; | ||
291 | uint32_t interval; | 300 | uint32_t interval; |
292 | int ret; | 301 | int ret; |
293 | 302 | ||
294 | if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 303 | if (parm->type != video->streaming->type) |
295 | return -EINVAL; | 304 | return -EINVAL; |
296 | 305 | ||
297 | if (uvc_queue_streaming(&video->queue)) | 306 | if (uvc_queue_streaming(&video->queue)) |
298 | return -EBUSY; | 307 | return -EBUSY; |
299 | 308 | ||
309 | if (parm->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
310 | timeperframe = parm->parm.capture.timeperframe; | ||
311 | else | ||
312 | timeperframe = parm->parm.output.timeperframe; | ||
313 | |||
300 | memcpy(&probe, &video->streaming->ctrl, sizeof probe); | 314 | memcpy(&probe, &video->streaming->ctrl, sizeof probe); |
301 | interval = uvc_fraction_to_interval( | 315 | interval = uvc_fraction_to_interval(timeperframe.numerator, |
302 | parm->parm.capture.timeperframe.numerator, | 316 | timeperframe.denominator); |
303 | parm->parm.capture.timeperframe.denominator); | ||
304 | 317 | ||
305 | uvc_trace(UVC_TRACE_FORMAT, "Setting frame interval to %u/%u (%u).\n", | 318 | uvc_trace(UVC_TRACE_FORMAT, "Setting frame interval to %u/%u (%u).\n", |
306 | parm->parm.capture.timeperframe.numerator, | 319 | timeperframe.numerator, timeperframe.denominator, interval); |
307 | parm->parm.capture.timeperframe.denominator, | ||
308 | interval); | ||
309 | probe.dwFrameInterval = uvc_try_frame_interval(frame, interval); | 320 | probe.dwFrameInterval = uvc_try_frame_interval(frame, interval); |
310 | 321 | ||
311 | /* Probe the device with the new settings. */ | 322 | /* Probe the device with the new settings. */ |
@@ -315,11 +326,15 @@ static int uvc_v4l2_set_streamparm(struct uvc_video_device *video, | |||
315 | memcpy(&video->streaming->ctrl, &probe, sizeof probe); | 326 | memcpy(&video->streaming->ctrl, &probe, sizeof probe); |
316 | 327 | ||
317 | /* Return the actual frame period. */ | 328 | /* Return the actual frame period. */ |
318 | parm->parm.capture.timeperframe.numerator = probe.dwFrameInterval; | 329 | timeperframe.numerator = probe.dwFrameInterval; |
319 | parm->parm.capture.timeperframe.denominator = 10000000; | 330 | timeperframe.denominator = 10000000; |
320 | uvc_simplify_fraction(&parm->parm.capture.timeperframe.numerator, | 331 | uvc_simplify_fraction(&timeperframe.numerator, |
321 | &parm->parm.capture.timeperframe.denominator, | 332 | &timeperframe.denominator, 8, 333); |
322 | 8, 333); | 333 | |
334 | if (parm->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) | ||
335 | parm->parm.capture.timeperframe = timeperframe; | ||
336 | else | ||
337 | parm->parm.output.timeperframe = timeperframe; | ||
323 | 338 | ||
324 | return 0; | 339 | return 0; |
325 | } | 340 | } |
@@ -476,8 +491,12 @@ static int uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) | |||
476 | strncpy(cap->bus_info, video->dev->udev->bus->bus_name, | 491 | strncpy(cap->bus_info, video->dev->udev->bus->bus_name, |
477 | sizeof cap->bus_info); | 492 | sizeof cap->bus_info); |
478 | cap->version = DRIVER_VERSION_NUMBER; | 493 | cap->version = DRIVER_VERSION_NUMBER; |
479 | cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | 494 | if (video->streaming->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) |
480 | | V4L2_CAP_STREAMING; | 495 | cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
496 | | V4L2_CAP_STREAMING; | ||
497 | else | ||
498 | cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | ||
499 | | V4L2_CAP_STREAMING; | ||
481 | break; | 500 | break; |
482 | } | 501 | } |
483 | 502 | ||
@@ -655,7 +674,7 @@ static int uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) | |||
655 | struct v4l2_fmtdesc *fmt = arg; | 674 | struct v4l2_fmtdesc *fmt = arg; |
656 | struct uvc_format *format; | 675 | struct uvc_format *format; |
657 | 676 | ||
658 | if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || | 677 | if (fmt->type != video->streaming->type || |
659 | fmt->index >= video->streaming->nformats) | 678 | fmt->index >= video->streaming->nformats) |
660 | return -EINVAL; | 679 | return -EINVAL; |
661 | 680 | ||
@@ -794,7 +813,7 @@ static int uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) | |||
794 | struct v4l2_cropcap *ccap = arg; | 813 | struct v4l2_cropcap *ccap = arg; |
795 | struct uvc_frame *frame = video->streaming->cur_frame; | 814 | struct uvc_frame *frame = video->streaming->cur_frame; |
796 | 815 | ||
797 | if (ccap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 816 | if (ccap->type != video->streaming->type) |
798 | return -EINVAL; | 817 | return -EINVAL; |
799 | 818 | ||
800 | ccap->bounds.left = 0; | 819 | ccap->bounds.left = 0; |
@@ -820,7 +839,7 @@ static int uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) | |||
820 | unsigned int bufsize = | 839 | unsigned int bufsize = |
821 | video->streaming->ctrl.dwMaxVideoFrameSize; | 840 | video->streaming->ctrl.dwMaxVideoFrameSize; |
822 | 841 | ||
823 | if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || | 842 | if (rb->type != video->streaming->type || |
824 | rb->memory != V4L2_MEMORY_MMAP) | 843 | rb->memory != V4L2_MEMORY_MMAP) |
825 | return -EINVAL; | 844 | return -EINVAL; |
826 | 845 | ||
@@ -840,7 +859,7 @@ static int uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) | |||
840 | { | 859 | { |
841 | struct v4l2_buffer *buf = arg; | 860 | struct v4l2_buffer *buf = arg; |
842 | 861 | ||
843 | if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 862 | if (buf->type != video->streaming->type) |
844 | return -EINVAL; | 863 | return -EINVAL; |
845 | 864 | ||
846 | if (!uvc_has_privileges(handle)) | 865 | if (!uvc_has_privileges(handle)) |
@@ -866,7 +885,7 @@ static int uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) | |||
866 | { | 885 | { |
867 | int *type = arg; | 886 | int *type = arg; |
868 | 887 | ||
869 | if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 888 | if (*type != video->streaming->type) |
870 | return -EINVAL; | 889 | return -EINVAL; |
871 | 890 | ||
872 | if (!uvc_has_privileges(handle)) | 891 | if (!uvc_has_privileges(handle)) |
@@ -881,7 +900,7 @@ static int uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg) | |||
881 | { | 900 | { |
882 | int *type = arg; | 901 | int *type = arg; |
883 | 902 | ||
884 | if (*type != V4L2_BUF_TYPE_VIDEO_CAPTURE) | 903 | if (*type != video->streaming->type) |
885 | return -EINVAL; | 904 | return -EINVAL; |
886 | 905 | ||
887 | if (!uvc_has_privileges(handle)) | 906 | if (!uvc_has_privileges(handle)) |
diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c index 6d0ac3be8191..e7c31995527f 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, | |||
453 | } | 453 | } |
454 | } | 454 | } |
455 | 455 | ||
456 | static int uvc_video_encode_header(struct uvc_video_device *video, | ||
457 | struct uvc_buffer *buf, __u8 *data, int len) | ||
458 | { | ||
459 | data[0] = 2; /* Header length */ | ||
460 | data[1] = UVC_STREAM_EOH | UVC_STREAM_EOF | ||
461 | | (video->last_fid & UVC_STREAM_FID); | ||
462 | return 2; | ||
463 | } | ||
464 | |||
465 | static int uvc_video_encode_data(struct uvc_video_device *video, | ||
466 | struct uvc_buffer *buf, __u8 *data, int len) | ||
467 | { | ||
468 | struct uvc_video_queue *queue = &video->queue; | ||
469 | unsigned int nbytes; | ||
470 | void *mem; | ||
471 | |||
472 | /* Copy video data to the URB buffer. */ | ||
473 | mem = queue->mem + buf->buf.m.offset + queue->buf_used; | ||
474 | nbytes = min((unsigned int)len, buf->buf.bytesused - queue->buf_used); | ||
475 | nbytes = min(video->bulk.max_payload_size - video->bulk.payload_size, | ||
476 | nbytes); | ||
477 | memcpy(data, mem, nbytes); | ||
478 | |||
479 | queue->buf_used += nbytes; | ||
480 | |||
481 | return nbytes; | ||
482 | } | ||
483 | |||
456 | /* ------------------------------------------------------------------------ | 484 | /* ------------------------------------------------------------------------ |
457 | * URB handling | 485 | * URB handling |
458 | */ | 486 | */ |
@@ -559,6 +587,48 @@ static void uvc_video_decode_bulk(struct urb *urb, | |||
559 | } | 587 | } |
560 | } | 588 | } |
561 | 589 | ||
590 | static void uvc_video_encode_bulk(struct urb *urb, | ||
591 | struct uvc_video_device *video, struct uvc_buffer *buf) | ||
592 | { | ||
593 | u8 *mem = urb->transfer_buffer; | ||
594 | int len = video->urb_size, ret; | ||
595 | |||
596 | if (buf == NULL) { | ||
597 | urb->transfer_buffer_length = 0; | ||
598 | return; | ||
599 | } | ||
600 | |||
601 | /* If the URB is the first of its payload, add the header. */ | ||
602 | if (video->bulk.header_size == 0) { | ||
603 | ret = uvc_video_encode_header(video, buf, mem, len); | ||
604 | video->bulk.header_size = ret; | ||
605 | video->bulk.payload_size += ret; | ||
606 | mem += ret; | ||
607 | len -= ret; | ||
608 | } | ||
609 | |||
610 | /* Process video data. */ | ||
611 | ret = uvc_video_encode_data(video, buf, mem, len); | ||
612 | |||
613 | video->bulk.payload_size += ret; | ||
614 | len -= ret; | ||
615 | |||
616 | if (buf->buf.bytesused == video->queue.buf_used || | ||
617 | video->bulk.payload_size == video->bulk.max_payload_size) { | ||
618 | if (buf->buf.bytesused == video->queue.buf_used) { | ||
619 | video->queue.buf_used = 0; | ||
620 | buf->state = UVC_BUF_STATE_DONE; | ||
621 | uvc_queue_next_buffer(&video->queue, buf); | ||
622 | video->last_fid ^= UVC_STREAM_FID; | ||
623 | } | ||
624 | |||
625 | video->bulk.header_size = 0; | ||
626 | video->bulk.payload_size = 0; | ||
627 | } | ||
628 | |||
629 | urb->transfer_buffer_length = video->urb_size - len; | ||
630 | } | ||
631 | |||
562 | static void uvc_video_complete(struct urb *urb) | 632 | static void uvc_video_complete(struct urb *urb) |
563 | { | 633 | { |
564 | struct uvc_video_device *video = urb->context; | 634 | struct uvc_video_device *video = urb->context; |
@@ -756,7 +826,15 @@ static int uvc_init_video_bulk(struct uvc_video_device *video, | |||
756 | if (uvc_alloc_urb_buffers(video, size) < 0) | 826 | if (uvc_alloc_urb_buffers(video, size) < 0) |
757 | return -ENOMEM; | 827 | return -ENOMEM; |
758 | 828 | ||
759 | pipe = usb_rcvbulkpipe(video->dev->udev, ep->desc.bEndpointAddress); | 829 | if (usb_endpoint_dir_in(&ep->desc)) |
830 | pipe = usb_rcvbulkpipe(video->dev->udev, | ||
831 | ep->desc.bEndpointAddress); | ||
832 | else | ||
833 | pipe = usb_sndbulkpipe(video->dev->udev, | ||
834 | ep->desc.bEndpointAddress); | ||
835 | |||
836 | if (video->streaming->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) | ||
837 | size = 0; | ||
760 | 838 | ||
761 | for (i = 0; i < UVC_URBS; ++i) { | 839 | for (i = 0; i < UVC_URBS; ++i) { |
762 | urb = usb_alloc_urb(0, gfp_flags); | 840 | urb = usb_alloc_urb(0, gfp_flags); |
@@ -977,12 +1055,22 @@ int uvc_video_init(struct uvc_video_device *video) | |||
977 | atomic_set(&video->active, 0); | 1055 | atomic_set(&video->active, 0); |
978 | 1056 | ||
979 | /* Select the video decoding function */ | 1057 | /* Select the video decoding function */ |
980 | if (video->dev->quirks & UVC_QUIRK_BUILTIN_ISIGHT) | 1058 | if (video->streaming->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { |
981 | video->decode = uvc_video_decode_isight; | 1059 | if (video->dev->quirks & UVC_QUIRK_BUILTIN_ISIGHT) |
982 | else if (video->streaming->intf->num_altsetting > 1) | 1060 | video->decode = uvc_video_decode_isight; |
983 | video->decode = uvc_video_decode_isoc; | 1061 | else if (video->streaming->intf->num_altsetting > 1) |
984 | else | 1062 | video->decode = uvc_video_decode_isoc; |
985 | video->decode = uvc_video_decode_bulk; | 1063 | else |
1064 | video->decode = uvc_video_decode_bulk; | ||
1065 | } else { | ||
1066 | if (video->streaming->intf->num_altsetting == 1) | ||
1067 | video->decode = uvc_video_encode_bulk; | ||
1068 | else { | ||
1069 | uvc_printk(KERN_INFO, "Isochronous endpoints are not " | ||
1070 | "supported for video output devices.\n"); | ||
1071 | return -EINVAL; | ||
1072 | } | ||
1073 | } | ||
986 | 1074 | ||
987 | return 0; | 1075 | return 0; |
988 | } | 1076 | } |
diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h index 2a5bdacbaf27..731cf7951656 100644 --- a/drivers/media/video/uvc/uvcvideo.h +++ b/drivers/media/video/uvc/uvcvideo.h | |||
@@ -529,6 +529,7 @@ struct uvc_streaming { | |||
529 | __u16 maxpsize; | 529 | __u16 maxpsize; |
530 | 530 | ||
531 | struct uvc_streaming_header header; | 531 | struct uvc_streaming_header header; |
532 | enum v4l2_buf_type type; | ||
532 | 533 | ||
533 | unsigned int nformats; | 534 | unsigned int nformats; |
534 | struct uvc_format *format; | 535 | struct uvc_format *format; |
@@ -564,12 +565,15 @@ struct uvc_buffer { | |||
564 | #define UVC_QUEUE_DROP_INCOMPLETE (1 << 2) | 565 | #define UVC_QUEUE_DROP_INCOMPLETE (1 << 2) |
565 | 566 | ||
566 | struct uvc_video_queue { | 567 | struct uvc_video_queue { |
568 | enum v4l2_buf_type type; | ||
569 | |||
567 | void *mem; | 570 | void *mem; |
568 | unsigned int flags; | 571 | unsigned int flags; |
569 | __u32 sequence; | 572 | __u32 sequence; |
570 | 573 | ||
571 | unsigned int count; | 574 | unsigned int count; |
572 | unsigned int buf_size; | 575 | unsigned int buf_size; |
576 | unsigned int buf_used; | ||
573 | struct uvc_buffer buffer[UVC_MAX_VIDEO_BUFFERS]; | 577 | struct uvc_buffer buffer[UVC_MAX_VIDEO_BUFFERS]; |
574 | struct mutex mutex; /* protects buffers and mainqueue */ | 578 | struct mutex mutex; /* protects buffers and mainqueue */ |
575 | spinlock_t irqlock; /* protects irqqueue */ | 579 | spinlock_t irqlock; /* protects irqqueue */ |
@@ -584,8 +588,9 @@ struct uvc_video_device { | |||
584 | atomic_t active; | 588 | atomic_t active; |
585 | unsigned int frozen : 1; | 589 | unsigned int frozen : 1; |
586 | 590 | ||
587 | struct list_head iterms; | 591 | struct list_head iterms; /* Input terminals */ |
588 | struct uvc_entity *oterm; | 592 | struct uvc_entity *oterm; /* Output terminal */ |
593 | struct uvc_entity *sterm; /* USB streaming terminal */ | ||
589 | struct uvc_entity *processing; | 594 | struct uvc_entity *processing; |
590 | struct uvc_entity *selector; | 595 | struct uvc_entity *selector; |
591 | struct list_head extensions; | 596 | struct list_head extensions; |
@@ -726,7 +731,8 @@ extern struct uvc_driver uvc_driver; | |||
726 | extern void uvc_delete(struct kref *kref); | 731 | extern void uvc_delete(struct kref *kref); |
727 | 732 | ||
728 | /* Video buffers queue management. */ | 733 | /* Video buffers queue management. */ |
729 | extern void uvc_queue_init(struct uvc_video_queue *queue); | 734 | extern void uvc_queue_init(struct uvc_video_queue *queue, |
735 | enum v4l2_buf_type type); | ||
730 | extern int uvc_alloc_buffers(struct uvc_video_queue *queue, | 736 | extern int uvc_alloc_buffers(struct uvc_video_queue *queue, |
731 | unsigned int nbuffers, unsigned int buflength); | 737 | unsigned int nbuffers, unsigned int buflength); |
732 | extern int uvc_free_buffers(struct uvc_video_queue *queue); | 738 | extern int uvc_free_buffers(struct uvc_video_queue *queue); |