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/video/uvc/uvc_driver.c | |
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/video/uvc/uvc_driver.c')
-rw-r--r-- | drivers/media/video/uvc/uvc_driver.c | 109 |
1 files changed, 75 insertions, 34 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 | */ |