3. Linux USB子系统架构
Linux USB 子系统采用经典的分层架构设计,将主机侧与设备侧的驱动逻辑解耦,并通过 USB Core 层提供统一的资源管理与协议抽象。理解这一分层模型是进行 USB 驱动移植与调试的基础。
3.1 分层模型总览
整个 USB 子系统从纵向划分为三个核心层次,每一层职责明确,接口清晰。下图展示了主机侧与设备侧的分层对应关系:
关键理解:主机侧与设备侧通过相同的 USB 总线协议通信,但两侧的软件栈完全对称——主机侧由 HCD 驱动硬件控制器,设备侧由 UDC 驱动硬件控制器。USB Core 层在两侧分别承担不同的管理职责,但都向上层提供统一的编程接口。
3.2 USB Core(核心层)
USB Core 是 Linux USB 子系统的中枢,负责管理 USB 总线上的所有设备、接口、端点以及数据传输。它不直接操作硬件,而是通过 HCD 或 UDC 层间接控制。
| 核心职责 | 说明 | 关键数据结构 / API |
|---|---|---|
| 总线枚举 | 检测设备插入/拔出,分配地址,读取描述符 | hub_event()、usb_new_device() |
| 设备管理 | 维护设备树、接口、端点链表 | struct usb_device、struct usb_interface |
| 数据传输 | 封装 URB(USB Request Block),调度传输 | struct urb、usb_submit_urb() |
| 电源管理 | 挂起/恢复、远程唤醒、选择性挂起 | usb_suspend()、usb_resume() |
| 驱动绑定 | 匹配 USB 设备与 usb_driver |
usb_register()、usb_match_id() |
移植关注点:在驱动移植过程中,USB Core 层通常不需要修改,但需要确认内核配置中是否包含了必要的 USB Core 选项(如
CONFIG_USB、CONFIG_USB_SUPPORT)。如果目标 SoC 需要支持 OTG,还需开启 CONFIG_USB_OTG。
3.3 HCD(主机控制器驱动)
HCD 是主机侧最底层的软件模块,直接与 USB 主机控制器硬件交互。Linux 内核支持四种主流主机控制器标准:
| 标准 | 全称 | 速度支持 | 典型硬件 | 内核驱动 |
|---|---|---|---|---|
| UHCI | Universal Host Controller Interface | USB 1.1 (Full/Low) | Intel/VIA 南桥 | uhci-hcd |
| OHCI | Open Host Controller Interface | USB 1.1 (Full/Low) | NXP/ST/Allwinner SoC | ohci-hcd |
| EHCI | Enhanced Host Controller Interface | USB 2.0 (High) | 大多数 SoC 集成 | ehci-hcd |
| xHCI | eXtensible Host Controller Interface | USB 3.0/3.1/3.2 (SuperSpeed) | Intel/AMD/瑞萨 | xhci-hcd |
HCD 层向上通过 struct hc_driver 结构体向 USB Core 注册回调函数,包括:
struct hc_driver {
const char *description;
const char *product_desc;
size_t hcd_priv_size;
/* 硬件初始化与去初始化 */
int (*start)(struct usb_hcd *hcd);
void (*stop)(struct usb_hcd *hcd);
/* 中断处理 */
irqreturn_t (*irq)(struct usb_hcd *hcd);
/* URB 提交与完成 */
int (*urb_enqueue)(struct usb_hcd *hcd,
struct urb *urb, gfp_t mem_flags);
int (*urb_dequeue)(struct usb_hcd *hcd,
struct urb *urb, int status);
/* 端口控制 */
int (*hub_status_data)(struct usb_hcd *hcd, char *buf);
int (*hub_control)(struct usb_hcd *hcd,
u16 typeReq, u16 wValue,
u16 wIndex, char *buf, u16 wLength);
};
移植陷阱:许多 SoC 的 EHCI 控制器需要依赖 PHY 驱动初始化 USB 物理层。在设备树中必须正确描述 PHY 的引用关系(
phys 属性),否则 HCD 在 start() 阶段会因 PHY 未就绪而失败。常见错误是只使能了 EHCI 驱动却遗漏了对应的 PHY 驱动。
3.4 UDC(设备控制器驱动)
UDC 是设备侧(Gadget)的底层驱动,负责管理 SoC 内部的 USB 设备控制器硬件。与 HCD 不同,UDC 不主动发起传输,而是响应主机发起的请求。
Linux 内核中常见的 UDC 驱动包括:
- DWC2:DesignWare USB 2.0 OTG 控制器,广泛用于 Allwinner、Rockchip、NXP i.MX 系列
- DWC3:DesignWare USB 3.0 控制器,用于 TI AM57x、Xilinx ZynqMP、高通平台
- ChipIdea:NXP 内部 USB 2.0 控制器,用于 i.MX6/7 系列
- FSL:飞思卡尔专用 USB 控制器,用于 PowerPC 架构
- Renesas:瑞萨 R-Car 系列 USB 3.0 控制器
UDC 驱动通过 struct usb_gadget_ops 向 Gadget Core 层暴露硬件操作接口:
struct usb_gadget_ops {
int (*get_frame)(struct usb_gadget *gadget);
int (*wakeup)(struct usb_gadget *gadget);
int (*set_selfpowered)(struct usb_gadget *gadget, int value);
int (*vbus_session)(struct usb_gadget *gadget, int is_active);
int (*vbus_draw)(struct usb_gadget *gadget, unsigned mA);
int (*pullup)(struct usb_gadget *gadget, int is_on);
int (*start)(struct usb_gadget *gadget,
struct usb_gadget_driver *driver);
int (*stop)(struct usb_gadget *gadget);
};
设备树适配要点:UDC 驱动通常通过设备树节点描述硬件资源。以 DWC2 为例,设备树中需要指定
compatible = "rockchip,rk3399-usb", "snps,dwc2",并配置 dr_mode 属性(host / peripheral / otg)。如果 SoC 支持 OTG,还需添加 extcon 节点用于 ID 引脚检测。
3.5 分层模型的数据流
以主机侧读取 U 盘数据为例,数据流经各层的路径如下:
- USB 设备驱动(如 usb-storage)构造 URB,调用
usb_submit_urb()提交给 USB Core。 - USB Core 根据 URB 的目标端点,将请求路由到对应的 HCD。
- HCD 将 URB 转换为硬件可执行的传输描述符(TD),写入主机控制器的寄存器或 DMA 链表。
- 主机控制器硬件 通过 USB 总线发送 IN/OUT 事务,与设备通信。
- 数据返回时,HCD 中断处理函数将完成状态回填到 URB,调用完成回调。
- USB Core 将完成的 URB 返回给设备驱动,驱动解析数据并提交给上层文件系统。
3.6 分层模型在移植中的意义
掌握 USB 子系统的分层结构,在驱动移植过程中可以快速定位问题归属:
| 现象 | 可能问题层 | 排查方向 |
|---|---|---|
| 设备无法枚举 | HCD / UDC 层 | 检查 PHY 初始化、时钟门控、设备树 reg 地址 |
| 枚举成功但数据传输超时 | HCD / UDC 层 | 检查 DMA 配置、中断触发、端点 FIFO 大小 |
| 特定设备无法识别 | USB Core / 设备驱动层 | 检查 VID/PID 匹配、描述符解析、驱动绑定 |
| Gadget 功能无法启用 | UDC / Gadget Core 层 | 检查 dr_mode 配置、UDC 注册状态、configfs 配置 |
| OTG 角色切换失败 | 跨层交互 | 检查 extcon 驱动、ID 中断、VBUS 检测 |
最佳实践:在开始 USB 驱动移植前,先通过
lsusb -t(主机侧)或 cat /sys/kernel/debug/usb/udc(设备侧)确认底层驱动是否已正确注册。如果这些命令无输出,问题大概率出在 HCD/UDC 层,无需向上层排查。