This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TM4C123GE6PM: Conflicting USB comp. dev. documentation

Part Number: TM4C123GE6PM
Other Parts Discussed in Thread: EK-TM4C1294XL

Hello,

I have to functioning USB projects for the 123GX launchpad and I'm trying to take these two USB projects and combine them into a composite device.  After a few days of reading the documentation and usblib source code I've run into what looks like conflicting information - or I just got confused.

I see here that the usblib users guide says you need to support 3x strings which makes sense (shown below):

But when I look at the source code it requires more than this.  See below.

    //
    //! A pointer to the string descriptor array for this device.  This array
    //! must contain the following string descriptor pointers in this order.
    //! Language descriptor, Manufacturer name string (language 1), Product
    //! name string (language 1), Serial number string (language 1), Composite
    //! device interface description string (language 1), Configuration
    //! description string (language 1).
    //!
    //! If supporting more than 1 language, the descriptor block (except for
    //! string descriptor 0) must be repeated for each language defined in the
    //! language descriptor.
    //!
    //
    const uint8_t * const *ppui8StringDescriptors;

    //
    //! The number of descriptors provided in the ppStringDescriptors
    //! array.  This must be 1 + ((5 + (number of strings)) *
    //!                           (number of languages)).
    //
    const uint32_t ui32NumStringDescriptors;

The above user's guide screenshot and source code snippet are referring to a section of the composite device structure (found in usbdcomp.h) shown below:

complete structure source found in usbdcomp.h

//*****************************************************************************
//
//! The structure used by the application to define operating parameters for
//! the composite device class.
//
//*****************************************************************************
typedef struct
{
    //
    //! The vendor ID that this device is to present in the device descriptor.
    //
    const uint16_t ui16VID;

    //
    //! The product ID that this device is to present in the device descriptor.
    //
    const uint16_t ui16PID;

    //
    //! The maximum power consumption of the device, expressed in mA.
    //
    const uint16_t ui16MaxPowermA;

    //
    //! Indicates whether the device is self or bus-powered and whether or not
    //! it supports remote wake up.  Valid values are \b USB_CONF_ATTR_SELF_PWR
    //! or \b USB_CONF_ATTR_BUS_PWR, optionally ORed with
    //! \b USB_CONF_ATTR_RWAKE.
    //
    const uint8_t ui8PwrAttributes;

    //
    //! A pointer to the callback function which will be called to notify
    //! the application of events relating to the operation of the composite
    //! device.
    //
    const tUSBCallback pfnCallback;

    //
    //! A pointer to the string descriptor array for this device.  This array
    //! must contain the following string descriptor pointers in this order.
    //! Language descriptor, Manufacturer name string (language 1), Product
    //! name string (language 1), Serial number string (language 1), Composite
    //! device interface description string (language 1), Configuration
    //! description string (language 1).
    //!
    //! If supporting more than 1 language, the descriptor block (except for
    //! string descriptor 0) must be repeated for each language defined in the
    //! language descriptor.
    //!
    //
    const uint8_t * const *ppui8StringDescriptors;

    //
    //! The number of descriptors provided in the ppStringDescriptors
    //! array.  This must be 1 + ((5 + (number of strings)) *
    //!                           (number of languages)).
    //
    const uint32_t ui32NumStringDescriptors;

    //
    //! The number of devices in the psDevices array.
    //
    const uint32_t ui32NumDevices;

    //
    //! This application supplied array holds the the top level device class
    //! information as well as the Instance data for that class.
    //
    tCompositeEntry * const psDevices;

    //
    //! The private data for this device instance.  This memory must remain
    //! accessible for as long as the composite device is in use and must
    //! not be modified by any code outside the composite class driver.
    //
    tCompositeInstance sPrivateData;
}
tUSBDCompositeDevice;

Questions:

1. Should I just follow the comments in the structure source code for string desc pointer which says the following are required {language desc, manf name string, product name str, serial num string, composite dev interface desc string, configuration desc string}?  I ask because this is more than the user's guide says to have. 

2. So what format are the strings supposed to be in?  An example of the hid string descriptors are shown below.  Should I copy and paste these and just change the contents for the composite strings?

