Some real-world devices have multiple units with the same ID. When creating their media entities, it would lead to warnings and failure to create such entities. However, the V4L2 devices would still be created and work. Restore their support, but still warn about the multiple units with the same ID. Avoid the failure in navigating through the chain by storing pointers to the entities instead of only their IDs. --- drivers/media/usb/uvc/uvc_driver.c | 16 +++++++++++----- drivers/media/usb/uvc/uvc_entity.c | 4 +++- drivers/media/usb/uvc/uvcvideo.h | 1 + 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c index 1a22364f7da9..dd81067f8d30 100644 --- a/drivers/media/usb/uvc/uvc_driver.c +++ b/drivers/media/usb/uvc/uvc_driver.c @@ -791,10 +791,8 @@ static struct uvc_entity *uvc_alloc_new_entity(struct uvc_device *dev, u16 type, } /* Per UVC 1.1+ spec 3.7.2, the ID is unique. */ - if (uvc_entity_by_id(dev, id)) { - dev_err(&dev->udev->dev, "Found multiple Units with ID %u\n", id); - return ERR_PTR(-EINVAL); - } + if (uvc_entity_by_id(dev, id)) + dev_warn(&dev->udev->dev, "Found multiple Units with ID %u\n", id); extra_size = roundup(extra_size, sizeof(*entity->pads)); if (num_pads) @@ -802,7 +800,7 @@ static struct uvc_entity *uvc_alloc_new_entity(struct uvc_device *dev, u16 type, else num_inputs = 0; size = sizeof(*entity) + extra_size + sizeof(*entity->pads) * num_pads - + num_inputs; + + num_inputs + sizeof(struct uvc_entity *) * num_inputs; entity = kzalloc(size, GFP_KERNEL); if (entity == NULL) return ERR_PTR(-ENOMEM); @@ -840,6 +838,7 @@ static struct uvc_entity *uvc_alloc_new_entity(struct uvc_device *dev, u16 type, entity->bNrInPins = num_inputs; entity->baSourceID = (u8 *)(&entity->pads[num_pads]); + entity->source_entities = (struct uvc_entity **)(&entity->baSourceID[num_inputs]); return entity; } @@ -1503,6 +1502,7 @@ static int uvc_scan_chain_forward(struct uvc_video_chain *chain, } forward->baSourceID[0] = source->id; + forward->source_entities[0] = source; } list_add_tail(&forward->chain, &chain->entities); @@ -1586,6 +1586,8 @@ static int uvc_scan_chain_backward(struct uvc_video_chain *chain, return -EINVAL; } + entity->source_entities[i] = term; + uvc_dbg_cont(PROBE, " %d", term->id); list_add_tail(&term->chain, &chain->entities); @@ -1620,6 +1622,8 @@ static int uvc_scan_chain_backward(struct uvc_video_chain *chain, return -EINVAL; } + (*_entity)->source_entities[0] = entity; + *_entity = entity; return 0; } @@ -1783,6 +1787,7 @@ static int uvc_scan_fallback(struct uvc_device *dev) goto error; prev->baSourceID[0] = entity->id; + prev->source_entities[0] = entity; prev = entity; } @@ -1790,6 +1795,7 @@ static int uvc_scan_fallback(struct uvc_device *dev) goto error; prev->baSourceID[0] = iterm->id; + prev->source_entities[0] = iterm; list_add_tail(&chain->list, &dev->chains); diff --git a/drivers/media/usb/uvc/uvc_entity.c b/drivers/media/usb/uvc/uvc_entity.c index cc68dd24eb42..7f42292b7fde 100644 --- a/drivers/media/usb/uvc/uvc_entity.c +++ b/drivers/media/usb/uvc/uvc_entity.c @@ -36,7 +36,9 @@ static int uvc_mc_create_links(struct uvc_video_chain *chain, if (!(entity->pads[i].flags & MEDIA_PAD_FL_SINK)) continue; - remote = uvc_entity_by_id(chain->dev, entity->baSourceID[i]); + remote = entity->source_entities[i]; + if (remote == NULL) + remote = uvc_entity_by_id(chain->dev, entity->baSourceID[i]); if (remote == NULL || remote->num_pads == 0) return -EINVAL; diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h index 07f9921d83f2..a4ee79e4e85b 100644 --- a/drivers/media/usb/uvc/uvcvideo.h +++ b/drivers/media/usb/uvc/uvcvideo.h @@ -239,6 +239,7 @@ struct uvc_entity { u8 bNrInPins; u8 *baSourceID; + struct uvc_entity **source_entities; int (*get_info)(struct uvc_device *dev, struct uvc_entity *entity, u8 cs, u8 *caps); -- 2.34.1 --nwQemdKUjYgXQ6Qm--