2. Linux USB 子系统架构:核心层、主机控制器驱动(HCD)、设备驱动、Gadget驱动框架

Linux USB 子系统是嵌入式系统中结构最清晰、分层最严格的驱动框架之一。理解其分层架构是调试枚举失败与 URB 超时的前提。整个子系统从上到下分为四层:USB 设备驱动、USB 核心层 (USB Core)、主机控制器驱动 (HCD) 以及底层的 USB 主机控制器硬件。在设备侧,还存在一套对称的 Gadget 驱动框架。

调试启示: 枚举失败通常发生在 USB Core 与 HCD 的交互过程中;URB 超时则多源于设备驱动与 USB Core 之间的 URB 提交/完成链路异常。定位问题前,先确认故障发生在哪一层。
Linux USB 子系统分层架构 USB 设备驱动 (usb_driver) USB 鼠标、U 盘、USB 摄像头、USB 串口等 USB 核心层 (USB Core) 设备枚举、URB 管理、管道(Pipe)抽象、协议解析 usb_bus_type / usb_device / usb_interface / urb 主机控制器驱动 (HCD) ehci-hcd / ohci-hcd / uhci-hcd / xhci-hcd 硬件寄存器操作、TD/TRB 管理、中断处理 USB 主机控制器硬件 (HC) EHCI / OHCI / UHCI / xHCI 控制器 Gadget 驱动框架 设备侧 (Device Side) Gadget Function UDC 驱动 UDC 硬件 与主机侧对称 但方向相反

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-hcdEHCI高速 (480 Mbps)iTD / siTD / qTD
ohci-hcdOHCI全速/低速 (12/1.5 Mbps)ED / TD
uhci-hcdUHCI全速/低速 (12/1.5 Mbps)TD / QH
xhci-hcdxHCI超速/高速/全速/低速 (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);

设备驱动的典型工作流程:

  1. probe:匹配 id_table,获取接口和端点信息,分配 URB 并提交。
  2. URB 提交:调用 usb_submit_urb(),指定端点、传输类型、回调函数。
  3. URB 完成:回调函数中检查状态,处理数据或重试。
  4. 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 在四层之间的流转路径,是分析超时问题的核心:

  1. 设备驱动 调用 usb_submit_urb() 将 URB 送入 USB Core。
  2. USB Core 检查 URB 合法性,映射 DMA 缓冲区,调用 HCD 的 urb_enqueue 回调。
  3. HCD 将 URB 拆分为硬件 TD/TRB,写入控制器队列,启动传输。
  4. 硬件 执行传输,完成后触发中断。
  5. HCD 中断处理函数回收 TD/TRB,调用 usb_hcd_giveback_urb() 将 URB 回传给 USB Core。
  6. USB Core 调用设备驱动注册的 URB 完成回调。
URB 生命周期:从提交到完成 设备驱动 usb_submit_urb() USB Core urb_enqueue HCD TD/TRB 提交 硬件 执行 中断 → usb_hcd_giveback_urb() → 回调 ⚠ 超时断点:HCD 未及时完成 → -ETIMEDOUT ⚠ 枚举失败断点:USB Core 未收到设备描述符 调试工具 usbmon / ftrace /sys/kernel/debug/usb/*

2.6 各层关键文件与调试入口

层级内核源码路径调试接口
USB Coredrivers/usb/core//sys/kernel/debug/usb/devices
HCDdrivers/usb/host/ehci-dbg.c / xhci-dbg.c 中的 debugfs
设备驱动drivers/usb/class/ 等usbmon 捕获 URB 级数据
Gadgetdrivers/usb/gadget/configfs / gadgetfs
实战建议: 遇到枚举失败,首先检查 dmesg 中 USB Core 的 hub_event 和 usb_new_device 日志;遇到 URB 超时,使用 usbmon 抓取 URB 提交与完成的时间戳,对比 HCD 中断频率。分层排查,事半功倍。