繁体   English   中英

如何从 Windows 中的 USB HID 设备获取原始描述符数据?

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

如何从 Windows 中的 HID 设备获取原始描述符数据?

背景:

我需要从 Windows 中的 HID 设备获取制造商、产品名称和序列号。 我正在使用 hid.dll 使用此处看到的功能访问设备。 我的问题与这个问题非常相似。 我能够从某些 HID 设备中获取制造商字符串和产品字符串,但大多数都无法返回此数据,HidD_GetManufacturerString 返回 false。 但是,我知道这些设备的描述符中确实有字符串信息,因为我可以使用 USBTreeView看到它。

有趣的是,即使对于确实返回制造商和产品名称的设备,我通过 hid.dll 获得的值也与我使用上述工具从 USB 设备获取原始数据时看到的值非常不同。

例如,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 根本无法打开这些设备来检索这些数据,因为它们不使用 winusb.sys 驱动程序。

1) 我不明白为什么 HidD 函数返回的值与 USB 描述符中的值不匹配。 2) 我找不到任何方法来访问 HID 设备的原始 USB 描述符数据,因为我无法使用 WinUSB 访问它们。


编辑1:

好的,所以我对 HID 有了更多了解。 看来我通过 hid 获得的数据。dll 是驱动程序指定的数据,而不是来自 USB 设备的数据。 HID 也可以应用于 USB 以外的传输设备。 所以没关系。 最终,我真正想知道的是,当我拥有 HID 设备时,如何获得 USB 设备以及为此我使用什么 API。 除了不起作用的WinUSB,我唯一能找到的是内核级函数IOCTL。 我不知道这是否适合普通的非管理员应用程序。

我终于找到了解决方案。 主要问题只是将HID设备与其父USB设备相关联。 这是基本过程:

假设您已经拥有HID设备和SP_DEVINFO_DATA:

  1. 枚举所有USB设备,如此处所示
  2. 使用CM_GetChild和CM_GetSibling查找USB设备的所有子代。
  3. 将已知的HID设备的实例句柄(SP_DEVINFO_DATA-> DevInst)与CM函数返回的每个子设备的实例句柄进行比较,以确定哪个USB设备是父设备。
  4. 从那里,您可以获得想要的任何USB信息,包括描述符。

我在这里做到了。 您需要记住很多事情——比如复合 USB 设备支持。 主要算法是这样的:

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);

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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