2. Linux USB子系统架构

Linux USB子系统采用经典的分层架构设计,将复杂的USB协议栈抽象为三个清晰的层次:USB核心层、主机控制器驱动(HCD)和设备控制器驱动(UDC)。这种分层模型使得USB驱动开发可以专注于特定角色,同时复用核心层的通用协议处理逻辑。

核心要点:USB子系统通过分层解耦,让主机侧(HCD)和设备侧(UDC)共享同一套核心层API,而底层硬件差异被驱动层完全隔离。

2.1 分层模型总览

下图展示了USB子系统在Linux内核中的完整分层结构,从顶层USB设备/客户端驱动到底层硬件控制器,共分为三个主要层次:

Linux USB子系统分层架构 USB核心层 (USB Core) 协议解析 · 标准请求处理 · 总线枚举 · 设备/配置/接口/端点管理 usb_init() · usb_register() · usb_alloc_dev() · usb_submit_urb() HCD (主机控制器驱动) EHCI · OHCI · UHCI · xHCI urb → td → 硬件传输描述符 hcd_register() · hc_driver UDC (设备控制器驱动) DWC2 · DWC3 · Chipidea · MUSB usb_ep_queue() · usb_gadget usb_add_gadget() · usb_gadget_driver USB主机控制器硬件 PCI/平台总线 · 寄存器 · DMA · 中断 如:Intel xHCI · Renesas uPD72020 USB设备控制器硬件 SoC集成 · 寄存器 · FIFO · DMA 如:STM32 DWC2 · TI AM335x MUSB 分层职责说明 • USB核心层:不依赖硬件,提供统一的设备模型、URB管理、标准请求处理 • HCD/UDC:桥接核心层与硬件,处理传输描述符、寄存器操作、中断服务 • 硬件层:物理控制器,执行实际USB总线事务

2.2 USB核心层(USB Core)

USB核心层是Linux USB子系统的中枢,它不直接操作硬件,而是提供一套完整的框架来管理USB设备、配置、接口和端点。核心层的主要职责包括:

  • 设备枚举:检测USB设备插入/拔出,分配地址,读取设备描述符、配置描述符等。
  • URB管理:提供usb_submit_urb()、usb_kill_urb()等API,管理USB请求块的生命周期。
  • 标准请求处理:处理GET_DESCRIPTOR、SET_CONFIGURATION等标准USB请求。
  • 驱动绑定:通过usb_register()注册USB驱动,匹配USB设备ID表。
  • 电源管理:支持USB挂起/恢复、远程唤醒等电源管理操作。
调试提示:在调试USB核心层问题时,可以打开内核动态调试:echo 'file drivers/usb/core/* +p' > /sys/kernel/debug/dynamic_debug/control,观察枚举和URB提交的详细日志。

2.3 主机控制器驱动(HCD)

HCD负责管理USB主机控制器硬件,将核心层的URB请求转换为硬件可执行的传输描述符(TD)。Linux内核支持四种主流HCD标准:

HCD类型 速度支持 典型硬件 内核驱动
UHCI USB 1.1 (低速/全速) Intel/VIA南桥 uhci-hcd
OHCI USB 1.1 (低速/全速) 非Intel平台(如S3C2440) ohci-hcd
EHCI USB 2.0 (高速) 大多数x86/ARM平台 ehci-hcd
xHCI USB 3.0/3.1/3.2 (超高速) 现代x86/ARM64平台 xhci-hcd

HCD驱动的核心数据结构是struct hc_driver,它定义了HCD需要实现的操作接口:

// include/linux/usb/hcd.h
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);

    /* 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 (*alloc_dev)(struct usb_hcd *hcd, struct usb_device *udev);
    void (*free_dev)(struct usb_hcd *hcd, struct usb_device *udev);

    /* 中断处理 */
    irqreturn_t (*irq)(struct usb_hcd *hcd);

    /* 电源管理 */
    int (*hub_suspend)(struct usb_hcd *hcd);
    int (*hub_resume)(struct usb_hcd *hcd);
};

