Author Topic: USB HID Raw Report Descriptor  (Read 13257 times)

kevinfodor

  • Member
  • ***
  • Posts: 2
USB HID Raw Report Descriptor
« on: August 11, 2011, 05:16:14 pm »

Hello,

I am writing a small Windows based utility (using Eclipse/MinGW) which needs to request from a HID device the raw report descriptor. From my understanding, I will need to perform a GET_DESCRIPTOR(0x06) request from the devices's interface using a control transfer.

The request I want to make is essentially what I believe is the followng USB request;

SetupPacket:
0000: 81 06 00 22 00 00 60 00

In response I would like to get the raw HID report descriptor data which for this device is;

TransferBuffer: 0x00000020 (32) length
0000: 06 52 ff 09 01 a1 01 09 01 15 80 25 7f 95 40 75
0010: 08 81 02 09 01 15 80 25 7f 95 40 75 08 91 02 c0

In fact I see this transaction when Windows enumerates the device. What I want to do is to be able to make my own user-space request for the HID's raw report descriptor.

I have been able to accomplish this using libusb without problems. For instance if I do the following this gives me the results I want;

        // Get report descriptor from USB control channel
        ret = usb_control_msg(hdev, USB_ENDPOINT_IN | USB_TYPE_STANDARD
                        | USB_RECIP_INTERFACE, USB_REQ_GET_DESCRIPTOR,
            (USB_DT_REPORT << 8), iInterface, pHidReptDesc, HidReptDescLen,
            timeout);


However I do not want to be tied down to having to install the filter driver (or require anyone to install it) to do so. So instead I am hoping to use the APIs available from the WinDDK.

The best information I have found on the WinDDK involves using the IOCTL_USB_USER_REQUEST and submitting a USBUSER_OP_SEND_RAW_COMMAND. However I am not able to get this code to work.

{
   PUSB_SEND_RAW_COMMAND_PARAMETERS getDescriptor;
   PUSBUSER_REQUEST_HEADER requestHeader;
   BOOL success;
   ULONG nBytes;
   ULONG nBytesReturned;
   UCHAR getDescriptorBuf[sizeof(USBUSER_REQUEST_HEADER)
         + sizeof(USB_SEND_RAW_COMMAND_PARAMETERS) + 0x80];
   nBytes = sizeof(getDescriptorBuf);

   requestHeader = (PUSBUSER_REQUEST_HEADER) getDescriptorBuf;
   getDescriptor = (PUSB_SEND_RAW_COMMAND_PARAMETERS) (requestHeader + 1);

   memset(requestHeader, 0, nBytes);
   requestHeader->UsbUserRequest = USBUSER_OP_SEND_RAW_COMMAND;
   requestHeader->RequestBufferLength = nBytes;

   getDescriptor->Usb_bmRequest = 0x81;
   getDescriptor->Usb_bRequest = 0x6; //GET_DESCRIPTOR;
   getDescriptor->Usb_wVlaue = (USB_HID_REPORT_TYPE << 8) | 0;
   getDescriptor->Usb_wIndex = 0;
   getDescriptor->Usb_wLength = 0x80;

   // Not sure how to set these...
   getDescriptor->Timeout = 0;
   getDescriptor->DataLength = 0;
   getDescriptor->DeviceAddress = 0;
   getDescriptor->MaximumPacketSize = 0;
   getDescriptor->UsbdStatusCode = 0;

   HexDump(stdout, NULL, getDescriptor, 8);

   success = DeviceIoControl(hHCDevice, IOCTL_USB_USER_REQUEST, requestHeader,
         nBytes, requestHeader, nBytes, &nBytesReturned, NULL);

   if (!success)
   {
      DWORD osErr;
      osErr = GetLastError();
      Printf("USER_REQUEST: result=%d, lasterr=%08x\n", osErr, osErr);
   }
   HexDump(stdout, NULL, getDescriptorBuf, sizeof(getDescriptorBuf));
   return success;
}

