Jérôme Bolduc
2015-12-09 13:56:54 UTC
Hello,
I would like to add these devices among the list of supported devices.
2997:0001 INOGENI DVIUSB
2997:0004 INOGENI 4K2USB3
2997:0009 INOGENI VGA2USB3
2997:000B INOGENI SDI2USB3
Thanks,
Jérôme
-----Original Message-----
From: linux-uvc-devel-***@lists.sourceforge.net
[mailto:linux-uvc-devel-***@lists.sourceforge.net]
Sent: 9 décembre 2015 08:07
To: linux-uvc-***@lists.sourceforge.net
Subject: Linux-uvc-devel Digest, Vol 46, Issue 8
Send Linux-uvc-devel mailing list submissions to
linux-uvc-***@lists.sourceforge.net
To subscribe or unsubscribe via the World Wide Web, visit
https://lists.sourceforge.net/lists/listinfo/linux-uvc-devel
or, via email, send a message with subject or body 'help' to
linux-uvc-devel-***@lists.sourceforge.net
You can reach the person managing the list at
linux-uvc-devel-***@lists.sourceforge.net
When replying, please edit your Subject line so it is more specific than
"Re: Contents of Linux-uvc-devel digest..."
Today's Topics:
1. Re: Acer Usb Camera 5986:055a recognized but no /dev/video0
entry (Henrik Ingo)
----------------------------------------------------------------------
Message: 1
Date: Wed, 9 Dec 2015 15:06:52 +0200
From: Henrik Ingo <***@avoinelama.fi>
Subject: Re: [linux-uvc-devel] Acer Usb Camera 5986:055a recognized
but no /dev/video0 entry
To: linux-uvc-***@lists.sourceforge.net
Message-ID:
<***@mail.gmail.com>
Content-Type: text/plain; charset="utf-8"
Hi again
Inspired by Arno's tracing activities, I decided to look deeper into this
device as well. Below is my understanding of what's wrong.
Attached is a diff with a lot of new uvc_trace() added, just to print out as
much info I could get my hands on. Functionally it's the same that I posted
previously.
Command to get below results:
sudo modprobe quirks=4096 trace=0xffff
Note: Until a few days ago I knew nothing about linux kernel code or device
drivers. If you're in the same position, take the below with caution. If
you're capable of contradicting or adding to the below, I very much welcome
that.
*Basics*
Linux has a standard way of doing doubly linked lists called `struct
list_head`. You can read about it here:
http://www.makelinux.net/ldd3/chp-11-sect-5
*Relevant uvcvideo driver basics*
A UVC device will internally consist of multiple "entities". The entities
form a "chain", through which (video) data flows. And endpoint in the chain
is a "terminal": input terminal, output terminal or streaming terminal. (The
Acer camera is a streaming terminal.) Non-enpoint entities are called
"units".
Code comment explains this in more detail as:
/* ------------------------------------------------------------------------
* UVC device scan
*/
/*
* Scan the UVC descriptors to locate a chain starting at an Output Terminal
* and containing the following units:
*
* - one or more Output Terminals (USB Streaming or Display)
* - zero or one Processing Unit
* - zero, one or more single-input Selector Units
* - zero or one multiple-input Selector Units, provided all inputs are
* connected to input terminals
* - zero, one or mode single-input Extension Units
* - one or more Input Terminals (Camera, External or USB Streaming)
*
* The terminal and units must match on of the following structures:
*
* ITT_*(0) -> +---------+ +---------+ +---------+ -> TT_STREAMING(0)
* ... | SU{0,1} | -> | PU{0,1} | -> | XU{0,n} | ...
* ITT_*(n) -> +---------+ +---------+ +---------+ -> TT_STREAMING(n)
*
* +---------+ +---------+ -> OTT_*(0)
* TT_STREAMING -> | PU{0,1} | -> | XU{0,n} | ...
* +---------+ +---------+ -> OTT_*(n)
*
* The Processing Unit and Extension Units can be in any order. Additional
* Extension Units connected to the main chain as single-unit branches are
* also supported. Single-input Selector Units are ignored.
*/
The latter structure is the one this Acer camera is trying to provide.
The call stack for the code we're looking into is below. uvc_probe() is the
first function to create a UVC-specific data structure (struct
uvc_device) out of the general usb_* arguments given to it:
uvc_probe(struct usb_interface *intf, const struct usb_device_id *id)
uvc_scan_device(struct uvc_device)
for each(dev->entities)
if (output terminal)
uvc_scan_chain()
while ( entity != NULL )
uvc_scan_chain_entity()
uvc_scan_chain_forward()
uvc_scan_chain_backward()
The struct uvc_device contains a struct list_head called entities
(dev->entities). This contains a list of uvc_entity structs, which are the
entities of the UVC device. The purpose of the above code path is to
discover these entities, their types (and functionality related to each
type) and to store them in another list_head in the order that they from a
chain (entity->chain, if there are many chains, they are found under
dev->chains).
*Observations*
At the start of uvc_scan_device(), the list dev->entities contains 4
entities:
[ 108.931880] uvcvideo: Just to see what's there, scan the list backward
(prev) first.
[ 108.931882] uvcvideo: id=4 type=6 (0x0006) name=Extension 4
prev=ffff8800a971b800 this=ffff8800a971e800 next=ffff88006f7f7508.
[ 108.931884] uvcvideo: id=3 type=33025 (0x8101) name=Output 3
prev=ffff8800a971bc00 this=ffff8800a971b800 next=ffff8800a971e800.
[ 108.931886] uvcvideo: id=2 type=5 (0x0005) name=Processing 2
prev=ffff8800a971a800 this=ffff8800a971bc00 next=ffff8800a971b800.
[ 108.931888] uvcvideo: id=1 type=513 (0x0201) name=Camera 1
prev=ffff88006f7f7508 this=ffff8800a971a800 next=ffff8800a971bc00.
[ 108.931889] uvcvideo: Backward scan completed, now start again and go
forward (next):
[ 108.931891] uvcvideo: id=1 type=513 (0x0201) name=Camera 1
prev=ffff88006f7f7508 this=ffff8800a971a800 next=ffff8800a971bc00.
[ 108.931893] uvcvideo: id=2 type=5 (0x0005) name=Processing 2
prev=ffff8800a971a800 this=ffff8800a971bc00 next=ffff8800a971b800.
[ 108.931894] uvcvideo: id=3 type=33025 (0x8101) name=Output 3
prev=ffff8800a971bc00 this=ffff8800a971b800 next=ffff8800a971e800.
[ 108.931896] uvcvideo: id=4 type=6 (0x0006) name=Extension 4
prev=ffff8800a971b800 this=ffff8800a971e800 next=ffff88006f7f7508.
[ 108.931897] uvcvideo: End of informational scan, we now return to our
normal programming...
(Sorry, I had to scan list_head both directions to confirm it's really
circular. I'm new to this :-)
The code then proceeds to find an output terminal and trying to scan
backwards from that. Each uvc_entity contains the field
entity->baSourceID, which is a pointer to the previous entity in the
uvc chain. The code tries to follow this until it finds the other end of a
complete chain. From traces that also contain baSourceID, it's easy to see
what chain structure we should end up with here:
[ 108.931899] uvcvideo: uvc_scan_device() loop: id=1, type=513
(0x0201) name=Camera 1, baSourceID=0
[ 108.931901] uvcvideo: uvc_scan_device() loop: id=2, type=5 (0x0005)
name=Processing 2, baSourceID=1 [ 108.931902] uvcvideo: uvc_scan_device()
loop: id=3, type=257
(0x0101) name=Output 3, baSourceID=6
[ 108.931903] uvcvideo: Found OUTPUT_TERMINAL type, check if it's already
part of a chain...
[ 108.931904] uvcvideo: Terminal is not part of a chain, so allocate memory
and init+scan a new chain...
[ 108.931905] uvcvideo: Scanning UVC chain:
[ 108.931909] uvcvideo: uvc_scan_chain_entity() new entity: id=3,
type=257 (0x0101), name=Output 3, baSourceID=6.
[ 108.931910] OT 3
[ 108.931911] uvcvideo: uvc_scan_chain_entity(): ...list_add_tail() [
108.931913] uvcvideo: uvc_scan_chain_backward(): id=3, type=257 (0x0101),
name=Output 3, baSourceID=6.
[ 108.931914] uvcvideo: Found reference to unknown entity 6, but ignoring
as UVC_QUIRK_IGNORE_CHAIN_ERR is set.
In other words, the chain clearly is:
+--------------+
| Camera 1 |
| id=1 |
| type=0x201 |
+--------------+
|
v
+--------------+
| Processing 2 |
| id=2 |
| type=0x5 |
+--------------+
|
v
+--------------+
| Extension 4 |
| id=4 |
| type=0x6 |
+--------------+
+--------------+
| ??? |
| id=6 |
| |
+--------------+
|
v
+--------------+
| Output 3 |
| id=3 |
| type=0x101 |
+--------------+
We know that there should be an entity id=6, since "Output 3" is connected
to it in the chain. In addition, we can speculate that there probably is an
entity id=5 that we haven't seen yet, but that would be located between id=4
and id=6.
The problem is that entities 5 and 6 are not present in dev->entities, so
the code doesn't find them and aborts with an error. With the attached
patch, the error is ignored and uvc_scan_chain() is left holding entity 3.
Luckily this happens to be an output terminal, so we actually have a
"working" UVC chain consisting solely of the entity "Output 3", which is
returned as success to the calling code.
*Next steps*
My main question now is, who is populating dev->entities, and why is it
incomplete? The correct fix would be to change that code so that entities 5
and 6 are correctly discovered and added to the list, before we enter the
code path discussed above.
Alternatively, as already has been suggested in this thread, since we seem
to end up with a working device (there's an output terminal, and video comes
out of it), a fix that would be welcomed by those of us stuck with this
device, would be to simply ignore this error and return ok with the
incomplete chain. Note also that prior to uvc_scan_chain(), we have
successfully found controls in entities 1 and 2, so it seems probably that
applications can successfully set things like white balance, sharpness,
etc...
A variation of the second alternative would be to simply connect entities 3
and 4, to get the chain 1 -> 2 -> 4 -> 3. Based on the code comment cited
above, this is actually a valid chain, since we have a streaming terminal, a
processing unit, an extension unit and an output unit. In other words, if we
set baSourceID=4 (instead of 6) on entity 3, everything would work fine.
It's just a single bit that's wrong!
henrik
--
***@avoinelama.fi
+358-40-5697354 skype: henrik.ingo irc: hingo
www.openlife.cc
My LinkedIn profile: http://fi.linkedin.com/pub/henrik-ingo/3/232/8a7
-------------- next part --------------
diff --git a/debian.master/changelog b/debian.master/changelog index
b464ecf..e7ca622 100644
--- a/debian.master/changelog
+++ b/debian.master/changelog
@@ -1,3 +1,12 @@
+linux (4.2.0-19.23+myxperiment02) wily; urgency=low
+
+ [ Henrik Ingo ]
+
+ * Add UVC_QUIRK_IGNORE_CHAIN_ERR to support webcams that work, even if
they'd otherwise fail on probing.
+ - http://sourceforge.net/p/linux-uvc/mailman/message/34670220/
+
+ -- Henrik Ingo <***@localhost> Sat, 05 Dec 2015 14:59:42
+ -0200
+
linux (4.2.0-19.23) wily; urgency=low
[ Luis Henriques ]
diff --git a/debian/scripts/sub-flavour b/debian/scripts/sub-flavour old
mode 100644 new mode 100755 diff --git a/drivers/media/usb/uvc/uvc_driver.c
b/drivers/media/usb/uvc/uvc_driver.c
index fae81ef..f6d2087 100644
--- a/drivers/media/usb/uvc/uvc_driver.c
+++ b/drivers/media/usb/uvc/uvc_driver.c
@@ -1285,6 +1285,8 @@ next_descriptor:
static int uvc_scan_chain_entity(struct uvc_video_chain *chain,
struct uvc_entity *entity)
{
+uvc_trace(UVC_TRACE_PROBE, "uvc_scan_chain_entity() new entity: id=%d,
type=%d (0x%04x), name=%s, baSourceID=%d.\n",
+ entity->id, UVC_ENTITY_TYPE(entity),
UVC_ENTITY_TYPE(entity),
+entity->name, entity->baSourceID ? *(entity->baSourceID) : 0 );
switch (UVC_ENTITY_TYPE(entity)) {
case UVC_VC_EXTENSION_UNIT:
if (uvc_trace_param & UVC_TRACE_PROBE) @@ -1361,6 +1363,7 @@
static int uvc_scan_chain_entity(struct uvc_video_chain *chain,
return -1;
}
+uvc_trace(UVC_TRACE_PROBE, "uvc_scan_chain_entity():
+...list_add_tail()\n");
list_add_tail(&entity->chain, &chain->entities);
return 0;
}
@@ -1380,6 +1383,8 @@ static int uvc_scan_chain_forward(struct
uvc_video_chain *chain,
forward);
if (forward == NULL)
break;
+uvc_trace(UVC_TRACE_DESCR, "uvc_scan_chain_forward(): forward->id=%d,
forward->type=%d (0x%04x), name=%s, baSourceID=%d.\n",
+ forward->id, UVC_ENTITY_TYPE(forward),
UVC_ENTITY_TYPE(forward),
+forward->name, entity->baSourceID ? *(entity->baSourceID) : 0 );
if (forward == prev)
continue;
@@ -1392,6 +1397,7 @@ static int uvc_scan_chain_forward(struct
uvc_video_chain *chain,
return -EINVAL;
}
+uvc_trace(UVC_TRACE_DESCR, "uvc_scan_chain_forward():
+...list_add_tail()\n");
list_add_tail(&forward->chain, &chain->entities);
if (uvc_trace_param & UVC_TRACE_PROBE) {
if (!found)
@@ -1412,6 +1418,7 @@ static int uvc_scan_chain_forward(struct
uvc_video_chain *chain,
return -EINVAL;
}
+uvc_trace(UVC_TRACE_DESCR, "uvc_scan_chain_forward():
+...list_add_tail()\n");
list_add_tail(&forward->chain, &chain->entities);
if (uvc_trace_param & UVC_TRACE_PROBE) {
if (!found)
@@ -1436,6 +1443,8 @@ static int uvc_scan_chain_backward(struct
uvc_video_chain *chain,
struct uvc_entity *term;
int id = -EINVAL, i;
+uvc_trace(UVC_TRACE_DESCR, "uvc_scan_chain_backward(): id=%d, type=%d
(0x%04x), name=%s, baSourceID=%d.\n",
+ entity->id, UVC_ENTITY_TYPE(entity),
UVC_ENTITY_TYPE(entity),
+entity->name, entity->baSourceID ? *(entity->baSourceID) : 0);
switch (UVC_ENTITY_TYPE(entity)) {
case UVC_VC_EXTENSION_UNIT:
case UVC_VC_PROCESSING_UNIT:
@@ -1466,6 +1475,7 @@ static int uvc_scan_chain_backward(struct
uvc_video_chain *chain,
if (uvc_trace_param & UVC_TRACE_PROBE)
printk(" %d", term->id);
+uvc_trace(UVC_TRACE_DESCR, "uvc_scan_chain_backward():
+...list_add_tail()\n");
list_add_tail(&term->chain, &chain->entities);
uvc_scan_chain_forward(chain, term, entity);
}
@@ -1494,10 +1504,19 @@ static int uvc_scan_chain_backward(struct
uvc_video_chain *chain,
entity = uvc_entity_by_id(chain->dev, id);
if (entity == NULL) {
+ if ( chain->dev->quirks & UVC_QUIRK_IGNORE_CHAIN_ERR ) {
+ uvc_trace(UVC_TRACE_DESCR, "Found reference to "
+ "unknown entity %d, but ignoring as "
+ "UVC_QUIRK_IGNORE_CHAIN_ERR is set.\n", id);
+ /* Since we don't move *_entity, uvc_scan_chain()
will also return during next loop. */
+ return 0;
+ }
uvc_trace(UVC_TRACE_DESCR, "Found reference to "
"unknown entity %d.\n", id);
return -EINVAL;
}
+uvc_trace(UVC_TRACE_DESCR, "uvc_scan_chain_backward() new entity: id=%d,
type=%d (0x%04x), name=%s, baSourceID=%d.\n",
+ entity->id, UVC_ENTITY_TYPE(entity),
UVC_ENTITY_TYPE(entity),
+entity->name, entity->baSourceID ? *(entity->baSourceID) : 0 );
*_entity = entity;
return 0;
@@ -1516,9 +1535,18 @@ static int uvc_scan_chain(struct uvc_video_chain
*chain,
while (entity != NULL) {
/* Entity must not be part of an existing chain */
if (entity->chain.next || entity->chain.prev) {
- uvc_trace(UVC_TRACE_DESCR, "Found reference to "
- "entity %d already in chain.\n",
entity->id);
- return -EINVAL;
+ if ( chain->dev->quirks & UVC_QUIRK_IGNORE_CHAIN_ERR
) {
+ uvc_trace(UVC_TRACE_DESCR, "Found reference
to "
+ "entity %d already in chain, but "
+ "ignoring as
UVC_QUIRK_IGNORE_CHAIN_ERR is set.\n",
+ entity->id);
+ return 0;
+ }
+ else {
+ uvc_trace(UVC_TRACE_DESCR, "Found reference
to "
+ "entity %d already in chain.\n",
entity->id);
+ return -EINVAL;
+ }
}
/* Process entity */
@@ -1584,9 +1612,29 @@ static int uvc_scan_device(struct uvc_device *dev)
struct uvc_video_chain *chain;
struct uvc_entity *term;
+ struct list_head *ptr;
+ struct uvc_entity *ent;
+uvc_trace(UVC_TRACE_PROBE, "Just to see what's there, scan the list
backward (prev) first.\n");
+ for (ptr = dev->entities.prev; ptr != &dev->entities; ptr = ptr->prev)
{
+ ent = list_entry(ptr, struct uvc_entity, list);
+uvc_trace(UVC_TRACE_PROBE, "id=%d type=%d (0x%04x) name=%s prev=%p this=%p
next=%p.\n",
+ ent->id, ent->type, ent->type, ent->name, ptr->prev, ptr,
ptr->next);
+ }
+uvc_trace(UVC_TRACE_PROBE, "Backward scan completed, now start again and go
forward (next):\n");
+ for (ptr = dev->entities.next; ptr != &dev->entities; ptr = ptr->next)
{
+ ent = list_entry(ptr, struct uvc_entity, list);
+uvc_trace(UVC_TRACE_PROBE, "id=%d type=%d (0x%04x) name=%s prev=%p this=%p
next=%p.\n",
+ ent->id, ent->type, ent->type, ent->name, ptr->prev, ptr,
ptr->next);
+ }
+uvc_trace(UVC_TRACE_PROBE, "End of informational scan, we now return to
+our normal programming...\n");
+
+
list_for_each_entry(term, &dev->entities, list) {
+uvc_trace(UVC_TRACE_PROBE, "uvc_scan_device() loop: id=%d, type=%d (0x%04x)
name=%s, baSourceID=%d\n",
+ term->id, UVC_ENTITY_TYPE(term),
UVC_ENTITY_TYPE(term), term->name,
+term->baSourceID ? *(term->baSourceID) : 0 );
if (!UVC_ENTITY_IS_OTERM(term))
continue;
+uvc_trace(UVC_TRACE_PROBE, "Found OUTPUT_TERMINAL type, check if it's
+already part of a chain...\n");
/* If the terminal is already included in a chain, skip it.
* This can happen for chains that have multiple output @@
-1595,6 +1643,7 @@ static int uvc_scan_device(struct uvc_device *dev)
*/
if (term->chain.next || term->chain.prev)
continue;
+uvc_trace(UVC_TRACE_PROBE, "Terminal is not part of a chain, so
+allocate memory and init+scan a new chain...\n");
chain = kzalloc(sizeof(*chain), GFP_KERNEL);
if (chain == NULL)
@@ -1927,6 +1976,8 @@ static int uvc_probe(struct usb_interface *intf,
if (uvc_ctrl_init_device(dev) < 0)
goto error;
+uvc_trace(UVC_TRACE_PROBE, "About to scan uvc device: %s, intfnum:
+%d.\n", dev->name, dev->intfnum); uvc_trace(UVC_TRACE_PROBE, "Will scan
+dev->entities: (next: %p, prev: %p).\n", dev->entities.next,
+dev->entities.prev);
/* Scan the device for video chains. */
if (uvc_scan_device(dev) < 0)
goto error;
diff --git a/drivers/media/usb/uvc/uvcvideo.h
b/drivers/media/usb/uvc/uvcvideo.h
index 816dd1a..2f83287 100644
--- a/drivers/media/usb/uvc/uvcvideo.h
+++ b/drivers/media/usb/uvc/uvcvideo.h
@@ -152,6 +152,7 @@
#define UVC_QUIRK_RESTRICT_FRAME_RATE 0x00000200
#define UVC_QUIRK_RESTORE_CTRLS_ON_INIT 0x00000400
#define UVC_QUIRK_FORCE_Y8 0x00000800
+#define UVC_QUIRK_IGNORE_CHAIN_ERR 0x00001000
/* Format flags */
#define UVC_FMT_FLAG_COMPRESSED 0x00000001
-------------- next part --------------
A non-text attachment was scrubbed...
Name: dmesg.log.x02
Type: application/octet-stream
Size: 71120 bytes
Desc: not available
------------------------------
----------------------------------------------------------------------------
--
------------------------------
_______________________________________________
Linux-uvc-devel mailing list
Linux-uvc-***@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-uvc-devel
End of Linux-uvc-devel Digest, Vol 46, Issue 8
**********************************************
------------------------------------------------------------------------------
I would like to add these devices among the list of supported devices.
2997:0001 INOGENI DVIUSB
2997:0004 INOGENI 4K2USB3
2997:0009 INOGENI VGA2USB3
2997:000B INOGENI SDI2USB3
Thanks,
Jérôme
-----Original Message-----
From: linux-uvc-devel-***@lists.sourceforge.net
[mailto:linux-uvc-devel-***@lists.sourceforge.net]
Sent: 9 décembre 2015 08:07
To: linux-uvc-***@lists.sourceforge.net
Subject: Linux-uvc-devel Digest, Vol 46, Issue 8
Send Linux-uvc-devel mailing list submissions to
linux-uvc-***@lists.sourceforge.net
To subscribe or unsubscribe via the World Wide Web, visit
https://lists.sourceforge.net/lists/listinfo/linux-uvc-devel
or, via email, send a message with subject or body 'help' to
linux-uvc-devel-***@lists.sourceforge.net
You can reach the person managing the list at
linux-uvc-devel-***@lists.sourceforge.net
When replying, please edit your Subject line so it is more specific than
"Re: Contents of Linux-uvc-devel digest..."
Today's Topics:
1. Re: Acer Usb Camera 5986:055a recognized but no /dev/video0
entry (Henrik Ingo)
----------------------------------------------------------------------
Message: 1
Date: Wed, 9 Dec 2015 15:06:52 +0200
From: Henrik Ingo <***@avoinelama.fi>
Subject: Re: [linux-uvc-devel] Acer Usb Camera 5986:055a recognized
but no /dev/video0 entry
To: linux-uvc-***@lists.sourceforge.net
Message-ID:
<***@mail.gmail.com>
Content-Type: text/plain; charset="utf-8"
Hi again
Inspired by Arno's tracing activities, I decided to look deeper into this
device as well. Below is my understanding of what's wrong.
Attached is a diff with a lot of new uvc_trace() added, just to print out as
much info I could get my hands on. Functionally it's the same that I posted
previously.
Command to get below results:
sudo modprobe quirks=4096 trace=0xffff
Note: Until a few days ago I knew nothing about linux kernel code or device
drivers. If you're in the same position, take the below with caution. If
you're capable of contradicting or adding to the below, I very much welcome
that.
*Basics*
Linux has a standard way of doing doubly linked lists called `struct
list_head`. You can read about it here:
http://www.makelinux.net/ldd3/chp-11-sect-5
*Relevant uvcvideo driver basics*
A UVC device will internally consist of multiple "entities". The entities
form a "chain", through which (video) data flows. And endpoint in the chain
is a "terminal": input terminal, output terminal or streaming terminal. (The
Acer camera is a streaming terminal.) Non-enpoint entities are called
"units".
Code comment explains this in more detail as:
/* ------------------------------------------------------------------------
* UVC device scan
*/
/*
* Scan the UVC descriptors to locate a chain starting at an Output Terminal
* and containing the following units:
*
* - one or more Output Terminals (USB Streaming or Display)
* - zero or one Processing Unit
* - zero, one or more single-input Selector Units
* - zero or one multiple-input Selector Units, provided all inputs are
* connected to input terminals
* - zero, one or mode single-input Extension Units
* - one or more Input Terminals (Camera, External or USB Streaming)
*
* The terminal and units must match on of the following structures:
*
* ITT_*(0) -> +---------+ +---------+ +---------+ -> TT_STREAMING(0)
* ... | SU{0,1} | -> | PU{0,1} | -> | XU{0,n} | ...
* ITT_*(n) -> +---------+ +---------+ +---------+ -> TT_STREAMING(n)
*
* +---------+ +---------+ -> OTT_*(0)
* TT_STREAMING -> | PU{0,1} | -> | XU{0,n} | ...
* +---------+ +---------+ -> OTT_*(n)
*
* The Processing Unit and Extension Units can be in any order. Additional
* Extension Units connected to the main chain as single-unit branches are
* also supported. Single-input Selector Units are ignored.
*/
The latter structure is the one this Acer camera is trying to provide.
The call stack for the code we're looking into is below. uvc_probe() is the
first function to create a UVC-specific data structure (struct
uvc_device) out of the general usb_* arguments given to it:
uvc_probe(struct usb_interface *intf, const struct usb_device_id *id)
uvc_scan_device(struct uvc_device)
for each(dev->entities)
if (output terminal)
uvc_scan_chain()
while ( entity != NULL )
uvc_scan_chain_entity()
uvc_scan_chain_forward()
uvc_scan_chain_backward()
The struct uvc_device contains a struct list_head called entities
(dev->entities). This contains a list of uvc_entity structs, which are the
entities of the UVC device. The purpose of the above code path is to
discover these entities, their types (and functionality related to each
type) and to store them in another list_head in the order that they from a
chain (entity->chain, if there are many chains, they are found under
dev->chains).
*Observations*
At the start of uvc_scan_device(), the list dev->entities contains 4
entities:
[ 108.931880] uvcvideo: Just to see what's there, scan the list backward
(prev) first.
[ 108.931882] uvcvideo: id=4 type=6 (0x0006) name=Extension 4
prev=ffff8800a971b800 this=ffff8800a971e800 next=ffff88006f7f7508.
[ 108.931884] uvcvideo: id=3 type=33025 (0x8101) name=Output 3
prev=ffff8800a971bc00 this=ffff8800a971b800 next=ffff8800a971e800.
[ 108.931886] uvcvideo: id=2 type=5 (0x0005) name=Processing 2
prev=ffff8800a971a800 this=ffff8800a971bc00 next=ffff8800a971b800.
[ 108.931888] uvcvideo: id=1 type=513 (0x0201) name=Camera 1
prev=ffff88006f7f7508 this=ffff8800a971a800 next=ffff8800a971bc00.
[ 108.931889] uvcvideo: Backward scan completed, now start again and go
forward (next):
[ 108.931891] uvcvideo: id=1 type=513 (0x0201) name=Camera 1
prev=ffff88006f7f7508 this=ffff8800a971a800 next=ffff8800a971bc00.
[ 108.931893] uvcvideo: id=2 type=5 (0x0005) name=Processing 2
prev=ffff8800a971a800 this=ffff8800a971bc00 next=ffff8800a971b800.
[ 108.931894] uvcvideo: id=3 type=33025 (0x8101) name=Output 3
prev=ffff8800a971bc00 this=ffff8800a971b800 next=ffff8800a971e800.
[ 108.931896] uvcvideo: id=4 type=6 (0x0006) name=Extension 4
prev=ffff8800a971b800 this=ffff8800a971e800 next=ffff88006f7f7508.
[ 108.931897] uvcvideo: End of informational scan, we now return to our
normal programming...
(Sorry, I had to scan list_head both directions to confirm it's really
circular. I'm new to this :-)
The code then proceeds to find an output terminal and trying to scan
backwards from that. Each uvc_entity contains the field
entity->baSourceID, which is a pointer to the previous entity in the
uvc chain. The code tries to follow this until it finds the other end of a
complete chain. From traces that also contain baSourceID, it's easy to see
what chain structure we should end up with here:
[ 108.931899] uvcvideo: uvc_scan_device() loop: id=1, type=513
(0x0201) name=Camera 1, baSourceID=0
[ 108.931901] uvcvideo: uvc_scan_device() loop: id=2, type=5 (0x0005)
name=Processing 2, baSourceID=1 [ 108.931902] uvcvideo: uvc_scan_device()
loop: id=3, type=257
(0x0101) name=Output 3, baSourceID=6
[ 108.931903] uvcvideo: Found OUTPUT_TERMINAL type, check if it's already
part of a chain...
[ 108.931904] uvcvideo: Terminal is not part of a chain, so allocate memory
and init+scan a new chain...
[ 108.931905] uvcvideo: Scanning UVC chain:
[ 108.931909] uvcvideo: uvc_scan_chain_entity() new entity: id=3,
type=257 (0x0101), name=Output 3, baSourceID=6.
[ 108.931910] OT 3
[ 108.931911] uvcvideo: uvc_scan_chain_entity(): ...list_add_tail() [
108.931913] uvcvideo: uvc_scan_chain_backward(): id=3, type=257 (0x0101),
name=Output 3, baSourceID=6.
[ 108.931914] uvcvideo: Found reference to unknown entity 6, but ignoring
as UVC_QUIRK_IGNORE_CHAIN_ERR is set.
In other words, the chain clearly is:
+--------------+
| Camera 1 |
| id=1 |
| type=0x201 |
+--------------+
|
v
+--------------+
| Processing 2 |
| id=2 |
| type=0x5 |
+--------------+
|
v
+--------------+
| Extension 4 |
| id=4 |
| type=0x6 |
+--------------+
+--------------+
| ??? |
| id=6 |
| |
+--------------+
|
v
+--------------+
| Output 3 |
| id=3 |
| type=0x101 |
+--------------+
We know that there should be an entity id=6, since "Output 3" is connected
to it in the chain. In addition, we can speculate that there probably is an
entity id=5 that we haven't seen yet, but that would be located between id=4
and id=6.
The problem is that entities 5 and 6 are not present in dev->entities, so
the code doesn't find them and aborts with an error. With the attached
patch, the error is ignored and uvc_scan_chain() is left holding entity 3.
Luckily this happens to be an output terminal, so we actually have a
"working" UVC chain consisting solely of the entity "Output 3", which is
returned as success to the calling code.
*Next steps*
My main question now is, who is populating dev->entities, and why is it
incomplete? The correct fix would be to change that code so that entities 5
and 6 are correctly discovered and added to the list, before we enter the
code path discussed above.
Alternatively, as already has been suggested in this thread, since we seem
to end up with a working device (there's an output terminal, and video comes
out of it), a fix that would be welcomed by those of us stuck with this
device, would be to simply ignore this error and return ok with the
incomplete chain. Note also that prior to uvc_scan_chain(), we have
successfully found controls in entities 1 and 2, so it seems probably that
applications can successfully set things like white balance, sharpness,
etc...
A variation of the second alternative would be to simply connect entities 3
and 4, to get the chain 1 -> 2 -> 4 -> 3. Based on the code comment cited
above, this is actually a valid chain, since we have a streaming terminal, a
processing unit, an extension unit and an output unit. In other words, if we
set baSourceID=4 (instead of 6) on entity 3, everything would work fine.
It's just a single bit that's wrong!
henrik
--
***@avoinelama.fi
+358-40-5697354 skype: henrik.ingo irc: hingo
www.openlife.cc
My LinkedIn profile: http://fi.linkedin.com/pub/henrik-ingo/3/232/8a7
-------------- next part --------------
diff --git a/debian.master/changelog b/debian.master/changelog index
b464ecf..e7ca622 100644
--- a/debian.master/changelog
+++ b/debian.master/changelog
@@ -1,3 +1,12 @@
+linux (4.2.0-19.23+myxperiment02) wily; urgency=low
+
+ [ Henrik Ingo ]
+
+ * Add UVC_QUIRK_IGNORE_CHAIN_ERR to support webcams that work, even if
they'd otherwise fail on probing.
+ - http://sourceforge.net/p/linux-uvc/mailman/message/34670220/
+
+ -- Henrik Ingo <***@localhost> Sat, 05 Dec 2015 14:59:42
+ -0200
+
linux (4.2.0-19.23) wily; urgency=low
[ Luis Henriques ]
diff --git a/debian/scripts/sub-flavour b/debian/scripts/sub-flavour old
mode 100644 new mode 100755 diff --git a/drivers/media/usb/uvc/uvc_driver.c
b/drivers/media/usb/uvc/uvc_driver.c
index fae81ef..f6d2087 100644
--- a/drivers/media/usb/uvc/uvc_driver.c
+++ b/drivers/media/usb/uvc/uvc_driver.c
@@ -1285,6 +1285,8 @@ next_descriptor:
static int uvc_scan_chain_entity(struct uvc_video_chain *chain,
struct uvc_entity *entity)
{
+uvc_trace(UVC_TRACE_PROBE, "uvc_scan_chain_entity() new entity: id=%d,
type=%d (0x%04x), name=%s, baSourceID=%d.\n",
+ entity->id, UVC_ENTITY_TYPE(entity),
UVC_ENTITY_TYPE(entity),
+entity->name, entity->baSourceID ? *(entity->baSourceID) : 0 );
switch (UVC_ENTITY_TYPE(entity)) {
case UVC_VC_EXTENSION_UNIT:
if (uvc_trace_param & UVC_TRACE_PROBE) @@ -1361,6 +1363,7 @@
static int uvc_scan_chain_entity(struct uvc_video_chain *chain,
return -1;
}
+uvc_trace(UVC_TRACE_PROBE, "uvc_scan_chain_entity():
+...list_add_tail()\n");
list_add_tail(&entity->chain, &chain->entities);
return 0;
}
@@ -1380,6 +1383,8 @@ static int uvc_scan_chain_forward(struct
uvc_video_chain *chain,
forward);
if (forward == NULL)
break;
+uvc_trace(UVC_TRACE_DESCR, "uvc_scan_chain_forward(): forward->id=%d,
forward->type=%d (0x%04x), name=%s, baSourceID=%d.\n",
+ forward->id, UVC_ENTITY_TYPE(forward),
UVC_ENTITY_TYPE(forward),
+forward->name, entity->baSourceID ? *(entity->baSourceID) : 0 );
if (forward == prev)
continue;
@@ -1392,6 +1397,7 @@ static int uvc_scan_chain_forward(struct
uvc_video_chain *chain,
return -EINVAL;
}
+uvc_trace(UVC_TRACE_DESCR, "uvc_scan_chain_forward():
+...list_add_tail()\n");
list_add_tail(&forward->chain, &chain->entities);
if (uvc_trace_param & UVC_TRACE_PROBE) {
if (!found)
@@ -1412,6 +1418,7 @@ static int uvc_scan_chain_forward(struct
uvc_video_chain *chain,
return -EINVAL;
}
+uvc_trace(UVC_TRACE_DESCR, "uvc_scan_chain_forward():
+...list_add_tail()\n");
list_add_tail(&forward->chain, &chain->entities);
if (uvc_trace_param & UVC_TRACE_PROBE) {
if (!found)
@@ -1436,6 +1443,8 @@ static int uvc_scan_chain_backward(struct
uvc_video_chain *chain,
struct uvc_entity *term;
int id = -EINVAL, i;
+uvc_trace(UVC_TRACE_DESCR, "uvc_scan_chain_backward(): id=%d, type=%d
(0x%04x), name=%s, baSourceID=%d.\n",
+ entity->id, UVC_ENTITY_TYPE(entity),
UVC_ENTITY_TYPE(entity),
+entity->name, entity->baSourceID ? *(entity->baSourceID) : 0);
switch (UVC_ENTITY_TYPE(entity)) {
case UVC_VC_EXTENSION_UNIT:
case UVC_VC_PROCESSING_UNIT:
@@ -1466,6 +1475,7 @@ static int uvc_scan_chain_backward(struct
uvc_video_chain *chain,
if (uvc_trace_param & UVC_TRACE_PROBE)
printk(" %d", term->id);
+uvc_trace(UVC_TRACE_DESCR, "uvc_scan_chain_backward():
+...list_add_tail()\n");
list_add_tail(&term->chain, &chain->entities);
uvc_scan_chain_forward(chain, term, entity);
}
@@ -1494,10 +1504,19 @@ static int uvc_scan_chain_backward(struct
uvc_video_chain *chain,
entity = uvc_entity_by_id(chain->dev, id);
if (entity == NULL) {
+ if ( chain->dev->quirks & UVC_QUIRK_IGNORE_CHAIN_ERR ) {
+ uvc_trace(UVC_TRACE_DESCR, "Found reference to "
+ "unknown entity %d, but ignoring as "
+ "UVC_QUIRK_IGNORE_CHAIN_ERR is set.\n", id);
+ /* Since we don't move *_entity, uvc_scan_chain()
will also return during next loop. */
+ return 0;
+ }
uvc_trace(UVC_TRACE_DESCR, "Found reference to "
"unknown entity %d.\n", id);
return -EINVAL;
}
+uvc_trace(UVC_TRACE_DESCR, "uvc_scan_chain_backward() new entity: id=%d,
type=%d (0x%04x), name=%s, baSourceID=%d.\n",
+ entity->id, UVC_ENTITY_TYPE(entity),
UVC_ENTITY_TYPE(entity),
+entity->name, entity->baSourceID ? *(entity->baSourceID) : 0 );
*_entity = entity;
return 0;
@@ -1516,9 +1535,18 @@ static int uvc_scan_chain(struct uvc_video_chain
*chain,
while (entity != NULL) {
/* Entity must not be part of an existing chain */
if (entity->chain.next || entity->chain.prev) {
- uvc_trace(UVC_TRACE_DESCR, "Found reference to "
- "entity %d already in chain.\n",
entity->id);
- return -EINVAL;
+ if ( chain->dev->quirks & UVC_QUIRK_IGNORE_CHAIN_ERR
) {
+ uvc_trace(UVC_TRACE_DESCR, "Found reference
to "
+ "entity %d already in chain, but "
+ "ignoring as
UVC_QUIRK_IGNORE_CHAIN_ERR is set.\n",
+ entity->id);
+ return 0;
+ }
+ else {
+ uvc_trace(UVC_TRACE_DESCR, "Found reference
to "
+ "entity %d already in chain.\n",
entity->id);
+ return -EINVAL;
+ }
}
/* Process entity */
@@ -1584,9 +1612,29 @@ static int uvc_scan_device(struct uvc_device *dev)
struct uvc_video_chain *chain;
struct uvc_entity *term;
+ struct list_head *ptr;
+ struct uvc_entity *ent;
+uvc_trace(UVC_TRACE_PROBE, "Just to see what's there, scan the list
backward (prev) first.\n");
+ for (ptr = dev->entities.prev; ptr != &dev->entities; ptr = ptr->prev)
{
+ ent = list_entry(ptr, struct uvc_entity, list);
+uvc_trace(UVC_TRACE_PROBE, "id=%d type=%d (0x%04x) name=%s prev=%p this=%p
next=%p.\n",
+ ent->id, ent->type, ent->type, ent->name, ptr->prev, ptr,
ptr->next);
+ }
+uvc_trace(UVC_TRACE_PROBE, "Backward scan completed, now start again and go
forward (next):\n");
+ for (ptr = dev->entities.next; ptr != &dev->entities; ptr = ptr->next)
{
+ ent = list_entry(ptr, struct uvc_entity, list);
+uvc_trace(UVC_TRACE_PROBE, "id=%d type=%d (0x%04x) name=%s prev=%p this=%p
next=%p.\n",
+ ent->id, ent->type, ent->type, ent->name, ptr->prev, ptr,
ptr->next);
+ }
+uvc_trace(UVC_TRACE_PROBE, "End of informational scan, we now return to
+our normal programming...\n");
+
+
list_for_each_entry(term, &dev->entities, list) {
+uvc_trace(UVC_TRACE_PROBE, "uvc_scan_device() loop: id=%d, type=%d (0x%04x)
name=%s, baSourceID=%d\n",
+ term->id, UVC_ENTITY_TYPE(term),
UVC_ENTITY_TYPE(term), term->name,
+term->baSourceID ? *(term->baSourceID) : 0 );
if (!UVC_ENTITY_IS_OTERM(term))
continue;
+uvc_trace(UVC_TRACE_PROBE, "Found OUTPUT_TERMINAL type, check if it's
+already part of a chain...\n");
/* If the terminal is already included in a chain, skip it.
* This can happen for chains that have multiple output @@
-1595,6 +1643,7 @@ static int uvc_scan_device(struct uvc_device *dev)
*/
if (term->chain.next || term->chain.prev)
continue;
+uvc_trace(UVC_TRACE_PROBE, "Terminal is not part of a chain, so
+allocate memory and init+scan a new chain...\n");
chain = kzalloc(sizeof(*chain), GFP_KERNEL);
if (chain == NULL)
@@ -1927,6 +1976,8 @@ static int uvc_probe(struct usb_interface *intf,
if (uvc_ctrl_init_device(dev) < 0)
goto error;
+uvc_trace(UVC_TRACE_PROBE, "About to scan uvc device: %s, intfnum:
+%d.\n", dev->name, dev->intfnum); uvc_trace(UVC_TRACE_PROBE, "Will scan
+dev->entities: (next: %p, prev: %p).\n", dev->entities.next,
+dev->entities.prev);
/* Scan the device for video chains. */
if (uvc_scan_device(dev) < 0)
goto error;
diff --git a/drivers/media/usb/uvc/uvcvideo.h
b/drivers/media/usb/uvc/uvcvideo.h
index 816dd1a..2f83287 100644
--- a/drivers/media/usb/uvc/uvcvideo.h
+++ b/drivers/media/usb/uvc/uvcvideo.h
@@ -152,6 +152,7 @@
#define UVC_QUIRK_RESTRICT_FRAME_RATE 0x00000200
#define UVC_QUIRK_RESTORE_CTRLS_ON_INIT 0x00000400
#define UVC_QUIRK_FORCE_Y8 0x00000800
+#define UVC_QUIRK_IGNORE_CHAIN_ERR 0x00001000
/* Format flags */
#define UVC_FMT_FLAG_COMPRESSED 0x00000001
-------------- next part --------------
A non-text attachment was scrubbed...
Name: dmesg.log.x02
Type: application/octet-stream
Size: 71120 bytes
Desc: not available
------------------------------
----------------------------------------------------------------------------
--
------------------------------
_______________________________________________
Linux-uvc-devel mailing list
Linux-uvc-***@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-uvc-devel
End of Linux-uvc-devel Digest, Vol 46, Issue 8
**********************************************
------------------------------------------------------------------------------