Reputation: 3797
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.
SetupDiGetClassDevs(&GUID_CLASS_USB_DEVICE,...)
SetupDiGetDeviceInterfaceDetail()
CreateFile()
on device path to get handle to the device.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.
Upvotes: 5
Views: 5660
Reputation: 1441
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:
CreateFile()
callDeviceIoControl(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
bNumberOfPorts
call DeviceIoControl(hubInterfaceHandle, IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME, ...)
to get unique DriverKey
of device connected to this port.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.
Upvotes: 1