简体   繁体   中英

How do you get the raw descriptor data from a USB HID device in Windows?

How do you get the raw descriptor data from a HID device in Windows?

Background:

I need to get the Manufacturer, Product Name, and Serial Number from a HID device in Windows. I'm using hid.dll to access the devices using the functions seen here . My question is very similar to this one . I am able to get the manufacturer string and product string from SOME HID devices, but most fail to return this data with HidD_GetManufacturerString returning false. However, I KNOW these devices do have the string information in their descriptors because I am able to see it using USBTreeView .

The interesting thing is, even for the devices that do return manufacturer and product names, the values I'm getting through hid.dll are very different from the values I see using the above tool which gets the raw data from the USB device.

For example, an Xbox 360 controller:

Via USB Tree View:
Device Description       : Xbox 360 Controller for Windows
Language 0x0409          : "©Microsoft Corporation"
iProduct                 : 0x02
Language 0x0409          : "Controller"
iSerialNumber            : 0x03
Language 0x0409          : "0843806"

Via hid.dll using HidD_GetManufacturerString, HidD_GetProductString, and HidD_GetSerialNumberString:
Description              : HID-compliant game controller
Product                  : Controller (XBOX 360 Controller for Windows)
Manufacturer             : FAILS
Serial Number            : FAILS

WinUSB is unable to open these devices at all to retrieve this data as they do not use the winusb.sys driver.

1) I don't understand why the values returned by the HidD functions do not match the values in the USB descriptor. 2) I can't find any way to access the raw USB descriptor data for a HID device because I cannot access them with WinUSB.


Edit 1:

Okay, so I've learned a bit more about HID. It seems the data I'm getting through hid.dll is driver-specified data, not data coming from the USB device. HID can apply to devices on transports other than USB as well. So that's fine. Ultimately, what I really want to know is how can I get the USB device when I have the HID device and what API do I use for that. Besides WinUSB which doesn't work, the only thing I can find are kernel-level functions IOCTL. I don't know if that's suitable for a normal, non admin application.

I finally found the solution. The main problem was just associating a HID device to its parent USB device. This is the basic process:

Assuming you already have the HID device and the SP_DEVINFO_DATA for it:

  1. Enumerate all USB devices as seen here .
  2. Find all children of the USB devices with CM_GetChild and CM_GetSibling.
  3. Compare the known HID device's instance handle (SP_DEVINFO_DATA->DevInst) with each child device's instance handle that was returned by the CM functions to determine which USB device is the parent.
  4. From there, you can get any USB info you want including the descriptor.

I did that here . There was a bunch of things you need to keep in mind - like composite USB device support. Main algo was something like this:

m_DeviceInterfacePath = SearchParentDeviceInterface(hidDeviceInstanceId, &GUID_DEVINTERFACE_USB_DEVICE);
m_DeviceInstanceId = GetDeviceFromInterface(m_DeviceInterfacePath);

DEVINST devNodeHandle = OpenDevNode(m_DeviceInstanceId);

// open handle to wake up device from S3 suspend state
ScopedHandle usbInterfaceHandle = OpenDeviceInterface(m_DeviceInterfacePath);

// device index in parent USB hub
// https://docs.microsoft.com/windows-hardware/drivers/ddi/wdm/ns-wdm-_device_capabilities#usb
m_UsbPortIndex = PropertyDataCast<ULONG>(GetDevNodeProperty(devNodeHandle, &DEVPKEY_Device_Address, DEVPROP_TYPE_UINT32));

std::vector<std::string> usbDeviceCompatibleIds = PropertyDataCast<std::vector<std::string>>(GetDevNodeProperty(devNodeHandle, &DEVPKEY_Device_CompatibleIds, DEVPROP_TYPE_STRING_LIST));
for (const std::string& usbCompatibleId : usbDeviceCompatibleIds)
{
    stringutils::ci_string tmp(usbCompatibleId.data(), usbCompatibleId.size());
    // https://docs.microsoft.com/windows-hardware/drivers/usbcon/enumeration-of-the-composite-parent-device
    if (tmp.find("USB\\COMPOSITE") == stringutils::ci_string::npos)
        continue;

    // Its Composite USB device
    // Need to acquire interface number in parent USB device
    // https://docs.microsoft.com/windows-hardware/drivers/usbcon/usb-common-class-generic-parent-driver
    m_UsbCompositeDeviceInstanceId = GetParentDevice(hidDeviceInstanceId);
    if (!GetInterfaceNumber(m_UsbCompositeDeviceInstanceId, m_UsbInterfaceNumber))
    {
        // Try again
        m_UsbCompositeDeviceInstanceId = GetParentDevice(m_UsbCompositeDeviceInstanceId);
        if (!GetInterfaceNumber(m_UsbCompositeDeviceInstanceId, m_UsbInterfaceNumber))
        {
            DBGPRINT("UsbDevice: cannot get interface number");
            return;
        }
    }
    break;
}

std::string usbHubInterface = SearchParentDeviceInterface(m_DeviceInstanceId, &GUID_DEVINTERFACE_USB_HUB);

if (usbHubInterface.empty())
    return;

ScopedHandle hubInterfaceHandle = OpenDeviceInterface(usbHubInterface, true);

USB_DEVICE_DESCRIPTOR deviceDescriptor;
if (!GetDeviceDescriptor(hubInterfaceHandle, m_UsbPortIndex, deviceDescriptor))
    return;

m_VendorId = deviceDescriptor.idVendor;
m_ProductId = deviceDescriptor.idProduct;
m_VersionNumber = deviceDescriptor.bcdDevice;

// Assume that we are always using first configuration
const UCHAR configurationIndex = 0;
if (!GetFullConfigurationDescriptor(hubInterfaceHandle, m_UsbPortIndex, configurationIndex, m_ConfigurationDescriptor))
    return;

// Search for interface descriptor
PUSB_INTERFACE_DESCRIPTOR interfaceDescriptor = nullptr;
if (!SearchInterfaceDescriptor(m_ConfigurationDescriptor, m_UsbInterfaceNumber, interfaceDescriptor))
    return;

std::wstring stringBuffer;
// Get the array of supported Language IDs, which is returned in String Descriptor 0
if (!GetDeviceString(hubInterfaceHandle, m_UsbPortIndex, 0, 0, stringBuffer))
    return;

// Use first supported language
USHORT languageID = stringBuffer[0];
if (GetDeviceString(hubInterfaceHandle, m_UsbPortIndex, deviceDescriptor.iManufacturer, languageID, stringBuffer))
    m_Manufacturer = utf8::narrow(stringBuffer);

// Get interface name instead of whole product name, if present
UCHAR productStringIndex = interfaceDescriptor->iInterface ? interfaceDescriptor->iInterface : deviceDescriptor.iProduct;
if (GetDeviceString(hubInterfaceHandle, m_UsbPortIndex, productStringIndex, languageID, stringBuffer))
    m_Product = utf8::narrow(stringBuffer);

if (GetDeviceString(hubInterfaceHandle, m_UsbPortIndex, deviceDescriptor.iSerialNumber, languageID, stringBuffer))
    m_SerialNumber = utf8::narrow(stringBuffer);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM