How Operation System obtain Hardware ID - windows

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.

Related

Multiple devices on mdio bus

I have multiple devices on MDIO bus (one AR8035 PHY, and 6 DP83849IFVS dual PHYs). The bus is connected to AM335x SoC with linux 4.14.40. Davinchi_mdio scans bus and finds all devices and attaches driver I think for AR8035. How can I access this bus via mdio? I want to write stand-lone (not PHY driver) kernel module, that can simply access mdio bus? How can I do that? I wanted to do that with phy_write/phy_read but I can't get struct phy_device* from my kernel module. How can I get struct phy_device* from the name of the interface ("eth0"). Will it be safe in terms of locks/mutaxes?
If you already have an subsystem for MDIO controller, then I can think of implementing an UIO driver for MDIO interface, which deals with read and write.
UIO driver is safe when compared to the messy kernel driver and complete control will be with the user application which uses that UIO.
**
*Each UIO device is accessed through a device file and several sysfs attribute files. The device file will be called /dev/uio0 for the first device, and /dev/uio1, /dev/uio2 and so on for subsequent devices.
/dev/uioX is used to access the address space of the card. Just use mmap() to access registers or RAM locations of your card.
Interrupts are handled by reading from /dev/uioX. A blocking read() from /dev/uioX will return as soon as an interrupt occurs.*
**

How do WINDOWS func kernel drivers communicate with actual hardware?

So I understand that a kernel driver sits on top of HW device and then to communicate with the device via user space you will need to talk to the kernel driver via CreateFile && Read && Write. I have seen the design of Window's kernel drivers and their sample codes whether it is a USB or PCI or...
Now what I want to understand is how does the kernel drive communicate with the hardware? Where is the driver code would we usually find the code responsible for reading/writing registers on a certain device? What does the driver need to communicate with the device? I was told it is the BAR0 value that maps the HW to the virtual memory area which means any address we want to access on a physical device would start at that address. Is that correct? what If I have BAR0 = 0xfc500000, do i have to find addresses of certain register on the device and then ad it as an offset?
Driver need to get HW Resources from the OS. in a PCI device example, you will get MMIO Address and the interrupt vector. the MMIO Address is a physical address the PCI Controller and the BIOS map the device too.
the driver gets this value in EvtPepareHardware callback (in KMDF) and then need to map it to kernel Virtual address using MmMapIoSpace().
once you get a kernel Virtual address theoretically it is a "pointer" to the HW memory space and you can access the registers as you wish.
but it is recommended to use the HAL macros to void caching and other issues to access that memory. e.g. READ_REGISTER_ULONG64
to find the address of a registers you the Hardware device spec
for more info read this "Reading and Writing to Device Registers"

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 eth0 only actual interface in Linux

I am confuse among various interfaces of ethernet .I am just going through this U-Boot Link
http://www.denx.de/wiki/DULG/UBootEnvVariables
Where it says
ethaddr: Ethernet MAC address for first/only ethernet interface (= eth0 in Linux).
Now my confusion is eth0 is only real interface whose address is programmed into efuse register
Is other interfaces like eth1 ,eth2 and so on virtula interface which will be configured by applcation later on .
Also from this link
http://e2e.ti.com/support/arm/sitara_arm/f/791/t/209421.aspx
Where it says
The MAC addresses programmed into the internal e-fuses will be from the TI address pool. Customer will need to add some type of storage device (Flash, EEPROM) which contains their MAC addresses if they want to use addresses from their own address pool.
Now are these two mac address one written in e-fuse and other in Flash by customer two different address for eth0?
This uboot documentation is for many different kinds of hardware, some of which have only 1 interface, and some of which have more. The language "Ethernet MAC address for first/only ethernet interface (= eth0 in Linux)" just means that referenced variable is for eth0, which is the first ethernet interface. If there is only one interface, it is still called eth0. If your hardware has multiple ethernet interfaces, the other variables are for them.
Regarding the second question: it appears that this hardware device has a built-in ethernet controller, which needs a unique MAC address to function on a network. The device ships with a MAC address already configured (written into the e-fuse of the device, and therefore read-only). If you don't want to use that MAC address, you can instead use flash or EEPROM to store your own MAC address to configure the ethernet controller. Only one of those choices will be active.
One reason you might want to change the MAC address is that MAC addresses are assign in blocks to different vendors, and the shipped address is from the TI block. That means network analyzers will think the overall product is a TI device. If you want your product to appear as a different vendor, you need to use your own MAC address drawn from your own pool. If you don't know what this means, don't worry about it: use the one that is preconfigured and built-in.

How does windows identify a USB device uniquely?

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

Resources