diff options
-rw-r--r-- | drivers/media/video/uvc/uvc_driver.c | 75 |
1 files changed, 43 insertions, 32 deletions
diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c index 8d51a6a130b0..e7ce898ad706 100644 --- a/drivers/media/video/uvc/uvc_driver.c +++ b/drivers/media/video/uvc/uvc_driver.c | |||
@@ -1265,13 +1265,12 @@ static int uvc_scan_chain_entity(struct uvc_video_chain *chain, | |||
1265 | break; | 1265 | break; |
1266 | 1266 | ||
1267 | case UVC_TT_STREAMING: | 1267 | case UVC_TT_STREAMING: |
1268 | if (uvc_trace_param & UVC_TRACE_PROBE) | 1268 | if (UVC_ENTITY_IS_ITERM(entity)) { |
1269 | printk(" <- IT %d\n", entity->id); | 1269 | if (uvc_trace_param & UVC_TRACE_PROBE) |
1270 | 1270 | printk(" <- IT %d\n", entity->id); | |
1271 | if (!UVC_ENTITY_IS_ITERM(entity)) { | 1271 | } else { |
1272 | uvc_trace(UVC_TRACE_DESCR, "Unsupported input " | 1272 | if (uvc_trace_param & UVC_TRACE_PROBE) |
1273 | "terminal %u.\n", entity->id); | 1273 | printk(" OT %d", entity->id); |
1274 | return -1; | ||
1275 | } | 1274 | } |
1276 | 1275 | ||
1277 | break; | 1276 | break; |
@@ -1351,10 +1350,11 @@ static int uvc_scan_chain_forward(struct uvc_video_chain *chain, | |||
1351 | } | 1350 | } |
1352 | 1351 | ||
1353 | static int uvc_scan_chain_backward(struct uvc_video_chain *chain, | 1352 | static int uvc_scan_chain_backward(struct uvc_video_chain *chain, |
1354 | struct uvc_entity *entity) | 1353 | struct uvc_entity **_entity) |
1355 | { | 1354 | { |
1355 | struct uvc_entity *entity = *_entity; | ||
1356 | struct uvc_entity *term; | 1356 | struct uvc_entity *term; |
1357 | int id = -1, i; | 1357 | int id = -EINVAL, i; |
1358 | 1358 | ||
1359 | switch (UVC_ENTITY_TYPE(entity)) { | 1359 | switch (UVC_ENTITY_TYPE(entity)) { |
1360 | case UVC_VC_EXTENSION_UNIT: | 1360 | case UVC_VC_EXTENSION_UNIT: |
@@ -1398,34 +1398,49 @@ static int uvc_scan_chain_backward(struct uvc_video_chain *chain, | |||
1398 | 1398 | ||
1399 | id = 0; | 1399 | id = 0; |
1400 | break; | 1400 | break; |
1401 | |||
1402 | case UVC_ITT_VENDOR_SPECIFIC: | ||
1403 | case UVC_ITT_CAMERA: | ||
1404 | case UVC_ITT_MEDIA_TRANSPORT_INPUT: | ||
1405 | case UVC_OTT_VENDOR_SPECIFIC: | ||
1406 | case UVC_OTT_DISPLAY: | ||
1407 | case UVC_OTT_MEDIA_TRANSPORT_OUTPUT: | ||
1408 | case UVC_TT_STREAMING: | ||
1409 | id = UVC_ENTITY_IS_OTERM(entity) ? entity->output.bSourceID : 0; | ||
1410 | break; | ||
1401 | } | 1411 | } |
1402 | 1412 | ||
1403 | return id; | 1413 | if (id <= 0) { |
1414 | *_entity = NULL; | ||
1415 | return id; | ||
1416 | } | ||
1417 | |||
1418 | entity = uvc_entity_by_id(chain->dev, id); | ||
1419 | if (entity == NULL) { | ||
1420 | uvc_trace(UVC_TRACE_DESCR, "Found reference to " | ||
1421 | "unknown entity %d.\n", id); | ||
1422 | return -EINVAL; | ||
1423 | } | ||
1424 | |||
1425 | *_entity = entity; | ||
1426 | return 0; | ||
1404 | } | 1427 | } |
1405 | 1428 | ||
1406 | static int uvc_scan_chain(struct uvc_video_chain *chain, | 1429 | static int uvc_scan_chain(struct uvc_video_chain *chain, |
1407 | struct uvc_entity *oterm) | 1430 | struct uvc_entity *term) |
1408 | { | 1431 | { |
1409 | struct uvc_entity *entity, *prev; | 1432 | struct uvc_entity *entity, *prev; |
1410 | int id; | ||
1411 | 1433 | ||
1412 | entity = oterm; | 1434 | uvc_trace(UVC_TRACE_PROBE, "Scanning UVC chain:"); |
1413 | list_add_tail(&entity->chain, &chain->entities); | ||
1414 | uvc_trace(UVC_TRACE_PROBE, "Scanning UVC chain: OT %d", entity->id); | ||
1415 | 1435 | ||
1416 | id = entity->output.bSourceID; | 1436 | entity = term; |
1417 | while (id != 0) { | 1437 | prev = NULL; |
1418 | prev = entity; | ||
1419 | entity = uvc_entity_by_id(chain->dev, id); | ||
1420 | if (entity == NULL) { | ||
1421 | uvc_trace(UVC_TRACE_DESCR, "Found reference to " | ||
1422 | "unknown entity %d.\n", id); | ||
1423 | return -EINVAL; | ||
1424 | } | ||
1425 | 1438 | ||
1439 | while (entity != NULL) { | ||
1440 | /* Entity must not be part of an existing chain */ | ||
1426 | if (entity->chain.next || entity->chain.prev) { | 1441 | if (entity->chain.next || entity->chain.prev) { |
1427 | uvc_trace(UVC_TRACE_DESCR, "Found reference to " | 1442 | uvc_trace(UVC_TRACE_DESCR, "Found reference to " |
1428 | "entity %d already in chain.\n", id); | 1443 | "entity %d already in chain.\n", entity->id); |
1429 | return -EINVAL; | 1444 | return -EINVAL; |
1430 | } | 1445 | } |
1431 | 1446 | ||
@@ -1437,14 +1452,10 @@ static int uvc_scan_chain(struct uvc_video_chain *chain, | |||
1437 | if (uvc_scan_chain_forward(chain, entity, prev) < 0) | 1452 | if (uvc_scan_chain_forward(chain, entity, prev) < 0) |
1438 | return -EINVAL; | 1453 | return -EINVAL; |
1439 | 1454 | ||
1440 | /* Stop when a terminal is found. */ | ||
1441 | if (UVC_ENTITY_IS_TERM(entity)) | ||
1442 | break; | ||
1443 | |||
1444 | /* Backward scan */ | 1455 | /* Backward scan */ |
1445 | id = uvc_scan_chain_backward(chain, entity); | 1456 | prev = entity; |
1446 | if (id < 0) | 1457 | if (uvc_scan_chain_backward(chain, &entity) < 0) |
1447 | return id; | 1458 | return -EINVAL; |
1448 | } | 1459 | } |
1449 | 1460 | ||
1450 | return 0; | 1461 | return 0; |