在 USB 主控制器连接到 PCI/PCIE 总线的任何 PC 上,我会看到以下内容:
$ cat /sys/bus/usb/devices/usb1/{idVendor,idProduct,manufacturer,product,serial}
1d6b
0002
Linux 4.14.157-amd64-x32 ehci_hcd
EHCI Host Controller
0000:00:1a.0
即,EHCI 主机控制器(在本例中具有 PCI 设备位置0000:00:1a.0
)由一组虚假的字符串描述符和供应商/产品标识符表示。查找供应商 ID 1d6b
,usb.ids
发现它对应于 Linux Foundation。 (lsusb
将其列为“Linux Foundation 2.0 root hub”。)但是所引用的 PCI 设备serial
是真实的,并且具有以下属性:
$ cat /sys/bus/pci/devices/0000:00:1a.0/{vendor,device}
0x8086
0x8c2d
查找这些 ID,pci.ids
我们可以发现它是 Intel 8 系列/C220 系列芯片组系列 USB EHCI(与所说的相同lspci
)。来自真正硬件制造商的真正硬件。
那么为什么 Linux 用一些奇怪的 id 集来表示这个 Intel 硬件呢?我确实意识到 PCI 和 USB 供应商/产品 id 可能会发生冲突,因此不可能使用 PCI 命名空间中的 id 启动 USB 设备树。但为什么是字符串描述符呢?
我的猜测是,这是因为名为“*HCI Host Controller”的整个 USB 实体是一个虚构的实体。但另一方面,它似乎有一个地址(始终=1),该地址从未分配给该总线上新连接的设备。所以看起来这个 USB 实体可能是真实存在的。但这个保留地址也可能只是一种记账方式。
我的猜测正确吗?作为 USB 实体的主机控制器完全是虚构的吗?它是否从未作为线路上的实际可寻址设备出现?或者是否有一些真实的东西,我们实际上可以向其发送标准 USB 请求,而不是让内核简单地模拟它们的处理?
答案1
Linux 有一个抽象,可以让主机控制器驱动程序共享代码。作为评论drivers/usb/core/hcd.c
说:
* 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 设备地址 1 被分配给 中的根集线器register_root_hub()
,如该函数上方的注释所示:
* 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).
数据库证实了这一点usb.ids
,数据库表明对于供应商 ID,1d6b
产品 ID 1、2、3 分别对应于 1.1、2.0、3.0 根集线器。
我们在该设备的 Linux 设备树中拥有的是 USB 主控制器(真实设备)和 USB 根集线器(也是真实设备)的混合体,由上面讨论的 USB HCD 框架抽象出来。
现在,一些具有 xHCI 的现代系统也具有 EHCI 控制器,这些控制器具有英特尔公司集成速率匹配中心始终依附。这些不是根集线器,它们的地址为 2,而不是 1。英特尔手册,第 5.19.1 章:
The Hubs convert low and full-speed traffic into high-speed traffic.