如何通过直接在设备上执行DeviceIoControl()来获取USB设备描述符?

时间:2018-06-05 13:21:27

标签: windows winapi usb ioctl deviceiocontrol

我想在我的系统上获取USB设备的设备描述符。我正在Windows中创建一个用户空间应用程序(un-managed,native c ++)。从这些描述符中我想识别广告牌设备,并解析广告牌功能描述符(解析bos描述符)。

这是我的方法。

  1. SetupDiGetClassDevs(&GUID_CLASS_USB_DEVICE,...)
  2. 在系统上获取USB设备
  3. 使用SetupDiGetDeviceInterfaceDetail()
  4. 获取每台设备的设备路径
  5. 在设备路径上使用CreateFile()来获取设备的句柄。
  6. 问题IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION IOCTL使用DeviceIoControl()和句柄来获取设备描述符。
  7. 我被困在第4步(getLastError() - Invalid Function) 其他项目(like this sample code from Intel),枚举系统上的所有USB控制器,根集线器,端口和接口,并在根集线器的句柄上发出IOCTL,指定设备连接的端口号。

    我不想关心系统的USB层次结构。 它不易出错,并且使用安装API更容易在系统中获取USB设备。然而,我无法直接向他们发出IOCTL。

    Update1

    来自docs.microsoft.com
    IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION I / O控制请求检索与指示的端口索引相关联的设备的一个或多个描述符。此请求 定位到USB集线器设备 (GUID_DEVINTERFACE_USB_HUB)。因此,这个能给我USB设备设备描述符的ioctl意味着由USB Hub处理,而 NOT 则由USB设备处理。

    因此,其他解决方案将集线器的句柄传递给DeviceIoControl(),这可以从英特尔(Line 68)的源代码Linked here上看到。

    我想要使用上面步骤3中获得的句柄(设备句柄)来获取设备描述符。因此,IOCTL可能不同,或者可能有一种方法来处理集线器,以及使用USB设备的句柄连接设备的端口索引。

    我看到它的方式,设备描述符是USB设备的固有属性,因此必须有一种方法直接从USB设备获取它。

1 个答案:

答案 0 :(得分:1)

假设您首先已经拥有 USB 设备句柄,您需要从中获取 DEVPKEY_Device_Driver 属性字符串(通过 CM_Get_DevNode_PropertyWSetupDiGetDevicePropertyW)。

您将收到类似 {36fc9e60-c465-11cf-8056-444553540000}\0010 的字符串。

接下来,您需要遍历系统中的每个 USB 集线器(具有 GUID_DEVINTERFACE_USB_HUB 接口的设备)和每个:

  1. 通过 CreateFile() 调用打开它
  2. 调用 DeviceIoControl(hubInterfaceHandle, IOCTL_USB_GET_NODE_INFORMATION, ...) 以获取 USB_NODE_INFORMATION 结构,该结构在其 hubInfo.u.HubInformation.HubDescriptor.bNumberOfPorts 中包含多个 USB 端口
  3. 对于从 1(它们是基于一个的!!!)到 bNumberOfPorts 的每个端口,调用 DeviceIoControl(hubInterfaceHandle, IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME, ...) 以获得连接到该端口的设备的唯一 DriverKey
  4. 将上一步中的 DriverKey 字符串与 DEVPKEY_Device_Driver 调用中的字符串进行比较。如果它们相同 - 恭喜您找到了连接 U​​SB 设备的 USB 集线器和端口!

现在您可以调用 DeviceIoControl(usbHubInterfaceHandle, IOCTL_USB_GET_NODE_CONNECTION_INFORMATION, ...) 来获取包含 USB_NODE_CONNECTION_INFORMATIONUSB_DEVICE_DESCRIPTOR 结构!

此外,您还可以使用 USB_DESCRIPTOR_REQUEST 调用 DeviceIoControl(usbHubInterfaceHandle, IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, ...) 以获取除基本 USB_DEVICE_DESCRIPTOR 之外的其他 USB 描述符。

示例代码参见官方 USBView sample 中的 EnumerateHubPorts()GetDriverKeyName()

我也是在我的 RawInputDemo repo here 中这样做的。