3. Linux USB子系统架构

Linux USB 子系统采用经典的三层软件架构设计,将 USB 协议栈从下到上划分为 USB 设备控制器驱动(Gadget)、主机控制器驱动(HCD) 和 USB 核心层(Core)。这种分层设计实现了硬件无关性与协议处理的解耦,使得同一套 USB 核心代码可以适配不同的主机控制器(如 EHCI、XHCI)和设备角色(Host/Device)。

Linux USB 子系统三层架构总览 USB 核心层(USB Core) 协议解析 / 设备枚举 / 管道管理 / 驱动匹配 主机控制器驱动(HCD) EHCI / OHCI / UHCI / XHCI 设备控制器驱动(Gadget) UDC / 功能驱动 / 配置层 USB 硬件控制器 PCI / Platform / ACPI 总线接口 说明:Host 模式下使用 HCD 驱动;Device 模式下使用 Gadget 驱动;Core 层对两者提供统一接口

3.1 USB 核心层(USB Core)

USB Core 是 Linux USB 子系统的中枢,负责管理 USB 总线、设备枚举、配置解析、驱动匹配以及 urb(USB Request Block)的调度。它不直接操作硬件,而是通过 HCD 或 Gadget 层提供的回调函数与底层交互。

核心职责:

  • 设备枚举:检测 USB 设备插入/拔出,读取设备描述符、配置描述符、接口描述符等。
  • 驱动匹配:根据 idVendor / idProduct 或接口类代码匹配对应的 USB 设备驱动。
  • 管道管理:创建、维护和销毁 USB 管道(pipe),管理端点(endpoint)的通信。
  • urb 生命周期:分配、提交、取消和完成 urb,协调数据传输。
  • 电源管理:处理挂起/恢复、远程唤醒等电源事件。

USB Core 在源码中位于 drivers/usb/core/ 目录,主要文件包括:

文件 功能
hub.c USB Hub 驱动,处理端口状态变化和设备枚举
usb.c USB 设备初始化、注册、注销
driver.c USB 驱动模型,驱动与设备的绑定/解绑
urb.c urb 分配、提交、取消和完成处理
message.c 控制传输(setup 包)的发送与接收

3.2 主机控制器驱动(HCD)

HCD 是 USB Host 模式下直接与硬件控制器交互的软件层。它实现了 USB 主机控制器规范(如 EHCI、OHCI、UHCI、XHCI),负责将 USB Core 下发的 urb 转换为硬件可执行的传输描述符(TD),并处理中断、DMA 传输等底层操作。

HCD 内部结构及与 Core 的交互 USB Core 主机控制器驱动(HCD) urb → TD 转换 DMA 管理 中断处理 ... USB 主机控制器硬件

Linux 内核支持四种主流 HCD 标准:

HCD 类型 对应规范 速度支持 源码目录
EHCI Enhanced Host Controller Interface USB 2.0 (High Speed) drivers/usb/host/ehci-*.c
OHCI Open Host Controller Interface USB 1.1 (Full/Low Speed) drivers/usb/host/ohci-*.c
UHCI Universal Host Controller Interface USB 1.1 (Full/Low Speed) drivers/usb/host/uhci-*.c
XHCI eXtensible Host Controller Interface USB 3.0/2.0/1.1 (SuperSpeed+) drivers/usb/host/xhci-*.c

移植要点:在嵌入式平台移植 HCD 时,通常需要关注以下方面:

  • 时钟和电源管理:确保 USB 控制器时钟已使能,电源域正常。
  • DMA 配置:检查系统内存是否支持 USB 控制器所需的 DMA 类型(如 coherent 或 streaming DMA)。
  • 中断号与触发方式:确认设备树或平台数据中中断号、中断触发类型(边沿/电平)正确。
  • PHY 初始化:部分 SoC 需要额外配置 USB PHY(物理层收发器)。

3.3 设备控制器驱动(Gadget)

Gadget 层使 Linux 设备能够作为 USB 外设(Device)工作,例如模拟成 U 盘、串口、网卡或复合设备。它由三部分组成:UDC(USB Device Controller)驱动、Gadget 功能驱动和配置层(Configfs / Legacy)。

