3

I want to get the Device descriptor of USB devices on my system. I am creating a userspace application in Windows(un-managed, native c++ ). From these descriptors, I want to identify billboard devices and parse billboard capability descriptor (parsing bos descriptor).

Here is my approach.

  1. Get USB devices on a system by SetupDiGetClassDevs(&GUID_CLASS_USB_DEVICE,...)
  2. Get device path of each device using SetupDiGetDeviceInterfaceDetail()
  3. Use CreateFile() on device path to get handle to the device.
  4. Issue IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION IOCTL using DeviceIoControl(), and the handle, to get the device descriptor.

I am stuck on the 4th step (getLastError() - Invalid Function).
Other projects (like this sample code from Intel), enumerate all USB controllers on the system, root hubs, ports, and interfaces, and issue IOCTL on the root hub's handle, specifying the port number to which a device is connected.

I do not want to concern myself with the USB hierarchy of the system. It is less error-prone and easier to get USB devices in the system using setup API. However, nowhere I can see IOCTL being issued to them directly.

Update1

From learn.microsoft.com:
IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION I/O control request retrieves one or more descriptors for the device that is associated with the indicated port index. This request targets the USB hub device (GUID_DEVINTERFACE_USB_HUB). Thus this ioctl which can give me device descriptor of a USB device is meant to be handled by USB Hub, and NOT by a USB device.

Therefore the other solutions pass handle of hub to DeviceIoControl(), as can be seen on Line 68 of the source code from Intel (Linked here).

I instead want to use the handle obtained in step 3 (handle of the device) above to get the device descriptor. So, the IOCTL could be different, or possibly there is a way to get handle of the hub, and index of port to which the device is connected using the handle of the USB device.

The way I see it, device descriptor is an intrinsic property of a USB device, and therefore there must be a way to get it directly from the USB device.

Sahil Singh
  • 3,352
  • 39
  • 62
  • 1
    There must be a way to do this because the USBView utility from Microsoft shows all the USB device descriptors. It is [open source](https://github.com/Microsoft/Windows-driver-samples/tree/master/usb/usbview) so you can review its source code, and you can try out the MSYS2 package for it (`pacman -S mingw-w64-x86_64-usbview` in MSYS2). – David Grayson Jun 05 '18 at 15:21
  • I have seen source code of USBView utility, it too enumerates all hubs, controllers, ports, etc. – Sahil Singh Jun 05 '18 at 15:22
  • Still, you should be able to look at the specific parts of it that use `IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION` and make sure you are doing things the same way. – David Grayson Jun 05 '18 at 15:23
  • Anyway, it will be very hard for anyone to debug your code without seeing it in [mcve] form, so the best I can do is point to working example code out there in the universe and suggest that you copy it. – David Grayson Jun 05 '18 at 15:23
  • What exactly about the 4th step is getting you stuck? You should include a complete description of all error codes you are getting along with an MCVE. – David Grayson Jun 05 '18 at 15:24
  • I get "Invalid Function error". Updating the question with more details. – Sahil Singh Jun 05 '18 at 15:33
  • I have updated the question. If it is still needed, I will try to create a Minimal, Complete, and Verifiable example. – Sahil Singh Jun 05 '18 at 15:58
  • Thanks for updating it. I doubt you'll be able to find exactly what you are looking for, and you will actually need to open a handle to the USB hub device, and you probably can't get such a handle from a device handle. – David Grayson Jun 05 '18 at 18:44
  • 1
    I found this question. It mentions the same problems which I am facing. I will try the solutions mentioned there, and if successful, will mark this question as a duplicate. https://stackoverflow.com/questions/28007468/how-do-i-obtain-usb-device-descriptor-given-a-device-path?rq=1 – Sahil Singh Jun 06 '18 at 06:14

1 Answers1

1

Assuming you already have USB device handle first you need to get DEVPKEY_Device_Driver property string from it (by means of CM_Get_DevNode_PropertyW or SetupDiGetDevicePropertyW).

You'll receive string like {36fc9e60-c465-11cf-8056-444553540000}\0010.

Next you need to iterate over each USB hub in system (devices that have GUID_DEVINTERFACE_USB_HUB interface) and for each:

  1. Open it via CreateFile() call
  2. Call DeviceIoControl(hubInterfaceHandle, IOCTL_USB_GET_NODE_INFORMATION, ...) to get USB_NODE_INFORMATION structure that contains number of USB ports in its hubInfo.u.HubInformation.HubDescriptor.bNumberOfPorts
  3. For each port from 1 (they are one based!!!) to bNumberOfPorts call DeviceIoControl(hubInterfaceHandle, IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME, ...) to get unique DriverKey of device connected to this port.
  4. Compare DriverKey string you have on previous step with string you have from DEVPKEY_Device_Driver call. If they are same - congratulations you have found USB hub and port that have your USB device connected!

Now you can call DeviceIoControl(usbHubInterfaceHandle, IOCTL_USB_GET_NODE_CONNECTION_INFORMATION, ...) to get USB_NODE_CONNECTION_INFORMATION structure that contains USB_DEVICE_DESCRIPTOR!

Also you can additionally call DeviceIoControl(usbHubInterfaceHandle, IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, ...) with USB_DESCRIPTOR_REQUEST to get other USB descriptors in addition to basic USB_DEVICE_DESCRIPTOR.

For example code see EnumerateHubPorts() and GetDriverKeyName() in official USBView sample.

Also I just did that in my RawInputDemo repo here.

UPDATE: There is easier way to get USB device number in a parent USB HUB - just get DEVPKEY_Device_Address property from a USB devnode.

DJm00n
  • 1,083
  • 5
  • 18