3. Linux USB子系统架构

Linux USB 子系统采用经典的分层架构设计,将主机侧与设备侧的驱动逻辑解耦,并通过 USB Core 层提供统一的资源管理与协议抽象。理解这一分层模型是进行 USB 驱动移植与调试的基础。

3.1 分层模型总览

整个 USB 子系统从纵向划分为三个核心层次,每一层职责明确,接口清晰。下图展示了主机侧与设备侧的分层对应关系:

Linux USB 子系统分层架构图 Linux USB 子系统分层架构 主机侧 (Host) 设备侧 (Device) USB 设备驱动 (usb_driver) 如:usb-storage、usb-serial Gadget 功能驱动 如:g_ether、g_mass_storage USB Core (核心层) 协议管理 · 总线枚举 · 资源分配 USB Gadget Core 功能抽象 · 请求调度 · 事件管理 HCD (主机控制器驱动) EHCI / xHCI / OHCI / UHCI UDC (设备控制器驱动) DWC2 / DWC3 / ChipIdea / FSL USB Host 控制器 (硬件) PCI / Platform 总线挂载 USB Device 控制器 (硬件) SoC 内部集成 / 外挂 PHY 标准 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 盘数据为例,数据流经各层的路径如下:

  1. USB 设备驱动(如 usb-storage)构造 URB,调用 usb_submit_urb() 提交给 USB Core。
  2. USB Core 根据 URB 的目标端点,将请求路由到对应的 HCD。
  3. HCD 将 URB 转换为硬件可执行的传输描述符(TD),写入主机控制器的寄存器或 DMA 链表。
  4. 主机控制器硬件 通过 USB 总线发送 IN/OUT 事务,与设备通信。
  5. 数据返回时,HCD 中断处理函数将完成状态回填到 URB,调用完成回调。
  6. USB Core 将完成的 URB 返回给设备驱动,驱动解析数据并提交给上层文件系统。
USB 数据流分层传递示意图 USB 设备驱动 USB Core HCD USB 控制器硬件 URB 提交 URB 完成 TD 下发 中断上报 总线事务 数据响应 设备侧数据流方向相反:Gadget 功能驱动 → Gadget Core → UDC → 设备控制器硬件 主机发起的 OUT 事务在设备侧由 UDC 接收后逐层向上传递

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 层,无需向上层排查。