2.4 设备控制器驱动(UDC)

UDC是USB Gadget子系统的底层驱动,负责管理USB设备控制器硬件,使嵌入式设备能够作为USB外设(如虚拟串口、U盘、以太网卡)连接到主机。UDC驱动需要实现usb_gadget_ops结构体中的操作:

// include/linux/usb/gadget.h
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 int mA);
    int (*pullup)(struct usb_gadget *gadget, int is_on);
    int (*udc_start)(struct usb_gadget *gadget,
                     struct usb_gadget_driver *driver);
    int (*udc_stop)(struct usb_gadget *gadget);
};

常见的UDC硬件及其内核驱动:

  • DWC2:广泛用于STM32、Allwinner、Rockchip等SoC,驱动为dwc2。
  • DWC3:用于高性能SoC(如TI AM57x、Xilinx ZynqMP),驱动为dwc3。
  • Chipidea:用于NXP i.MX系列,驱动为ci_hdrc。
  • MUSB:用于TI OMAP/AM335x,驱动为musb-hdrc。

2.5 分层模型中的数据流

理解数据在分层模型中的流动路径,对调试USB驱动至关重要。下面以主机侧发送一个批量传输为例:

USB数据流:从应用到硬件(主机侧批量传输) USB设备驱动 usb_submit_urb() USB核心层 URB队列管理 HCD urb_enqueue() 硬件控制器 DMA/寄存器操作 USB总线 包传输 USB设备 端点接收 中断返回 · 完成回调 数据流关键路径 ① 设备驱动构造URB → ② 核心层将URB加入端点队列 → ③ HCD将URB拆分为传输描述符(TD) ④ 硬件通过DMA读取TD并执行总线事务 → ⑤ 设备响应 → ⑥ 中断上报 → ⑦ 核心层回调完成函数 调试重点:检查URB状态(-EINPROGRESS/0/-EPROTO)、TD完成位、中断触发频率

2.6 分层模型的关键数据结构

USB子系统的分层模型通过几个核心数据结构串联起来,理解这些结构体之间的关系是驱动开发的基础:

数据结构 所属层次 作用 关键字段
usb_device 核心层 代表一个USB设备 devnum, speed, config, ep0
usb_interface 核心层 代表一个USB接口 cur_altsetting, num_altsetting
urb 核心层 USB请求块,数据传输单元 pipe, transfer_buffer, actual_length, status
usb_hcd HCD 主机控制器驱动实例 self.root_hub, driver, regs
hc_driver HCD HCD操作函数表 urb_enqueue, urb_dequeue, start, stop
usb_gadget UDC 设备控制器实例 ops, ep0, speed, is_selfpowered
usb_ep UDC 端点抽象 ops, maxpacket, address, name
常见调试陷阱:在编写HCD或UDC驱动时,务必注意URB的transfer_flags设置。例如,URB_NO_TRANSFER_DMA_MAP标志会影响DMA映射方式,错误设置可能导致DMA地址错误或缓存一致性问题。建议在初始化阶段使用usb_alloc_urb()并明确设置所有标志位。

2.7 分层模型的初始化流程

USB子系统在系统启动时的初始化顺序严格遵循分层依赖关系:

  1. USB核心层初始化:usb_init()注册总线类型、创建sysfs文件、初始化hub驱动。
  2. HCD/UDC驱动注册:各平台通过module_init()或platform_driver_register()注册HCD或UDC驱动。
  3. 硬件探测:驱动探测函数读取设备树或PCI配置,初始化控制器寄存器。
  4. 创建root hub:HCD创建虚拟root hub设备,触发USB总线枚举。
  5. 设备枚举:hub线程检测端口状态变化,执行USB设备枚举流程。
  6. 驱动绑定:核心层根据设备ID表匹配USB设备驱动,调用驱动的probe()函数。