On any PC where USB host controller is connected to the PCI/PCIE bus I see the following:

$ cat /sys/bus/usb/devices/usb1/{idVendor,idProduct,manufacturer,product,serial}
Linux 4.14.157-amd64-x32 ehci_hcd
EHCI Host Controller

I.e. the EHCI host controller, which in this example has the PCI device position 0000:00:1a.0, is represented with a bogus set of string descriptors and vendor/product identifiers. Looking up the vendor id 1d6b in usb.ids I find that it corresponds to Linux Foundation. (lsusb lists it as "Linux Foundation 2.0 root hub".) But the PCI device referenced by the serial is real and has the following properties:

$ cat /sys/bus/pci/devices/0000:00:1a.0/{vendor,device}

Looking these ids up in pci.ids we can find that it's Intel 8 Series/C220 Series Chipset Family USB EHCI (the same as lspci would say). A real piece of hardware from a real HW manufacturer.

So why does Linux represent this Intel hardware with some strange set of ids? I do realize that PCI and USB vendor/product ids may collide, so it wouldn't be possible to start the USB device tree with ids from PCI namespace. But why the string descriptors?

My guess is that this is because the whole USB entity named "*HCI Host Controller" is a fictitious one. But on the other hand, it appears to have an address (always =1), which is never assigned to a newly-connected device on this bus. So it looks like there might be something real about this USB entity. But this reserved address might also be just a way of bookkeeping.

Is my guess correct? Is the host controller—as a USB entity—entirely fictitious? Does it never appear as an actual addressable device on the wire? Or is there something real to it, something we could actually send standard USB requests to, and not have their processing simply emulated by the kernel?

  • It seems the whole thing is emulated by the code in linux/drivers/usb/core/hcd.c. I still don't quite understand sure why it's needed to present this as a USB device and do the emulation.
    – Ruslan
    Nov 15, 2020 at 18:19
  • Are there any news on this question? I'm struggling with the same question, trying to understand the linux USB stack. My platform also lists two xHCI Host Controller from linux...
    – SeVe
    Sep 26, 2022 at 12:10
  • @SeVe see the answer
    – Ruslan
    Sep 26, 2022 at 14:13

1 Answer 1


Linux has an abstraction that lets Host Controller Drivers share code. As a comment in drivers/usb/core/hcd.c says:

 * USB Host Controller Driver framework
 * Plugs into usbcore (usb_bus) and lets HCDs share code, minimizing
 * HCD-specific behaviors/bugs.
 * This does error checks, tracks devices and urbs, and delegates to a
 * "hc_driver" only for code (and data) that really needs to know about
 * hardware differences.  That includes root hub registers, i/o queues,
 * and so on ... but as little else as possible.
 * Shared code includes most of the "root hub" code (these are emulated,
 * though each HC's hardware works differently) and PCI glue, plus request
 * tracking overhead.  The HCD code should only block on spinlocks or on
 * hardware handshaking; blocking on software events (such as other kernel
 * threads releasing resources, or completing actions) is all generic.
 * Happens the USB 2.0 spec says this would be invisible inside the "USBD",
 * and includes mostly a "HCDI" (HCD Interface) along with some APIs used
 * only by the hub driver ... and that neither should be seen or used by
 * usb client device drivers.

USB device address 1 is assigned to the root hub in register_root_hub(), as commented right above this function:

 * register_root_hub - called by usb_add_hcd() to register a root hub
 * @hcd: host controller for this root hub
 * This function registers the root hub with the USB subsystem.  It sets up
 * the device properly in the device tree and then calls usb_new_device()
 * to register the usb device.  It also assigns the root hub's USB address
 * (always 1).

This is corroborated by usb.ids database that says that for vendor Id 1d6b the product Ids 1,2,3 correspond to 1.1, 2.0, 3.0 root hub, respectively.

What we have in the Linux device tree at this device is a kind of mixture of the USB host controller (a real device) and the USB root hub (also a real device), abstracted by the USB HCD framework discussed above.

Now, some modern systems with xHCI have also EHCI controllers that have Intel Corp. Integrated Rate Matching Hub always attached. These are not the root hubs, they have address 2, not 1. From an Intel manual, chapter 5.19.1:

The Hubs convert low and full-speed traffic into high-speed traffic.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .