Skip to content

Commit

Permalink
uvcvideo: uvc_scan_fallback() for webcams with broken chain
Browse files Browse the repository at this point in the history
From: Henrik Ingo <henrik.ingo@avoinelama.fi>

[ Upstream commit e950267 ]

Some devices have invalid baSourceID references, causing uvc_scan_chain()
to fail, but if we just take the entities we can find and put them
together in the most sensible chain we can think of, turns out they do
work anyway. Note: This heuristic assumes there is a single chain.

At the time of writing, devices known to have such a broken chain are
  - Acer Integrated Camera (5986:055a)
  - Realtek rtl157a7 (0bda:57a7)

Signed-off-by: Henrik Ingo <henrik.ingo@avoinelama.fi>
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
Signed-off-by: Sasha Levin <alexander.levin@verizon.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Sumit Semwal <sumit.semwal@linaro.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
  • Loading branch information
Sumit Semwal authored and Greg Kroah-Hartman committed Mar 30, 2017
1 parent ce54941 commit 4e2c66b
Showing 1 changed file with 112 additions and 6 deletions.
118 changes: 112 additions & 6 deletions drivers/media/usb/uvc/uvc_driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -1595,6 +1595,114 @@ static const char *uvc_print_chain(struct uvc_video_chain *chain)
return buffer;
}

static struct uvc_video_chain *uvc_alloc_chain(struct uvc_device *dev)
{
struct uvc_video_chain *chain;

chain = kzalloc(sizeof(*chain), GFP_KERNEL);
if (chain == NULL)
return NULL;

INIT_LIST_HEAD(&chain->entities);
mutex_init(&chain->ctrl_mutex);
chain->dev = dev;
v4l2_prio_init(&chain->prio);

return chain;
}

/*
* Fallback heuristic for devices that don't connect units and terminals in a
* valid chain.
*
* Some devices have invalid baSourceID references, causing uvc_scan_chain()
* to fail, but if we just take the entities we can find and put them together
* in the most sensible chain we can think of, turns out they do work anyway.
* Note: This heuristic assumes there is a single chain.
*
* At the time of writing, devices known to have such a broken chain are
* - Acer Integrated Camera (5986:055a)
* - Realtek rtl157a7 (0bda:57a7)
*/
static int uvc_scan_fallback(struct uvc_device *dev)
{
struct uvc_video_chain *chain;
struct uvc_entity *iterm = NULL;
struct uvc_entity *oterm = NULL;
struct uvc_entity *entity;
struct uvc_entity *prev;

/*
* Start by locating the input and output terminals. We only support
* devices with exactly one of each for now.
*/
list_for_each_entry(entity, &dev->entities, list) {
if (UVC_ENTITY_IS_ITERM(entity)) {
if (iterm)
return -EINVAL;
iterm = entity;
}

if (UVC_ENTITY_IS_OTERM(entity)) {
if (oterm)
return -EINVAL;
oterm = entity;
}
}

if (iterm == NULL || oterm == NULL)
return -EINVAL;

/* Allocate the chain and fill it. */
chain = uvc_alloc_chain(dev);
if (chain == NULL)
return -ENOMEM;

if (uvc_scan_chain_entity(chain, oterm) < 0)
goto error;

prev = oterm;

/*
* Add all Processing and Extension Units with two pads. The order
* doesn't matter much, use reverse list traversal to connect units in
* UVC descriptor order as we build the chain from output to input. This
* leads to units appearing in the order meant by the manufacturer for
* the cameras known to require this heuristic.
*/
list_for_each_entry_reverse(entity, &dev->entities, list) {
if (entity->type != UVC_VC_PROCESSING_UNIT &&
entity->type != UVC_VC_EXTENSION_UNIT)
continue;

if (entity->num_pads != 2)
continue;

if (uvc_scan_chain_entity(chain, entity) < 0)
goto error;

prev->baSourceID[0] = entity->id;
prev = entity;
}

if (uvc_scan_chain_entity(chain, iterm) < 0)
goto error;

prev->baSourceID[0] = iterm->id;

list_add_tail(&chain->list, &dev->chains);

uvc_trace(UVC_TRACE_PROBE,
"Found a video chain by fallback heuristic (%s).\n",
uvc_print_chain(chain));

return 0;

error:
kfree(chain);
return -EINVAL;
}

/*
* Scan the device for video chains and register video devices.
*
Expand All @@ -1617,15 +1725,10 @@ static int uvc_scan_device(struct uvc_device *dev)
if (term->chain.next || term->chain.prev)
continue;

chain = kzalloc(sizeof(*chain), GFP_KERNEL);
chain = uvc_alloc_chain(dev);
if (chain == NULL)
return -ENOMEM;

INIT_LIST_HEAD(&chain->entities);
mutex_init(&chain->ctrl_mutex);
chain->dev = dev;
v4l2_prio_init(&chain->prio);

term->flags |= UVC_ENTITY_FLAG_DEFAULT;

if (uvc_scan_chain(chain, term) < 0) {
Expand All @@ -1639,6 +1742,9 @@ static int uvc_scan_device(struct uvc_device *dev)
list_add_tail(&chain->list, &dev->chains);
}

if (list_empty(&dev->chains))
uvc_scan_fallback(dev);

if (list_empty(&dev->chains)) {
uvc_printk(KERN_INFO, "No valid video chain found.\n");
return -1;
Expand Down

0 comments on commit 4e2c66b

Please sign in to comment.