2. Linux USB 子系统架构:整体软件栈分层与核心数据结构关系图

Linux USB 子系统采用经典的分层架构设计,从上到下依次为 设备层、总线层 和 主机控制器层。这种分层结构使得 USB 驱动开发具有高度的模块化和可移植性:上层驱动无需关心底层硬件细节,下层驱动无需理解上层协议语义。

2.1 三层软件栈总览

下表总结了每一层的主要职责、核心模块以及对应的内核对象:

层次 主要职责 核心模块/文件 关键数据结构
设备层 实现具体 USB 设备功能(如键盘、存储、网络) usb-storage, usbhid, cdc_ether usb_driver, usb_device, usb_interface
总线层 管理 USB 设备枚举、配置、带宽分配、协议解析 drivers/usb/core/ usb_bus_type, usb_device, usb_host_config
主机控制器层 直接操作硬件寄存器,完成 USB 事务传输 ehci-hcd, ohci-hcd, xhci-hcd usb_hcd, usb_host_endpoint, urb
关键理解: 总线层是整个 USB 子系统的“中枢神经”,它向上为设备驱动提供统一的注册/注销接口,向下通过 hcd 抽象层屏蔽不同主机控制器(EHCI/XHCI/OHCI)的硬件差异。

2.2 设备层(Device Layer)

设备层是离驱动开发者最近的层次。当你在内核中编写一个 USB 设备驱动时,你主要与 usb_driver 和 usb_interface 打交道。

  • usb_driver:代表一个 USB 设备驱动,通过 usb_register() 注册到总线层。其 probe() 回调在设备插入且匹配成功时被调用。
  • usb_interface:代表设备中的一个功能接口(Interface)。一个 USB 设备可以包含多个接口,每个接口对应一个逻辑功能(如音频设备的控制接口和数据接口)。
  • usb_device:代表整个 USB 设备,包含设备描述符、配置描述符等信息。设备驱动通常不直接操作 usb_device,而是通过 usb_interface 间接访问。
开发提示: 在 probe() 回调中,你拿到的参数是 struct usb_interface * 和 const struct usb_device_id *。通过 interface_to_usbdev() 宏可以获取对应的 usb_device 指针。

2.3 总线层(Bus Layer)

总线层位于 drivers/usb/core/ 目录下,是 USB 子系统的核心。它负责设备枚举、配置选择、带宽管理、电源管理以及设备热插拔事件的分发。

总线层维护了两个关键链表:

  • 设备链表:挂载所有已注册的 usb_device 实例。
  • 驱动链表:挂载所有已注册的 usb_driver 实例。

当新设备插入时,总线层执行以下步骤:

  1. 读取设备描述符,分配 usb_device 结构体。
  2. 读取配置描述符,解析接口和端点信息。
  3. 为每个接口创建 usb_interface 实例。
  4. 遍历驱动链表,调用 usb_device_match() 进行匹配。
  5. 匹配成功则调用驱动的 probe() 函数。

2.4 主机控制器层(Host Controller Layer)

主机控制器层是软件与硬件之间的桥梁。它通过 usb_hcd(USB Host Controller Driver)抽象结构体,将不同主机控制器(EHCI、XHCI、OHCI、UHCI)的硬件操作统一为标准的回调函数。

该层核心职责包括:

  • 管理根 Hub(Root Hub),模拟 Hub 行为以响应设备插入/拔出。
  • 分配和管理 USB 传输描述符(TD)和队列头(QH)。
  • 处理中断传输、批量传输、等时传输和控制传输的调度。
  • 通过 urb(USB Request Block)与上层进行数据交互。
注意: 主机控制器驱动(HCD)通常由芯片厂商提供,内核已集成主流控制器驱动(如 xhci-hcd、ehci-hcd)。除非你正在移植新硬件平台,否则一般不需要修改这一层。

2.5 核心数据结构关系图

下面的 SVG 图展示了 USB 子系统中最重要的数据结构及其关联关系:

Linux USB 核心数据结构关系图 Linux USB 核心数据结构关系图 设备层 (Device Layer) usb_driver probe / disconnect usb_interface cur_altsetting usb_device descriptor 总线层 (Bus Layer) usb_bus_type match / uevent usb_host_config interface[] usb_device config / bus 主机控制器层 (HCD Layer) usb_hcd driver / regs urb pipe / transfer_buffer usb_host_endpoint urb_list / desc 说明:虚线箭头表示层间引用关系。usb_device 在设备层和总线层均有出现,但视角不同:设备层关注功能接口,总线层关注配置和枚举。 设备层 总线层 主机控制器层

2.6 数据结构之间的关键关联

理解上述关系图后,需要掌握以下几个核心关联规则:

  • usb_driver ↔ usb_interface:一个 usb_driver 可以绑定多个 usb_interface,但一个 usb_interface 只能被一个 usb_driver 绑定。
  • usb_device ↔ usb_host_config:一个 usb_device 可以有多个配置(usb_host_config),但同一时刻只能有一个激活的配置。
  • usb_interface ↔ usb_host_endpoint:每个 usb_interface 包含多个端点(usb_host_endpoint),端点描述符定义了传输类型和方向。
  • urb ↔ usb_host_endpoint:每个 urb 必须关联到一个具体的 usb_host_endpoint,通过 usb_pipe_endpoint() 建立连接。
  • usb_hcd ↔ usb_bus_type:每个 usb_hcd 实例对应一个 usb_bus_type 实例,通过 usb_create_hcd() 创建时自动关联。
面试/笔试高频题: 请描述一个 URB 从设备驱动提交到主机控制器完成传输的完整路径。答案要点:设备驱动 → usb_submit_urb() → 总线层调度 → hcd->urb_enqueue() → 主机控制器硬件操作 → 完成回调。

2.7 分层架构的设计优势

Linux USB 子系统的三层架构并非随意划分,而是经过多年演进形成的成熟设计,其优势体现在:

优势 具体体现
硬件无关性 设备驱动只需调用 USB 核心 API,无需关心底层是 EHCI 还是 XHCI。
驱动复用 同一个 USB 存储驱动可以在 x86、ARM、RISC-V 等不同平台上运行。
热插拔支持 总线层统一处理设备插入/拔出事件,自动触发 probe/disconnect。
协议升级 新增 USB 协议版本(如 USB4)只需修改主机控制器层,不影响上层驱动。
调试便利 通过 /sys/kernel/debug/usb/ 可以查看每一层的状态信息。
学习建议: 在阅读 USB 驱动源码时,先确定当前代码属于哪一层。设备层代码通常位于 drivers/usb/ 子目录下,总线层核心代码在 drivers/usb/core/,主机控制器驱动在 drivers/usb/host/。