How does windows identify a USB device uniquely? - windows

How does windows identify a USB device uniquely, even though the device data supplied from the USB device is common to all devices of that make ?
To state this alternatively, Windows can distinguish between two instances of Dell keyboards of same model, without the keyboard supplying any unique serial number. What is the exclusive data field windows searches for when initializing the USB device ?

Windows uses Device Instance ID for identification. As you can see in the documentation it contains a device part and an instance part.
The device part is taken from a USB device.
It is up to a bus driver how to generate the instance part. The bus driver cannot solely rely on the information returned from the usb device. Because two identical devices will break the system - Device Instance IDs must be unique! So usually it appends additional info - port number and etc (the exact algorithms is unknown and depends on driver manufacturer). Also PNP manager can add more uniqueness to the Instance ID.

When we connect a device to the host the device, enumeration process will happen, At the end of this process, the host will supply a unique address to the newly connected device. So each device connected to the system will have a unique Id which is supplied by the system, using this id devices can be identified and the communication happens

Related

How Operation System obtain Hardware ID

I am recently read documentation about Windows-Driver-Model, one of a chapter of it says :
Before a driver is installed for a new device, the bus or hub driver to which the device is connected assigns a hardware identifier (ID) to the device.
But how ??
For example the OS want to communicate with a USB device.
How can it ( the os ) obtain the hardware-id of the device ?
Is there some kind of protocol to communicate with the hardware that works like :
The OS send a signal ( or USB formatted message ) with a body of such as "I want to know hardware-id"
The hardware must response to this message to OS with a body of such as "My hardware-id is xxx"
If there is a protocol like this, could you please told me the "standard" of such a protocol.
On most modern computers every USB hub is connected to one xHCI controller (https://wiki.osdev.org/EXtensible_Host_Controller_Interface). At boot the BIOS will build ACPI tables in RAM that the OS will look for in conventional positions. Once the OS finds these tables, it will look at every entry to determine what devices are plugged to the computer including xHCI controllers. As stated on osdev.org
All xHCI controllers will have a Class ID of 0x0C, a Sublcass ID of 0x03, and an Interface value of 0x30. The configuration space for this device will contain two Base Address Registers: BAR0 and BAR1. These two 32-bit address fields combine to create a single 64-bit address that points to the base address of the memory mapped registers for the controller.
The memory mapped register of the xHCI s are then used to send commands to the USB device including commands to get the device descriptor of the USB device. The document on https://www.intel.com/content/dam/www/public/us/en/documents/technical-specifications/extensible-host-controler-interface-usb-xhci.pdf is the spec for the xHCI. So if you want to really understand how it works under the hood then this is a great place to look at.

How to find serial number of USB serial adapter, given the COM port?

I want to get from a Windows COM port name (COM11) to the serial number of the USB device that provides that COM port (I'm presently working with FTDI adapters, if that matters).
I can use SetupDiGetClassDevs(&GUID_DEVCLASS_PORTS, NULL, NULL, DIGCF_PRESENT) to enumerate the ports on the system, then I can use SetupDiEnumDeviceInfo and SetupDiGetDeviceRegistryProperty to get the vid/pid out of the Hardware ID.
But I can't seem to figure out a way to get hold of the serial number.
The objective is to program the serial adapters with serial numbers that identify their usage for a simulator program we've got (so the user doesn't have to figure out which adapter is which COM port).
You can try using SetupDiGetDeviceInstanceId to get the Device Instance ID of USB device, which should be a string of the form USB\VID_xxxx&PID_xxxx\[ID]. If your USB device is not composite, then [ID] would be the serial number. This is how libusbp obtains the serial number of a USB device.
If your device is composite, the serial port would be a child device and you would have to go up one level to find the parent that represents the actual USB device, which should have the device instance ID that you care about.
Before writing any code, I'd recommend checking the Device Instance ID in your Device Manager, where it is known as "Device Instance Path".
To make you feel somewhat better about extracting the serial number from a string that has other information, the Device Instance ID is documented by Microsoft here:
https://learn.microsoft.com/en-us/windows-hardware/drivers/install/device-instance-ids

How to get USB device descriptor by doing DeviceIoControl() directly on the device?

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.
Get USB devices on a system by SetupDiGetClassDevs(&GUID_CLASS_USB_DEVICE,...)
Get device path of each device using SetupDiGetDeviceInterfaceDetail()
Use CreateFile() on device path to get handle to the device.
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.
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:
Open it via CreateFile() call
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
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.
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.

Is there a way to determine if two IOHIDDeviceRef belong to same device?

I have two HID device references on Mac OS (IOHIDDeviceRef). How to determine if they are pointing to same physical device?
Bonus points:
What properties can be used to identify device if it was reconnected or new device.
For each of the HID device references, call IOHIDDeviceGetService to retrieve the IOService reference. Each IOService instance (technically, instances of its superclass IORegistryEntry) has a unique "Entry ID" which can be queried via IORegistryEntryGetRegistryEntryID(). If the Entry ID matches on the two io_service_t objects corresponding to the HID device references, then they refer to the same device.
Disconnecting and reconnecting will change the Entry ID, so you won't be able to tell if it's the same device that was connected previously via this method. If the underlying USB or bluetooth device has a serial number, you may be able to use that in combination with vendor and product IDs etc.

How can I get specific information about the serial (COM) port in Windows?

Since I have dozens of virtual serial (COM) ports installed and the half of them are Bluetooth devices, I'd like to know what port belong to what device and whether it's connecting directly or via Bluetooth.
So in particular I'm not interested in the trivial enumeration of all serial ports, which would only reveal a list of 'COM' + the corresponding number, but the real name of that device and probably its device ID (where information can be found about whether this is connecting via USB or Bluetooth.
While I could get these information via WMI, there are a plenty of problems related to this method. In particular it's bloody slow, but also it does only list connected devices (except for Bluetooth devices, that can potentially be connected and are shown regardless of a real connection)
I'd prefer a solution written in Delphi / Object Pascal, but any other language is also fine for me (the WMI access code was copied from C#).
If you use a programming language/API that can read the registry, check the subtree HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum.
This has subkeys containing device type, device class, instance ID. Each Instance ID has a subkey Device Parameters\PortName that has the COM name.
For example, on my system
ACPI\PNP0501\1\Device Parameters\PortName = COM1
BTHENUM\{GUID}{ID}\Device Parameters\PortName = COM4
The keys in the ID Part have additional information, for example
ACPI\PNP0501\1\FriendlyName = Kommunikationsanschluss (COM1) (german windows)
ACPI\PNP0501\1\Service = Serial
BTHENUM\{GUID}{ID}\Service = BTHMODEM
Use regedit to check for yourself which parts are interesting to you. But this should give you all information you need.

Resources