[media] uvcvideo: uvc_scan_fallback() for webcams with broken 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) 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>
This commit is contained in:
parent
3907fae86e
commit
e950267ab8
@ -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.
|
||||
*
|
||||
@ -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) {
|
||||
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user