2. Linux USB 子系统架构:核心层、主机控制器驱动(HCD)、设备驱动、Gadget驱动框架
Linux USB 子系统是嵌入式系统中结构最清晰、分层最严格的驱动框架之一。理解其分层架构是调试枚举失败与 URB 超时的前提。整个子系统从上到下分为四层:USB 设备驱动、USB 核心层 (USB Core)、主机控制器驱动 (HCD) 以及底层的 USB 主机控制器硬件。在设备侧,还存在一套对称的 Gadget 驱动框架。
调试启示: 枚举失败通常发生在 USB Core 与 HCD 的交互过程中;URB 超时则多源于设备驱动与 USB Core 之间的 URB 提交/完成链路异常。定位问题前,先确认故障发生在哪一层。
2.1 USB 核心层 (USB Core)
USB Core 是整个子系统的枢纽,它向上提供统一的设备驱动接口,向下封装 HCD 的差异。核心层负责以下关键任务:
- 设备枚举:解析设备描述符、配置描述符、接口描述符、端点描述符,建立
usb_device和usb_interface树。 - URB 管理:提供
usb_submit_urb()、usb_kill_urb()、usb_unlink_urb()等 API,管理异步 I/O 的生命周期。 - 管道抽象:将端点地址、传输类型、方向封装为
usb_pipe,屏蔽底层硬件差异。 - 总线模型:维护
usb_bus_type,实现设备-驱动匹配与热插拔。
关键数据结构:
struct usb_device 代表一个 USB 设备,struct usb_interface 代表一个功能接口,struct urb 代表一次 USB 请求块。调试时,/sys/kernel/debug/usb/devices 和 usbmon 是直接观察这些数据结构的窗口。
2.2 主机控制器驱动 (HCD)
HCD 是直接操作 USB 主机控制器寄存器的底层驱动。Linux 支持四种主流 HCD 标准:
| HCD 类型 | 对应控制器 | 速度支持 | 传输描述符 |
|---|---|---|---|
| ehci-hcd | EHCI | 高速 (480 Mbps) | iTD / siTD / qTD |
| ohci-hcd | OHCI | 全速/低速 (12/1.5 Mbps) | ED / TD |
| uhci-hcd | UHCI | 全速/低速 (12/1.5 Mbps) | TD / QH |
| xhci-hcd | xHCI | 超速/高速/全速/低速 (5G/480/12/1.5 Mbps) | TRB / TD |
HCD 的核心职责包括:
- 将 USB Core 下发的 URB 转换为硬件可执行的传输描述符(TD/TRB)。
- 管理主机控制器的内存队列(如 xHCI 的 Transfer Ring)。
- 处理硬件中断,将完成状态回传给 USB Core。
调试陷阱: 枚举失败时,常见错误是 HCD 未正确初始化或中断未注册。检查
dmesg 中 HCD 的 probe 日志,确认 usb_hcd_pci_probe 或 usb_add_hcd 是否成功。URB 超时则可能源于 HCD 的调度队列溢出或 TD 提交失败。
2.3 USB 设备驱动
设备驱动位于架构最上层,直接与用户空间交互。每个设备驱动对应一个 usb_driver 结构体,通过 usb_register() 注册到 USB Core。
// USB 设备驱动模板
static struct usb_driver my_usb_driver = {
.name = "my_usb_device",
.probe = my_usb_probe,
.disconnect = my_usb_disconnect,
.id_table = my_usb_id_table,
};
module_usb_driver(my_usb_driver);
设备驱动的典型工作流程:
- probe:匹配
id_table,获取接口和端点信息,分配 URB 并提交。 - URB 提交:调用
usb_submit_urb(),指定端点、传输类型、回调函数。 - URB 完成:回调函数中检查状态,处理数据或重试。
- disconnect:释放 URB,清理资源。
2.4 Gadget 驱动框架
Gadget 框架是 Linux 在设备侧(如开发板模拟 U 盘、USB 网卡)的驱动体系,与主机侧对称但方向相反。其核心组件包括:
- UDC (USB Device Controller) 驱动:直接操作设备侧 USB 控制器硬件,对应主机侧的 HCD。
- Gadget Function 驱动:实现具体功能,如 mass_storage、ether、serial,对应主机侧的设备驱动。
- ConfigFS / Legacy Gadget:用户空间配置接口,用于动态组合功能。
调试对比: 主机侧枚举失败看 HCD 和 USB Core;设备侧枚举失败看 UDC 驱动和 Gadget Function 的
bind 流程。URB 超时在主机侧表现为 -ETIMEDOUT,在 Gadget 侧则表现为请求队列未及时完成。
2.5 各层之间的数据流与 URB 生命周期
理解 URB 在四层之间的流转路径,是分析超时问题的核心:
- 设备驱动 调用
usb_submit_urb()将 URB 送入 USB Core。 - USB Core 检查 URB 合法性,映射 DMA 缓冲区,调用 HCD 的
urb_enqueue回调。 - HCD 将 URB 拆分为硬件 TD/TRB,写入控制器队列,启动传输。
- 硬件 执行传输,完成后触发中断。
- HCD 中断处理函数回收 TD/TRB,调用
usb_hcd_giveback_urb()将 URB 回传给 USB Core。 - USB Core 调用设备驱动注册的 URB 完成回调。
2.6 各层关键文件与调试入口
| 层级 | 内核源码路径 | 调试接口 |
|---|---|---|
| USB Core | drivers/usb/core/ | /sys/kernel/debug/usb/devices |
| HCD | drivers/usb/host/ | ehci-dbg.c / xhci-dbg.c 中的 debugfs |
| 设备驱动 | drivers/usb/class/ 等 | usbmon 捕获 URB 级数据 |
| Gadget | drivers/usb/gadget/ | configfs / gadgetfs |
实战建议: 遇到枚举失败,首先检查
dmesg 中 USB Core 的 hub_event 和 usb_new_device 日志;遇到 URB 超时,使用 usbmon 抓取 URB 提交与完成的时间戳,对比 HCD 中断频率。分层排查,事半功倍。