|
@@ -1595,6 +1595,114 @@ static const char *uvc_print_chain(struct uvc_video_chain *chain)
|
|
return buffer;
|
|
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.
|
|
* 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)
|
|
if (term->chain.next || term->chain.prev)
|
|
continue;
|
|
continue;
|
|
|
|
|
|
- chain = kzalloc(sizeof(*chain), GFP_KERNEL);
|
|
|
|
|
|
+ chain = uvc_alloc_chain(dev);
|
|
if (chain == NULL)
|
|
if (chain == NULL)
|
|
return -ENOMEM;
|
|
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;
|
|
term->flags |= UVC_ENTITY_FLAG_DEFAULT;
|
|
|
|
|
|
if (uvc_scan_chain(chain, term) < 0) {
|
|
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);
|
|
list_add_tail(&chain->list, &dev->chains);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ if (list_empty(&dev->chains))
|
|
|
|
+ uvc_scan_fallback(dev);
|
|
|
|
+
|
|
if (list_empty(&dev->chains)) {
|
|
if (list_empty(&dev->chains)) {
|
|
uvc_printk(KERN_INFO, "No valid video chain found.\n");
|
|
uvc_printk(KERN_INFO, "No valid video chain found.\n");
|
|
return -1;
|
|
return -1;
|