locked
Microsoft OS 2.0 Descriptors not working on an interface of a composite USB device RRS feed

  • Question

  • Hello.  I am trying to evaluate Microsoft OS 2.0 Descriptors to see if I should use them in my next USB project.  I am having trouble getting these descriptors to work for interface 0 on a composite device under Windows 8.1 64-bit.  I have read both the Microsoft OS 1.0 descriptors specification and the Microsoft OS 2.0 descriptors specification, which are available here:

    https://msdn.microsoft.com/en-us/library/windows/hardware/ff537430

    For testing, I have implemented a simple USB composite device according to the Interface Association Descriptors ECN (class = 0xEF, subclass = 0x02, protocol = 0x01).  The device has one configuration and two generic (vendor defined) interfaces.  I have written a Microsoft OS 2.0 Descriptor Set that should do three things:

    1) Make a registry property called "Happy" for the overall device.
    2) Assign a compatible ID of "WINUSB" to interface 0 of configuration 1.
    3) Assign a registry property called "DeviceInterfaceGUIDs" for interface 0 of configuration 1.

    I can tell from my Beagle USB 12 Protocol Analyzer that the Windows 8.1 machine is fetching this descriptor set.  I can also see the "Happy" property being correctly created in the "Device Parameters" for the overall device, so I know that Windows had some amount of success parsing the descriptor set.

    This is the structure of my OS 2.0 descriptor set:

    Header
      Registry Property: "Happy", REG_MULTI_SZ with some arbitrary data
      Subset header for configuration 1
        Subset header for interface 0
          Compatible ID: WINUSB
          Registry Property: "DeviceInterfaceGUIDs", REG_MULTI_SZ with some arbitrary data

    It is important to note that I was able to get Microsoft OS 2.0 descriptors working on a non-composite device that just has one interface.  To adjust the Microsoft OS 2.0 Descriptor Set for that test, I simply removed the two subset headers and I adjusted the length fields accordingly.  (I also changed the Device and Configuration descriptors accordingly.)  When I did that, everything worked fine: both registry properties and the compatible ID were correctly applied to the top-level USB device, and the WinUSB driver loaded.

    Also, I was able to get Microsoft OS 1.0 Descriptors to work for the composite device, allowing WinUSB to load on interface 0, and assigning a Device Interface GUID.

    I tried adding interface association descriptors (IADs) for each of the two interfaces in the composite device.  The IADs I added just associated each interface to itself; they did not associate the two interfaces together.  Adding the IADs did not help.

    Details about how I reproduced the problem:

    My device is based on the CC2511F32 microcontroller, and you can see the code (including all the descriptors) here:

    https://gist.github.com/DavidEGrayson/a3f2fd5a90ba5a390628

    1) I plugged the device into my Windows 8.1 64-bit computer using a USB 3.0 port.
    2) I compiled and loaded that code onto the device.
    3) In the Device Manager, I uninstalled both interfaces of the device and the parent device itself, to make Windows forget what it knows about the device.
    4) With regedit.exe, I deleted the key HKLM\SYSTEM\CurrentControlSet\Control\usbflags\1FFBDA020002.
    5) I unplugged the device and plugged it back in, while recording the packets on the bus using my Beagle USB 12 Protocol Analyzer.  The trace from the protocol analyzer is available here: http://www.davidegrayson.com/keep/usb_150604/trace_composite_1.tdc  If you want to, you can view that trace using free software from Total Phase: http://www.totalphase.com/products/data-center/
    6) In that trace, I see that the Device Descriptor, Configuration Descriptor, BOS descriptor, and Microsoft OS 2.0 Descriptor Set are all being transferred to the computer without problems.
    7) In regedit.exe, I can see that the "HKLM\SYSTEM\CurrentControlSet\Enum\USB\VID_1FFB&PID_DA01\F5-AA-66-6A\Device Parameters" key has a property named "Happy", with the correct value of ["3","5"] so I know that Windows was able to successfully read that part of my Microsoft OS 2.0 Descriptor Set.
    8) In the Device Manager, I see that the USB Composite Device has been set up correctly and it is using usbccgp.sys.  However, the other interfaces are not recognized and have a yellow triangle around them.  Here is a screenshot: http://www.davidegrayson.com/keep/usb_150604/composite_devmgmt.png
    9) I opened "USB Test Device A Interface 0", looked at its "Compatible Ids", and verified that "USB\MS_COMP_WINUSB" is NOT present.  Its only compatible IDs are: "USB\Class_ff&SubClass_00&Prot_00", "USB\Class_ff&SubClass_00", and "USB\Class_ff".
    10) I looked at the Device Instance Path of interface 0 (USB\VID_1FFB&PID_DA01&MI_00\6&11A23516&17&0000) and used that to find its registry key.  Under "Device Parameters" I do not see the DeviceInterfaceGUIDs property specified by my descriptors; all I see is "ExtPropDescSemaphore" (a REG_DWORD with a value of 1).

    These results suggest that there is something wrong with my Microsoft OS 2.0 Descriptor Set.  Since that descriptor set was able to work on a non-composite device with minimal modification, it seems especially likely that there is a problem in my Configuration Subset subset or Function Subset headers, but I have checked them carefully.  If you want to help me check them, here is the C source code for my descriptor set (edited slightly for clarity):

    #define MS_OS_20_SET_HEADER_DESCRIPTOR 0x00
    #define MS_OS_20_SUBSET_HEADER_CONFIGURATION 0x01
    #define MS_OS_20_SUBSET_HEADER_FUNCTION 0x02
    #define MS_OS_20_FEATURE_COMPATIBLE_ID 0x03
    #define MS_OS_20_FEATURE_REG_PROPERTY 0x04
    
    #define MS_OS_20_DESCRIPTOR_LENGTH 0xD2
    
    XDATA uint8 msOs20DescriptorSet[MS_OS_20_DESCRIPTOR_LENGTH] =
    {
        // Microsoft OS 2.0 Descriptor Set header (Table 10)
        0x0A, 0x00,  // wLength
        MS_OS_20_SET_HEADER_DESCRIPTOR, 0x00,
        0x00, 0x00, 0x03, 0x06,  // dwWindowsVersion: Windows 8.1 (NTDDI_WINBLUE)
        MS_OS_20_DESCRIPTOR_LENGTH, 0x00,
    
        // Microsoft OS 2.0 registry property descriptor (Table 14)
        0x20, 0x00,   // wLength
        MS_OS_20_FEATURE_REG_PROPERTY, 0x00,
        0x07, 0x00,   // wPropertyDataType: REG_MULTI_SZ
        0x0C, 0x00,   // wPropertyNameLength
        'H',0,'a',0,'p',0,'p',0,'y',0,0,0,
        0x0A, 0x00,   // wPropertyDataLength
        '3',0,0,0,'5',0,0,0,0,0,
    
        // Microsoft OS 2.0 configuration subset (Table 11)
        0x08, 0x00,  // wLength of this header
        MS_OS_20_SUBSET_HEADER_CONFIGURATION, 0x00,  // wDescriptorType
        1,           // bConfigurationValue
        0x00,        // bReserved
        0xA8, 0x00,  // wTotalLength of this subset
    
        // Microsoft OS 2.0 function subset header (Table 12)
        0x08, 0x00,  // wLength
        MS_OS_20_SUBSET_HEADER_FUNCTION, 0x00,  // wDescriptorType
        0,           // bFirstInterface
        0x00,        // bReserved,
        0xA0, 0x00,  // wSubsetLength
    
        // Microsoft OS 2.0 compatible ID descriptor (Table 13)
        0x14, 0x00,                                      // wLength
        MS_OS_20_FEATURE_COMPATIBLE_ID, 0x00,            // wDescriptorType
        'W', 'I', 'N', 'U', 'S', 'B', 0x00, 0x00,        // compatibleID
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  // subCompatibleID
    
        // Microsoft OS 2.0 registry property descriptor (Table 14)
        0x84, 0x00,   // wLength
        MS_OS_20_FEATURE_REG_PROPERTY, 0x00,
        0x07, 0x00,   // wPropertyDataType: REG_MULTI_SZ
        0x2a, 0x00,   // wPropertyNameLength
        'D',0,'e',0,'v',0,'i',0,'c',0,'e',0,'I',0,'n',0,'t',0,'e',0,'r',0,
        'f',0,'a',0,'c',0,'e',0,'G',0,'U',0,'I',0,'D',0,'s',0,0,0,
        0x50, 0x00,   // wPropertyDataLength
        '{',0,'9',0,'9',0,'c',0,'4',0,'b',0,'b',0,'b',0,'0',0,'-',0,
        'e',0,'9',0,'2',0,'5',0,'-',0,'4',0,'3',0,'9',0,'7',0,'-',0,
        'a',0,'f',0,'e',0,'e',0,'-',0,'9',0,'8',0,'1',0,'c',0,'d',0,
        '0',0,'7',0,'0',0,'2',0,'1',0,'6',0,'3',0,'}',0,0,0,0,0,
    };

    Here is a hex dump of the descriptor set as recorded by the protocol analyzer:

    0A 00 00 00 00 00 03 06 D2 00 20 00 04 00 07 00
    0C 00 48 00 61 00 70 00 70 00 79 00 00 00 0A 00
    33 00 00 00 35 00 00 00 00 00 08 00 01 00 01 00
    A8 00 08 00 02 00 00 00 A0 00 14 00 03 00 57 49
    4E 55 53 42 00 00 00 00 00 00 00 00 00 00 84 00
    04 00 07 00 2A 00 44 00 65 00 76 00 69 00 63 00
    65 00 49 00 6E 00 74 00 65 00 72 00 66 00 61 00
    63 00 65 00 47 00 55 00 49 00 44 00 73 00 00 00
    50 00 7B 00 39 00 39 00 63 00 34 00 62 00 62 00
    62 00 30 00 2D 00 65 00 39 00 32 00 35 00 2D 00
    34 00 33 00 39 00 37 00 2D 00 61 00 66 00 65 00
    65 00 2D 00 39 00 38 00 31 00 63 00 64 00 30 00
    37 00 30 00 32 00 31 00 36 00 33 00 7D 00 00 00
    00 00

    Questions I have:

    * What should I do to make Microsoft OS 2.0 Descriptors apply to interface 0 on my composite device?
    * Can Microsoft OS 2.0 Descriptors actually apply to an interface of a composite device in practice?  Is that a feature that is supposed to work in Windows 8.1?
    * Can anyone verify that my Microsoft OS 2.0 Descriptor Set is encoded correctly?
    * What is the meaning of the MsOs20Flags property that I see in the registry under "Device Parameters"?  I have observed it having values of 0x0b, 0x4b, and 0x63.  I assume it's a binary bitmap but I don't know what the bits mean, and maybe it would help me debug my problem.
    * How can I get messages about the BOS descriptor from the Microsoft Message Analyzer?  The instructions from this blog post seems to be written for an older version of the tool, and the filters they suggest end up filtering out 100% of the events in my capture.
    * Does anyone have a working example of Microsoft OS 2.0 Descriptors applying to a single interface?  If I can start with a working example and slowly modify it to suit my needs, I should be able to figure out what I did wrong.  I could not find any examples online.
    * Is there any more information I should post?

    Thanks!


    --David Grayson




    Thursday, June 4, 2015 8:34 PM

Answers

  • It looks like we'll need to update the MSOS 2.0 Descriptor docs to match the implementation in USBCCGP.  The bConfigurationValue in the configuration subset header should actually just be an index value, not the configuration value.

     

    Specifically it's the index value passed to GET_DESCRIPTOR to retrieve the configuration descriptor. 

     

    Try changing the value to 0 and see if that resolves the issue.  Sorry for the confusion.

    Friday, June 5, 2015 12:41 AM

All replies

  • It looks like we'll need to update the MSOS 2.0 Descriptor docs to match the implementation in USBCCGP.  The bConfigurationValue in the configuration subset header should actually just be an index value, not the configuration value.

     

    Specifically it's the index value passed to GET_DESCRIPTOR to retrieve the configuration descriptor. 

     

    Try changing the value to 0 and see if that resolves the issue.  Sorry for the confusion.

    Friday, June 5, 2015 12:41 AM
  • Thanks, everything works now!  I definitely agree that you should update the documentation, and I would also argue that you should name the field something other than bConfigurationValue, since that name is used unambiguously in the USB 2.0 specification to mean something else.  Thanks for the fast response.


    --David Grayson


    Friday, June 5, 2015 5:07 PM