//*****************************************************************************
//
// The languages supported by this device.
//
//*****************************************************************************
const uint8_t g_pui8LangDescriptor[] =
{
    4,
    USB_DTYPE_STRING,
    USBShort(USB_LANG_EN_US)
};

//*****************************************************************************
//
// The manufacturer string.
//
//*****************************************************************************
const uint8_t g_pui8ManufacturerString[] =
{
    (17 + 1) * 2,
    USB_DTYPE_STRING,
    'T', 0, 'e', 0, 'x', 0, 'a', 0, 's', 0, ' ', 0, 'I', 0, 'n', 0, 's', 0,
    't', 0, 'r', 0, 'u', 0, 'm', 0, 'e', 0, 'n', 0, 't', 0, 's', 0,
};

//*****************************************************************************
//
// The product string.
//
//*****************************************************************************
const uint8_t g_pui8ProductString[] =
{
    (19 + 1) * 2,
    USB_DTYPE_STRING,
    'G', 0, 'e', 0, 'n', 0, 'e', 0, 'r', 0, 'i', 0, 'c', 0, ' ', 0, 'B', 0,
    'u', 0, 'l', 0, 'k', 0, ' ', 0, 'D', 0, 'e', 0, 'v', 0, 'i', 0, 'c', 0,
    'e', 0
};
//*****************************************************************************
//
// The data interface description string.
//
//*****************************************************************************
const uint8_t g_pui8DataInterfaceString[] =
{
    (19 + 1) * 2,
    USB_DTYPE_STRING,
    'B', 0, 'u', 0, 'l', 0, 'k', 0, ' ', 0, 'D', 0, 'a', 0, 't', 0,
    'a', 0, ' ', 0, 'I', 0, 'n', 0, 't', 0, 'e', 0, 'r', 0, 'f', 0,
    'a', 0, 'c', 0, 'e', 0
};

//*****************************************************************************
//
// The configuration description string.
//
//*****************************************************************************
const uint8_t g_pui8ConfigString[] =
{
    (23 + 1) * 2,
    USB_DTYPE_STRING,
    'B', 0, 'u', 0, 'l', 0, 'k', 0, ' ', 0, 'D', 0, 'a', 0, 't', 0,
    'a', 0, ' ', 0, 'C', 0, 'o', 0, 'n', 0, 'f', 0, 'i', 0, 'g', 0,
    'u', 0, 'r', 0, 'a', 0, 't', 0, 'i', 0, 'o', 0, 'n', 0
};

The comments in the structure almost sound like you should end up with the below pointer to pointers to these strings.

//*****************************************************************************
//
// The descriptor string table.
//
//*****************************************************************************
const uint8_t * const g_ppui8StringDescriptors[] =
{
    g_pui8LangDescriptor,
    g_pui8ManufacturerString,
    g_pui8ProductString,
    g_pui8SerialNumberString,
    g_pui8DataInterfaceString,
    g_pui8ConfigString
};

3.  For number of strings field (ppui8StringDescriptors pointer)  the structure source says the following:

    //
    //! The number of descriptors provided in the ppStringDescriptors
    //! array.  This must be 1 + ((5 + (number of strings)) *
    //!                           (number of languages)).
    //
    const uint32_t ui32NumStringDescriptors;

so what strings count towards the "number of strings" part of that equation?  All of the ones pointed to by

const uint8_t * const *ppui8StringDescriptors;

4. When passing a HID and Bulk device structure do you pass the standard structure?  I noticed the example uses buffers that I'm not using?  My two device interfaces just use the standard structs from USBLIB.  So for example my bulk device interface in my bulk project that is working just uses the following structure - I've removed the buffering support that comes with the example project.

