1
\$\begingroup\$

I am currently programming a USB device on a STM32F7 microcontroller. This is a simple HID device (basic desktop mouse).

When plugging the device to the host (windows 10 computer), the USB transaction works as expected until the GET HID REPORT DESCRIPTOR request.

  1. Plugging the device to the computer
  2. The host resets the device, and asks for the Device Descriptor
  3. The device replies with the correct device descriptor.
  4. The host receives the Endpoint 0 MAXPACKETSIZE, and resets the device.
  5. The host sends a SET_ADDRESS request, the device sets its address accordingly.
  6. The host asks for the full device descriptor. The device replies by sending it.
  7. The host asks for the configuration descriptor, the device sends it.
  8. The host sends a SET_CONFIGURATION request, the device process it.
  9. The host sends a SET_IDLE request, the device process it.
  10. The host sends a GET HID REPORT DESCRIPTOR request, but it asks for more data than it was specified in the Configuration Descriptor. My device replies by sending the correct descriptor, but as its length is lower than the size asked by the host, this latter does not accept it.

Here is my full configuration descriptor:

const USB_ConfigurationDescriptorsPackage configuration_0_descriptors = {
        .configuration_descriptor = {
                .bLength                = sizeof(USB_ConfigurationDescriptor),
                .bDescriptorType        = USB_DESCRIPTOR_TYPE_CONFIGURATION,
                .wTotalLength           = sizeof(USB_ConfigurationDescriptorsPackage),
                .bNumInterfaces         = 1,        // only one interface (group of endpoints) needed for our application
                .bConfigurationValue    = 1,        // only one configuration, so index 1
                .iConfiguration         = 0,        // index 0 means that there is no string descriptor
                .bmAttributes           = (0x80),       // not(0x20) so no remote wake up, (not 0x40) --> bus powered; 0x80 --> required by the USB specification
                .bMaxPower              = 25        // our device will draw / require 2mA * 25 = 50 mA
        },

        .interface_descriptor = {
                .bLength                = sizeof(USB_InterfaceDescriptor),
                .bDescriptorType        = USB_DESCRIPTOR_TYPE_INTERFACE,
                .bInterfaceNumber       = 1,
                .bAlternateSetting      = 0,
                .bNumEndpoints          = 1,        // only one (IN) endpoint required / activated for our application
                /* in the USB Device Descriptor, we told the host that our class will be defined at interface level,
                 * so we define it here. */
                .bInterfaceClass        = USB_CLASS_HID,
                .bInterfaceSubClass     = USB_SUBCLASS_NONE,        // no interface subclass here
                .bInterfaceProtocol     = USB_PROTOCOL_NONE,        // no interface specific protocol here
                .iInterface             = 0                         // no string descriptor for our device
        },

        .endpoint_descriptor = {
                .bLength                = sizeof(USB_EndpointDescriptor),
                .bDescriptorType        = USB_DESCRIPTOR_TYPE_ENDPOINT,
                .bEndpointAddress       = (0x80 | 0x03),        // IN endpoint number 3 (can be chosen arbitrary)
                .bmAttributes           = USB_ENDPOINT_TYPE_INTERRUPT,
                .wMaxPacketSize         = 64,
                .bInterval              = 50
        },

        /* HID descriptor for a mouse */
        .hid_descriptor = {
                .bLength                    = sizeof(USB_HID_Descriptor),
                .bDescriptorType            = USB_DESCRIPTOR_TYPE_HID,
                .bcdHID                     = 0x0100,                       // first version of HID specification
                .bCountryCode               = USB_HID_COUNTRY_NONE,
                .bNumDescriptors            = 1,                            // only 1 HID report descriptor associated with this HID descriptor
                .bDescriptorType0           = USB_DESCRIPTOR_TYPE_HID_REPORT,
                .wDescriptorLength0         = sizeof(hid_report_descriptor)
        },
};

In the HID field, sizeof(hid_report_descriptor) = 48 bytes, which is the correct size of my HID report descriptor.

However, for an unknown reason, when in the GET HID REPORT DESCRIPTOR request, the host asks for a 112 bytes data length packet, instead of 48 bytes i.e. an extra 64 bytes.

I've tracked the USB communication on wireshark, to check that my device was sending the data it is expected to send. So I know that my device is doing what it is intended to.

Here's the trace on wireshark:

enter image description here

The detailed configuration descriptor sends by my device:

enter image description here

The detailed GET HID REPORT DESCRIPTOR request sent by the host:

enter image description here

As you can see, the device sends the correct configuration descriptor and specifies the host that the HID report descriptor is 48 bytes wide. But when the host asks for this descriptor, it asks for 112 bytes instead of 48. I have no idea why ...

Thank you for your help.

EDIT: I've checked with different descriptor sizes,and there is Always an extra 64 bytes, regardless the descriptor size. As this number is 64, it is probably not random. But I don't see to what it may be related.

\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

See section 8.5.3.2 of the USB 2.0 Specification:

A control pipe may have a variable-length data phase in which the host requests more data than is contained in the specified data structure. When all of the data structure is returned to the host, the function should indicate that the Data stage is ended by returning a packet that is shorter than the MaxPacketSize for the pipe. If the data structure is an exact multiple of wMaxPacketSize for the pipe, the function will return a zero-length packet to indicate the end of the Data stage.

This should be automatically handled by the USB library/hardware of your controller.

Windows probably does this to work around some broken HID device that specifies a descriptor size that is too small.

\$\endgroup\$
3
  • \$\begingroup\$ oh thank you very much,!!. then it seems that I've got an other problem. Perhaps the Report Descriptor is wrong ? I mean, the device returns the value it is expected to send as per the code, but the values themselves in the code could be the problem \$\endgroup\$
    – Wheatley
    Oct 15, 2022 at 16:11
  • \$\begingroup\$ There is no problem. \$\endgroup\$
    – CL.
    Oct 15, 2022 at 17:08
  • \$\begingroup\$ well, the host does not accept this descriptor, as it keeps sending the GET DESCRIPTOR HID request, it doesn't go the next step when it asks for the report itself. On wireshark I've noticed that the status of the transaction when the device sends the descriptor is USBD_STATUS_CANCELED 0xc0010000 \$\endgroup\$
    – Wheatley
    Oct 15, 2022 at 17:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.