Teensy, USB and Extended Configuration Descriptor

Status
Not open for further replies.

poxyran

Member
Hi All,

taking into account the advices that @PaulStoffregen gave me in my first post, I'll try to explain in details what I'm trying to do.

Using a Teensy ++ 2.0 I'm trying to write a program to reach a specific code in a Windows Driver. Actually, I'm starting with this code: https://github.com/avivgr/teensy_uvc

This specific code is reached when the USB device is a composite device with an Interface Association Descriptor (IAD) (http://msdn.microsoft.com/en-us/library/windows/hardware/ff540054(v=vs.85).aspx) and an Extended Configuration Descriptor (ECD) (http://www.google.com/patents/US7093031).

The code I pointed is "emulating" a MS LifeCam and has a IAD but it doesn't have an ECD.

I don't know how to start adding this new descriptor to the existing code (if is possible) so that is the first question. I assume you have to define a struct with the ECD header and then the specific device config but then what? Is this ECD going to be after the default config descriptor? Do I need to add code to process that descriptor? where? which are the steps to process that descriptor?. I read that an OS String descriptor (OSSD) has to be processed together with the ECD, where this OSSD has to be located?.

To be honest, I'm a little bit lost. I'm not a regular user of Teensy, I just use it for specific tasks and that's the reason of my post :)

I think I gave all the necessary information for you to understand what I'm trying to do but if you need more info just ask me.

Thanks in advance.
 
The good news is you can edit the code to send pretty much any USB descriptors.

The bad news is you have to edit the code, which isn't as simple as normal Arduino coding, and it's even more challenging if you're also unsure of exactly what descriptor data you need to send. So the first obvious step is to try to get a good list of the exact binary data for the descriptors, before jumping into the code.

For Teensy++ 2.0, the code is in a few different directories, depending on the setting in Tools > USB Type. For example, with USB Type set to Serial, hardware/teensy/cores/usb_serial is used. You can turn on verbose output while compiling in File > Preferences, to see the exact compiler commands. Looking at the full pathnames in those commands can help you get a clear idea of which code is actually being used.

USB descriptors are just binary data, which Teensy sends when the PC asks. Inside usb.c, you'll find several arrays, like this:

Code:
static const uint8_t PROGMEM device_descriptor[] = {
        18,                                     // bLength
        1,                                      // bDescriptorType
        0x00, 0x02,                             // bcdUSB
        2,                                      // bDeviceClass
        0,                                      // bDeviceSubClass
        0,                                      // bDeviceProtocol
        ENDPOINT0_SIZE,                         // bMaxPacketSize0
        LSB(VENDOR_ID), MSB(VENDOR_ID),         // idVendor
        LSB(PRODUCT_ID), MSB(PRODUCT_ID),       // idProduct
        0x00, 0x01,                             // bcdDevice
        1,                                      // iManufacturer
        2,                                      // iProduct
        3,                                      // iSerialNumber
        1                                       // bNumConfigurations
};

Editing the bytes is easy... if you know what data you need to send.

If you need to add an entirely new descriptor, just add another array for its data, and then add it to "descriptor_list".

Code:
// This table defines which descriptor data is sent for each specific
// request from the host (in wValue and wIndex).
static const struct descriptor_list_struct {
        uint16_t        wValue;
        uint16_t        wIndex;
        const uint8_t   *addr;
        uint8_t         length;
} PROGMEM descriptor_list[] = {
        {0x0100, 0x0000, device_descriptor, sizeof(device_descriptor)},
        {0x0200, 0x0000, config1_descriptor, sizeof(config1_descriptor)},
        {0x0300, 0x0000, (const uint8_t *)&string0, 4},
        {0x0301, 0x0409, (const uint8_t *)&string1, sizeof(STR_MANUFACTURER)},
        {0x0302, 0x0409, (const uint8_t *)&string2, sizeof(STR_PRODUCT)},
        {0x0303, 0x0409, (const uint8_t *)&string3, sizeof(STR_SERIAL_NUMBER)}
};
#define NUM_DESC_LIST (sizeof(descriptor_list)/sizeof(struct descriptor_list_struct))

The last 2 parameters are just the name of your array and its size, in bytes.

The first 2 tell the code when to send it. The PC reqests different descriptors by placing different codes into wValue and wIndex. Can you find more info about descriptors and wIndex, wValue and other stuff in the USB spec, chapter 9.

In principle, USB descriptors are just chunk of binary data that identify features. In practice, a lot of different options exist within that data. Especially Windows can be quite challenging to figure out why things don't work. But hopefully this info about how to do stuff on the Teensy side helps a bit?
 
Hi Paul!,

thanks for taking time to answer!.

I'll play a little bit with those arrays to see if I can trigger the specific code.

Btw, what do you use to sniff the descriptors?. Currently, I'm using USBCap (desowin.org/usbpcap) and USBLyzer (www.usblyzer.com) but I'm not sure if it is possible for those applications to get all the descriptors. I'm sarting thinking that they are missing some of them.
 
Status
Not open for further replies.
Back
Top