//*****************************************************************************
//
//! The structure used by the application to define operating parameters for
//! the bulk device.
//
//*****************************************************************************
typedef struct
{
    //
    //! The vendor ID that this device is to present in the device descriptor.
    //
    const uint16_t ui16VID;

    //
    //! The product ID that this device is to present in the device descriptor.
    //
    const uint16_t ui16PID;

    //
    //! The maximum power consumption of the device, expressed in milliamps.
    //
    const uint16_t ui16MaxPowermA;

    //
    //! Indicates whether the device is self- or bus-powered and whether or not
    //! it supports remote wakeup.  Valid values are USB_CONF_ATTR_SELF_PWR or
    //! USB_CONF_ATTR_BUS_PWR, optionally ORed with USB_CONF_ATTR_RWAKE.
    //
    const uint8_t ui8PwrAttributes;

    //
    //! A pointer to the callback function which will be called to notify
    //! the application of events related to the device's data receive channel.
    //
    const tUSBCallback pfnRxCallback;

    //
    //! A client-supplied pointer which will be sent as the first
    //! parameter in all calls made to the receive channel callback,
    //! pfnRxCallback.
    //
    void *pvRxCBData;

    //
    //! A pointer to the callback function which will be called to notify
    //! the application of events related to the device's data transmit
    //! channel.
    //
    const tUSBCallback pfnTxCallback;

    //
    //! A client-supplied pointer which will be sent as the first
    //! parameter in all calls made to the transmit channel callback,
    //! pfnTxCallback.
    //
    void *pvTxCBData;

    //
    //! A pointer to the string descriptor array for this device.  This array
    //! must contain pointers to the following string descriptors in this
    //! order.  Language descriptor, Manufacturer name string (language 1),
    //! Product name string (language 1), Serial number string (language 1),
    //! Interface description string (language 1) and Configuration description
    //! string (language 1).
    //!
    //! If supporting more than 1 language, the strings for indices 1 through 5
    //! must be repeated for each of the other languages defined in the
    //! language descriptor.
    //
    const uint8_t * const *ppui8StringDescriptors;

    //
    //! The number of descriptors provided in the ppStringDescriptors array.
    //! This must be 1 + (5 * number of supported languages).
    //
    const uint32_t ui32NumStringDescriptors;

    //
    //! The private instance data for this device.  This memory must
    //! not be modified by any code outside the bulk class driver.
    //
    tBulkInstance sPrivateData;
}
tUSBDBulkDevice;