Gadget 三层子结构 Gadget 功能驱动(Function Drivers) g_serial / g_ether / g_mass_storage / g_audio / g_cdc 配置层(Configfs / Legacy) 绑定功能驱动与 UDC,生成描述符 UDC 驱动(USB Device Controller) dwc2 / dwc3 / chipidea / musb / fsl_qe USB 设备控制器硬件

Gadget 层与 HCD 层在架构上对称,但方向相反:

对比维度 HCD(主机侧) Gadget(设备侧)
角色 Host(主设备) Device(从设备)
数据流向 Core → HCD → 硬件(发送/接收) 硬件 → UDC → 功能驱动(响应请求)
核心数据结构 struct usb_hcd struct usb_gadget
传输发起方 主机主动发起传输 设备等待主机请求,被动响应
典型应用 USB 鼠标、键盘、U 盘接入 模拟 U 盘、RNDIS 网卡、串口

3.4 三层之间的接口与数据流

USB Core 通过一组标准接口与 HCD 和 Gadget 层通信。对于 Host 模式,核心数据结构是 struct usb_hcd,其中包含 struct hc_driver 函数指针表;对于 Device 模式,核心数据结构是 struct usb_gadget,通过 struct usb_gadget_ops 与 UDC 交互。

Host 模式关键接口(hc_driver):

struct hc_driver {
    const char *description;
    int (*reset) (struct usb_hcd *hcd);
    int (*start) (struct usb_hcd *hcd);
    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);
    irqreturn_t (*irq) (struct usb_hcd *hcd);
    void (*stop) (struct usb_hcd *hcd);
    // ... 其他回调
};

Device 模式关键接口(usb_gadget_ops):

struct usb_gadget_ops {
    int (*get_frame) (struct usb_gadget *);
    int (*wakeup) (struct usb_gadget *);
    int (*set_selfpowered) (struct usb_gadget *, int);
    int (*vbus_session) (struct usb_gadget *, int);
    int (*vbus_draw) (struct usb_gadget *, unsigned mA);
    int (*pullup) (struct usb_gadget *, int);
    int (*udc_start) (struct usb_gadget *,
                      struct usb_gadget_driver *);
    int (*udc_stop) (struct usb_gadget *);
};

典型的数据流(以 Host 模式读取 U 盘为例):

  1. USB Core 检测到 Hub 端口状态变化,启动枚举流程。
  2. USB Core 通过控制传输(urb)读取设备描述符,分配地址。
  3. USB Core 匹配 U 盘驱动(如 usb-storage),调用驱动 probe。
  4. U 盘驱动 提交批量传输 urb 到 USB Core。
  5. USB Core 将 urb 传递给 HCD,HCD 将其转换为硬件传输描述符。
  6. HCD 启动 DMA 或 PIO 传输,完成后触发中断。
  7. HCD 中断处理函数调用 urb 完成回调,通知 USB Core 和驱动层。

常见移植陷阱:

  • HCD 的 urb_enqueue 回调中未正确处理 urb 的 transfer_flags(如 URB_NO_TRANSFER_DMA_MAP),导致 DMA 映射错误。
  • Gadget 的 UDC 驱动未实现 pullup 回调,导致设备无法被主机识别。
  • 在支持 OTG(On-The-Go)的平台上,未正确切换 HCD 和 Gadget 模式,导致角色协商失败。

3.5 三层模型在嵌入式移植中的意义

理解三层模型对于嵌入式 Linux USB 驱动移植至关重要:

  • 代码复用:USB Core 和功能驱动(如 usb-storage、CDC 以太网)是平台无关的,移植时只需关注 HCD 或 UDC 层。
  • 调试隔离:当 USB 不工作时,可以快速定位问题属于 Core 层、HCD 层还是硬件层。
  • 性能优化:在 HCD 层可以调整 DMA 缓冲区大小、中断合并策略、urb 队列深度等参数。
  • 电源管理:三层模型支持逐层挂起/恢复,HCD 层负责硬件寄存器操作,Core 层负责策略决策。

实践建议:在开始移植前,先通过 lsusb -t 或 cat /sys/kernel/debug/usb/devices 确认当前系统 USB 拓扑和驱动绑定情况,这有助于验证三层模型是否正常工作。