Although the call to DeviceIoControl() returns TRUE, I get nothing in return and I see nothing on the USBTrace analyzer.

I have also tried to use the IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION command but I have discovered that this forces the bmRequest field to 0x80, when I need 0x81.

Is there a better method to obtain a USB HID device's raw report descriptor?

Thanks in advance for any help you can offer.
Kevin


FYI, Below is some additional specific information about an example HID device I am trying to do this with.

Device Descriptor:
bcdUSB:             0x0200
bDeviceClass:         0x00
bDeviceSubClass:      0x00
bDeviceProtocol:      0x00
bMaxPacketSize0:      0x40 (64)
idVendor:           0x22B8 (Motorola PCS)
idProduct:          0x08A0
bcdDevice:          0x3728
iManufacturer:        0x00
iProduct:             0x02
0x0409: "Motorola S9-HD"
iSerialNumber:        0x00
bNumConfigurations:   0x01

ConnectionStatus: DeviceConnected
Current Config Value: 0x01
Device Bus Speed:     Full
Device Address:       0x0D
Open Pipes:              1

Endpoint Descriptor:
bEndpointAddress:     0x81  IN
Transfer Type:   Interrupt
wMaxPacketSize:     0x0010 (16)
bInterval:            0x01

Configuration Descriptor:
wTotalLength:       0x0022
bNumInterfaces:       0x01
bConfigurationValue:  0x01
iConfiguration:       0x00
bmAttributes:         0x80 (Bus Powered )
MaxPower:             0x64 (200 mA)

Interface Descriptor:
bInterfaceNumber:     0x00
bAlternateSetting:    0x00
bNumEndpoints:        0x01
bInterfaceClass:      0x03 (HID)
bInterfaceSubClass:   0x00
bInterfaceProtocol:   0x00
iInterface:           0x00

HID Descriptor:
bcdHID:             0x0100
bCountryCode:         0x00
bNumDescriptors:      0x01
bDescriptorType:      0x22
wDescriptorLength:  0x0020

Endpoint Descriptor:
bEndpointAddress:     0x81  IN
Transfer Type:   Interrupt
wMaxPacketSize:     0x0010 (16)
bInterval:            0x01



Jan Axelson

  • Administrator
  • Frequent Contributor
  • *****
  • Posts: 3033
    • Lakeview Research
Re: USB HID Raw Report Descriptor
« Reply #1 on: August 11, 2011, 05:34:12 pm »
The Windows HID API provides the HIDP_CAPS and related APIs for learning about reports:

http://msdn.microsoft.com/en-us/library/ms894902.aspx

I don't know of any API function for retrieving the raw descriptor.

Jan

kevinfodor

  • Member
  • ***
  • Posts: 2
Re: USB HID Raw Report Descriptor
« Reply #2 on: August 12, 2011, 10:31:54 am »
Jan,

Thanks for replying so quickly.

Yes, I will take a closer look at the HIDP_CAPS structure again.

Initially I used your book as a guide (for finding and parsing HIDs) using the HidP_xxx and HidD_xxx APIs. I had great luck with this. Able to find, and get reports easily from the device using the APIs and routines as you described them.

However when I couldn't figure out a way to get the raw report descriptor (since HidD_GetPreparsedData hides this) I started to look for alternative ways to issue my own control transfer from user-mode to eventually retrieve the raw descriptor's contents. You mentioned you don't know of any APIs to do this, so I imagine this explains why my search for a way to do this hasn't turned up anything :)

I wanted to get the raw descriptor because I need to process the HID reports on a separate device. The "key" so to speak (as you know) to interpret a HID report from a device is to have the report descriptor as it tells you everything about it. The remote system doesn't have HidD_GetPreparsedData(), nor the HidD_XXX APIs, so I am kind of on my own there.

I will look again to how I might interpret (and package) the contents of the HIDP_CAPS structure to "re-construct" the key on a remote system to independently interpreting HID reports.

Thanks again for your help!