Is this ok because it looks like the user's guide example passes the CDC device with the buffers and stuff which I'm not using in my bulk example anymore.

  • Hi Robert,

    1. Should I just follow the comments in the structure source code for string desc pointer which says the following are required {language desc, manf name string, product name str, serial num string, composite dev interface desc string, configuration desc string}?  I ask because this is more than the user's guide says to have. 

    Comparing between the wordings in the user's guide for the composite device strings and the structure defined in tUSBDCompositeDevice, the difference is that the tUSBDCompositeDevice also includes descriptors for language, composite device i/f string and configuration string. 

    In the user's guide, I wonder if all other strings is referred to language, composite device i/f string and configuration string.

    This list of strings should include the following three strings in the following order: Manufacturer, Product, and Product serial
     number. All other strings used by the classes are specified and are sourced from the included
    device classes.

    I think I will follow the already defined composite device structure. 

    2. So what format are the strings supposed to be in?  An example of the hid string descriptors are shown below.  Should I copy and paste these and just change the contents for the composite strings?

    I will suggest you take a look at C:\ti\TivaWare_C_Series-2.2.0.295\examples\boards\ek-tm4c1294xl\boot_demo_usb example. This is an example for TM4C129. However, TM4C129 and TM4C123 shares the same USB library so the idea is the same. In this example, a composite device is setup for a HID class and DFU class together. 

    3.  For number of strings field (ppui8StringDescriptors pointer)  the structure source says the following:

    I hope you can use C:\ti\TivaWare_C_Series-2.2.0.295\examples\boards\ek-tm4c1294xl\boot_demo_usb\usb_hiddfu_structs.c and C:\ti\TivaWare_C_Series-2.2.0.295\examples\boards\ek-tm4c1294xl\boot_demo_usb\usb_hiddfu_structs.h as a starting point to build a composite device. 

    There is another composite device containing two CDC class devices that you maybe helpful for you as a starting point. C:\ti\TivaWare_C_Series-2.2.0.295\examples\boards\ek-tm4c1294xl\usb_dev_cserial

  • Hi Charles,

    Thanks for the example projects - I've been working through those and they are very helpful.  I did find something very interesting in the USB composite driver code which I *think* TI has hardcoded in.  I noticed in the following structure found in usbdcomp.c

    //****************************************************************************
    //
    // Device Descriptor.  This is stored in RAM to allow several fields to be
    // changed at runtime based on the client's requirements.
    //
    //****************************************************************************
    static uint8_t g_pui8CompDeviceDescriptor[] =
    {
        18,                     // Size of this structure.
        USB_DTYPE_DEVICE,       // Type of this structure.
        USBShort(0x110),        // USB version 1.1 (if we say 2.0, hosts assume
                                // high-speed - see USB 2.0 spec 9.2.6.6)
        USB_CLASS_MISC,         // USB Device Class (spec 5.1.1)
        USB_MISC_SUBCLASS_COMMON, // USB Device Sub-class (spec 5.1.1)
        USB_MISC_PROTOCOL_IAD,  // USB Device protocol (spec 5.1.1)
        64,                     // Maximum packet size for default pipe.
        USBShort(0),            // Vendor ID (filled in during USBDCompositeInit).
        USBShort(0),            // Product ID (filled in during USBDCompositeInit).
        USBShort(0x100),        // Device Version BCD.
        1,                      // Manufacturer string identifier.
        2,                      // Product string identifier.
        3,                      // Product serial number.
        1                       // Number of configurations.
    };

    There seems to be hardcoded values for an "Interface association descriptor".  The bytes of interest are the following three - {USB_CLASS_MISC, USB_MISC_SUBCLASS_COMMON, USB_MISC_PROTOCOL_IAD} which are set to {0xEF, 0x02, 0x01} respectively.

    Link to a Microsoft document describing what IADs are:

    https://github.com/MicrosoftDocs/windows-driver-docs/blob/staging/windows-driver-docs-pr/usbcon/usb-interface-association-descriptor.md

    As my application is intended to be two separate tx/rx interfaces (one interrupt/hid and one bulk) I don't think I need the IAD functionality.  Do you know why this seems to be hard coded and am I correct in assuming that if a customer wants two separate interfaces we should mod this and set to zeros?  It sounds like this would basically tie my two interfaces to the same driver - is that the intent of the usblib driver stack?

    Thanks!

  • Hi Robert,

    I did find something very interesting in the USB composite driver code which I *think* TI has hardcoded in.  I noticed in the following structure found in usbdcomp.c

    Fullscreen
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    //****************************************************************************
    //
    // Device Descriptor. This is stored in RAM to allow several fields to be
    // changed at runtime based on the client's requirements.
    //
    //****************************************************************************
    static uint8_t g_pui8CompDeviceDescriptor[] =
    {
    18, // Size of this structure.
    USB_DTYPE_DEVICE, // Type of this structure.
    USBShort(0x110), // USB version 1.1 (if we say 2.0, hosts assume
    // high-speed - see USB 2.0 spec 9.2.6.6)
    USB_CLASS_MISC, // USB Device Class (spec 5.1.1)
    USB_MISC_SUBCLASS_COMMON, // USB Device Sub-class (spec 5.1.1)
    USB_MISC_PROTOCOL_IAD, // USB Device protocol (spec 5.1.1)
    64, // Maximum packet size for default pipe.
    USBShort(0), // Vendor ID (filled in during USBDCompositeInit).
    USBShort(0), // Product ID (filled in during USBDCompositeInit).
    USBShort(0x100), // Device Version BCD.
    1, // Manufacturer string identifier.
    2, // Product string identifier.
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    There seems to be hardcoded values for an "Interface association descriptor".  The bytes of interest are the following three - {USB_CLASS_MISC, USB_MISC_SUBCLASS_COMMON, USB_MISC_PROTOCOL_IAD} which are set to {0xEF, 0x02, 0x01} respectively.

    I think 0xEF, 0x02 and 0x01 has the meaning that the class usage is defined in the interface level. I think it has the same meaning as setting the class code to 0x0 which means the class usage is defined in the interface descriptor. 

    As my application is intended to be two separate tx/rx interfaces (one interrupt/hid and one bulk) I don't think I need the IAD functionality.  Do you know why this seems to be hard coded and am I correct in assuming that if a customer wants two separate interfaces we should mod this and set to zeros?  It sounds like this would basically tie my two interfaces to the same driver - is that the intent of the usblib driver stack?

    Yes, I think you can set the Device class to 0x0 in the Device Descriptor so that usage of the devices are described in the two Interface Descriptors. Although hardcoded in the library with  {0xEF, 0x02, 0x01}, it does not prevent the interface descriptors from describing the usage of the devices. As you can see for the composite device example including a HID and DFU, it is the interface descriptors which describe a HID class and a DFU class. Therefore, I think  {0xEF, 0x02, 0x01} will have the same effect as {0x0, 0x0, 0x0}.

    Honestly, I'm learning USB while answering your question. :-)

  • Hey Charles,

    I think I'm going to have to get the 1294xl board up and running and take a protocol analyzer capture of the enumeration traffic.  My original thought was that once I got the two interfaces up and running in separate project (not sure if you remember, but I modified the usblib to handle Microsoft OS descriptors for the BULK device) I could just combine them together in the composite and they would enumerate and appear in windows together just like they did separately.  It seems there is more to the story.  

    The problem I'm having may not be due to the above post about  {0xEF, 0x02, 0x01} because I zero'd them out and still get the same exact traffic.  It looks like the composite device takes the descriptor info from the HID/BULK device info and combines it in the configuration desc.  I've captured this and all the traffic looks correct (I think) except one descriptor section that makes no sense starting with 0x09, 0x21 where the second byte is supposed to be the descriptor type ID, but 0x21 maps to no idea I can find in the USB spec.  I'll paste the raw traffic in below - you can see the on descriptor section that I can't figure out.  I'll have to work on this longer and report back.  

    /*
    * Additional helpful info for debugging desc.
    * problems.
    *
    */

    Descriptor Types (from USB spec table 9-5):
    -------------------------------------------
    Device 1
    Configuration 2
    String 3
    Interface 4
    Endpoint 5
    Device_Qualifier 6
    Other_Speed_Config 7
    Interface_Power 8


    /*
    * Initial composite device descriptor capture
    * from protocol analyzer
    *
    */


    Device desriptor for composite device - first descriptor that comes across
    ---------------------------------------------------------------
    12 // bLength
    01 // bDescriptorType
    10 01 // bcdUSB
    EF // bDeviceClass
    02 // bDeviceSubClass
    01 // bDeviceProtocol
    40 // bMaxPacketSize
    BF 1C // idVendor
    07 00 // idProduct
    00 01 // bcdDevice (release number)
    01 // iManufacturer (index of string desc)
    02 // iProduct (index of product string desc)
    03 // iSerialNumber (string index)
    01 // bNumConfigurations

    // ----> The below is all in a single descriptor transaction

    Configuration Descriptor for composite device - 2 interfaces
    ---------------------------------------------------------------
    09 // bLength
    02 // bDesc Type
    40 00 // wTotalLen
    02 // bNumInterfaces
    01 // bConfigurationValue
    00 // iConfiguration
    80 // bmAttributes
    7D // bMaxPower


    Interace descriptor for interface 0 in compoiste config descriptor
    ---------------------------------------------------------------
    09 // bLength
    04 // bDescriptor Type
    00 // bInterfaceNumber
    00 // bAlternateSetting
    02 // bNumEndpoints
    03 // bInterfaceClass
    00 // bInterfaceSubclass
    00 // bInterfaceProtocol
    00 // iInterface

    !!! Not sure what this is
    ---------------------------------------------------------------
    09
    21
    00
    02
    00
    01
    22
    20
    00

    Endpoint Desc
    --------------
    07
    05
    81
    03
    40
    00
    01

    Endpoint Desc
    --------------
    07
    05
    01
    03
    40
    00
    01

    Interace descriptor for interface 1 in compoiste config descriptor
    ---------------------------------------------------------------
    09
    04
    01
    00
    02
    FF
    00
    00
    00

    Endpoint Desc
    --------------
    07
    05
    82
    02
    40
    00
    00

    Endpoint Desc
    --------------
    07
    05
    02
    02
    40
    00
    00

  • !!! Not sure what this is
    ---------------------------------------------------------------
    09
    21
    00
    02
    00
    01
    22
    20
    00

    Hi Robert,

      I don't know what this is. The only thing that makes sense is the first byte which indicates 9 bytes for the descriptor. It is likely a corrupted interface descriptor but I'm not sure. Normally, there is only one device descriptor per device which is 18 (0x12) bytes.  For most use cases, there is normally one configuration descriptor. The endpoint descriptor is also 7 bytes in your capture. That leaves this 9 bytes extra descriptor in a no-man's land. 

    Configuration Descriptor for composite device - 2 interfaces
    ---------------------------------------------------------------
    09 // bLength
    02 // bDesc Type
    40 00 // wTotalLen
    02 // bNumInterfaces
    01 // bConfigurationValue
    00 // iConfiguration
    80 // bmAttributes
    7D // bMaxPower

    I think your configuration descriptor may be worth investigating. If you look at the wTotalLen. It is shown as 40 00. I'm not sure if I should interpret this as 0x4000 (16384) or 0x0040 (64). Most likely it means 64 bytes. If it is 64 bytes, it is supposed to include the combined length of all descriptors (configuration, interface, endpoint, and class or vendor specific) returned for this configuration. Is it really 64 bytes when you add all the descriptors together? If I don't count the weird descriptor then there are only 55 bytes. If I count the weird descriptor then there are 64 bytes. 

    Configuration Desc (9) + Interface 0 Desc (9) + Endpoint Desc (7) + Endpoint Desc (7) + Interface 1 Desc (9) + Endpoint Desc (7) + Endpoint Desc (7) = 55.

    Configuration Desc (9) + Interface 0 Desc (9) + Weird Desc (9) + Endpoint Desc (7) + Endpoint Desc (7) + Interface 1 Desc (9) + Endpoint Desc (7) + Endpoint Desc (7) = 64.

    I will suggest you find out how the 64 byte is calculated for the TotalLength. Hopefully this will lead you to the origin of the weird descriptor. 

  • Hi Charles,

    So I figured out what was going on.  I needed to define the interface in the Microsoft OS compatible ID string descriptor to point to the second interface (interface 1) and it was pointing to interface 0.  I also had to set the USB version to 2.0.  It was set to 1.1 by default in the usblib.  

    I've now gotten my two interfaces in my composite device up and running at least form device manager's point of view.  I did however notice that my second interface (bulk) doesn't have the bulk string descriptors with it.  The bulk interface shows up as a device (as expected with usbccgp.sys driver) but with the composite device descriptors.  Does the composite device driver for usblib intend to throw away the bulk string descriptors?  It is kind of a problem because you have these additional interfaces described by the composite device strings which is misleading.  

    I also noticed that the traffic in the setup transaction is different for the composite descriptors vs where I think the bulk descriptors for this second interface would go.

    Composite descriptor setup token request:

    radix: hexadecimal
    80 06 02 03
    09 04 1C 00

    Where I think the bulk (interface #2) string descriptor request is happening:

    radix: hexadecimal
    80 06 02 03
    09 04 02 08

    So long story short my issue was 2x fold - the usbVersion in the normal descriptors for the device and the MS OS compatible feature descriptor interface pointer field.

    Thanks for your help! 

  • Oh! One other thing I wanted to run by you.  When setting up the interfaces for a composite device you setup the typical structures for a "device" like HID or bulk etc... then pass those to the composite device driver that merges them then puts them on the bus.

    In the individual data structures for the stand-alone devices which become the interfaces of the composite device, there are callbacks for RX / TX etc...  So for example HID has a handler for traffic, connect, disconnect etc... and so do the other structures passed to the composite device.  In the driverlib composite device example they use the same callback for the CDC devices.  This is fine, but what if you have two totally different interfaces on the composite device?  Do the individual callbacks (say for HID and bulk) get called respectively?  So for HID traffic does the HID callback handler/ISR handler get called and the same for bulk?  Almost like the callbacks/ISR handlers for traffic still operate as if they are individual devices?

    Said differently, what would happen with the example in the driverlib documentation if the two CDC structures needed to have different callback handlers instead of using the same one?

  • Do the individual callbacks (say for HID and bulk) get called respectively?  So for HID traffic does the HID callback handler/ISR handler get called and the same for bulk?  Almost like the callbacks/ISR handlers for traffic still operate as if they are individual devices?

    Hi Robert,

      I think so. In the C:\ti\TivaWare_C_Series-2.2.0.295\examples\boards\ek-tm4c1294xl\boot_demo_usb\boot_demo_usb.c example, there is callback for each individual device. In this example, there is a HID class and a DFU class device.