The more I dig into USB descriptors the more confused I get...
I'm working on a multi-channel USB audio device (6-mic/2-spkr).
I started walking through the entire set of descriptors as they exist
in usb_device_composite_hid_audio_unified_lite, comparing them to the
USB specification. The goal simply to understand the construction of
each descriptor so I can modify them as needed. Right at the top I find
a stumbling point...
According to section 4.2 of the spec ("USB Device Class Definition for
For both composite devices and audio-only devices, the device descriptor
must indicate that class information is to be found at the interface
level. Therefore, the bDeviceClass, bDeviceSubClass and bDeviceProtocol
fields of the device descriptor must contain the values 0xEF, 0x02, and
0x01 respectively so that enumeration software looks down at the interface
level to determine the Interface Class and to also ensure that IAD-aware
enumeration software gets loaded.
But, when I look at the descriptor in usb_device_descriptor.c, it uses
USB_DEVICE_CLASS, USB_DEVICE_SUBCLASS & USB DEVICE_PROTOCOL
all of which are #defines set to zero. The output of "lsusb -v" of my
device plugged into a Linux box shows:
Bus 001 Device 023: ID 1fc9:00a4 NXP Semiconductors
bDeviceClass 0 (Defined at Interface level)
So it appears to be doing what the spec says, however its not using
the values mentioned in the spec (0xEF, 0x02, 0x01). Further, when I
change those three values to match the spec lsusb seems confused...
Bus 001 Device 027: ID 1fc9:00a4 NXP Semiconductors
bDeviceClass 239 Miscellaneous Device
bDeviceSubClass 2 ?
bDeviceProtocol 1 Interface Association
And I have problems with my running application. Can anyone
explain what I am missing? Is anyone aware of any "USB Audio"
forums that would deal with these kinds of questions?
I couldn’t find any forum that’s focused to USB Audio at this level, and there seems to be little troubleshooting information on this regard.
It seems that the descriptor on the SDK example uses Device Class as 0 to simplify things, as an actual implementation would ideally require using the classes defined by the USB-IF (which again, ironically, do not have a public forum or communities to inquiry about these matters)
The 0xEF, 0x02, 0x01 values would be correct for the Interface Association Descriptor, which from what I understand would allow to have one descriptor describing two or more interfaces that are associated with a single device function. For example, a data interface and a control interface.
It could be that the example on the SDK do not use this feature and thus switching to the IAD configuration leads to problems when Linux enumerate the device.
Application Note 11018 (link below) is not using an i.MXRT but it may help if you are working with Audio. (Their descriptor does use the device class as 0XEF)
Hi @gusarambula ,
Thanks for your detailed reply.
I will have to experiment with the IAD till I make things work; because apparently the device descriptor should be set to 0xEF, 0x02, 0x01. If/when I get it working I will post back to resolve this...
I can confirm that 0xef, 0x02, 0x01 is an Interface Association Descriptor, which is commonly used (and needed) when USB-CDC with multiple VCOM interfaces is used. It allows multiple interfaces to be defined in a composite device which are in turn made up of their own multiple interfaces.
The Interface Association Descriptor can also be used when only one interface is used, although it is a bit redundant in that case.
0x00, 0x00, 0x00 is used to specify that the class is specified at the interface level (as you know).
Although very simple in comparison to your required configuration I have attached a diagram showing the configuration that I have recently used for a stereo ultrasonic microphone which helps with general audio class construction understanding.
In the case of a more complicated device with multiple audio interfaces the device level would use an Interface Association Descriptor instead and then there would be multiple interfaces configurations (like a tree under the configuration descriptor), each with its own Interface Association Descriptor. Each branch in itself is then in fact simple since it is describing just one item as in the single item case in the diagram.
I don't now about the specification extract since I have seen typical USB audio parts (like Logitec headset) using the 0,0,0 so it maybe shouldn't take it too literally. On the other hand, as noted for USB-CDC, one can always use an IAD at the device level if one wants to be finicky as it doesn't hurt either.
Personally I find the USB specs difficult to interpret since you already need to understand how the class in question works before it starts to make sense and find it most intuitive to record the enumeration of existing (quality) references and copy it - then do some educated guesses at why they are doing some of the things they do and change them to suit - depending on the effect the guess was close and if not try something else until the operation is suitable. At the end go back to the specs (which finally start to become partly understandable) to clear up anything that may work but not be fully according to the guides.
USB device and host developer for the uTasker project
I've got most of the snippets of this project working individually, soon I have to merge them into one composite device; hence my reason for starting with the composite unified audio example. My hardware is just one 6-in/8-out codec, but I have to configure it to look like a 6 channel mic array running in parallel with a simple speaker-phone type device with echo cancellation and noise reduction. So one of the mic channels will be pulling double duty running as the nth channel of the mic array, but also feeding into an echo canceller.
This is my first USB device (aside from being my first '1060) project, so its been interesting to say the least. Similar to your comments below, I just read some, and attempt some code, then re-read some and change some code, and the iterations continue. I figure about the time I finish this I'll understand the puzzle pieces the way I should have at the start.
Thanks for the diagram, I will take a look and reply if needed...