Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 3 of 3

Thread: Teensy, USB and Extended Configuration Descriptor

Hybrid View

  1. #1

    Teensy, USB and Extended Configuration Descriptor

    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:

    This specific code is reached when the USB device is a composite device with an Interface Association Descriptor (IAD) ( and an Extended Configuration Descriptor (ECD) (

    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.

  2. #2
    Senior Member PaulStoffregen's Avatar
    Join Date
    Nov 2012
    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:

    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".

    // 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?

  3. #3
    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 ( and USBLyzer ( 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.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts