2. Linux USB 驱动架构:USB核心层、主机控制器驱动(HCD)、设备驱动层、Gadget驱动层

Linux USB 子系统采用分层的软件架构设计,将复杂的 USB 协议栈抽象为四个清晰的层次。理解每一层的职责、边界以及数据流动路径,是开发稳定、高效的 USB 驱动的基础。本章将深入剖析 USB 核心层、主机控制器驱动(HCD)、设备驱动层以及 Gadget 驱动层的功能与协作机制。

架构核心思想: 分层解耦。上层驱动无需关心底层硬件的具体寄存器操作,底层驱动也无需理解上层协议的具体含义。USB 核心层作为枢纽,负责标准化数据结构和传输流程。

2.1 四层架构总览

Linux USB 驱动架构从上到下(或从主机侧到设备侧)可以分为以下四个主要层次:

  1. USB 设备驱动层(USB Device Driver Layer): 位于最上层,直接与用户空间交互或为内核其他子系统提供服务。它负责处理具体的 USB 设备功能,如 U 盘、键盘、鼠标、摄像头等。
  2. USB 核心层(USB Core Layer): 架构的枢纽,提供一组通用的 API 和数据结构,用于管理 USB 总线、设备、配置、接口、端点以及传输请求(URB)。
  3. USB 主机控制器驱动层(Host Controller Driver, HCD): 硬件抽象层,直接与 USB 主机控制器硬件(如 EHCI、XHCI)交互,负责完成底层的数据传输事务。
  4. USB Gadget 驱动层(Gadget Driver Layer): 用于设备端(Device Mode),使 Linux 设备能够模拟成 USB 外设(如虚拟串口、虚拟网卡、大容量存储设备)。
提示: 在嵌入式系统中,一个 SoC 可能同时具备主机模式(Host Mode)和设备模式(Device Mode)。HCD 层负责主机模式,而 Gadget 层负责设备模式。两者通过底层的 UDC(USB Device Controller)驱动与硬件交互。
Linux USB 驱动四层架构 USB 设备驱动层 (usb-storage, usbhid, usbnet, uvcvideo ...) USB 核心层 (USB Core) (设备枚举、URB 管理、总线模型、标准请求) 主机控制器驱动层 (HCD) (ehci-hcd, ohci-hcd, uhci-hcd, xhci-hcd) Gadget 驱动层 (g_serial, g_ether, g_mass_storage, configfs) 数据流:用户空间 → 设备驱动 → USB Core → HCD → USB 主机控制器硬件 Gadget 层数据流方向相反:UDC 硬件 → Gadget 驱动 → USB Core → 设备功能驱动

2.2 USB 核心层(USB Core)

USB Core 是 Linux USB 子系统的“操作系统”。它不直接操作硬件,而是为上层驱动和底层 HCD 提供标准化的服务。其主要职责包括:

  • 总线管理: 注册和管理 USB 总线,处理设备的热插拔事件。
  • 设备枚举: 当 USB 设备插入时,负责读取设备描述符、配置描述符、接口描述符等,并为设备分配唯一的地址。
  • URB 管理: 提供 usb_alloc_urb()、usb_submit_urb()、usb_kill_urb() 等 API,用于管理 USB 请求块(URB)。
  • 标准请求处理: 封装了 USB 规范中定义的标准设备请求(如 Get_Descriptor、Set_Configuration、Clear_Feature)。
  • 驱动模型集成: 将 USB 设备、接口、驱动注册到 Linux 设备驱动模型(LDM)中,实现 probe() 和 disconnect() 回调。
关键数据结构: struct usb_device 代表一个 USB 设备;struct usb_interface 代表一个功能接口;struct urb 代表一次 USB 数据传输请求。

2.3 主机控制器驱动层(HCD)

HCD 是 USB 主机控制器硬件的软件抽象。不同的 USB 规范(如 USB 1.x、2.0、3.x)对应不同的主机控制器接口标准,因此 Linux 内核提供了多个 HCD 实现。

HCD 名称 对应规范 速度支持 典型硬件
UHCI USB 1.x 低速 (1.5 Mbps)、全速 (12 Mbps) Intel/VIA 芯片组
OHCI USB 1.x 低速、全速 非 Intel 厂商(如 SIS、ALi)
EHCI USB 2.0 高速 (480 Mbps) 大多数 USB 2.0 主机控制器
XHCI USB 3.x 超高速 (5/10/20 Gbps),且向下兼容 现代 Intel/AMD/ARM SoC

HCD 的核心任务是实现 struct hc_driver 结构体中定义的回调函数,包括:

  • start() / stop():启动和停止主机控制器。
  • urb_enqueue() / urb_dequeue():将 URB 提交到硬件传输队列或从队列中移除。
  • hub_control():处理根集线器的控制请求(如复位端口、获取端口状态)。
注意: 在设备树中,通常不需要为标准的 PCIe 连接的 USB 控制器配置 HCD 驱动。但对于嵌入式 SoC 内部集成的 USB 控制器,必须通过设备树节点指定 compatible 属性来匹配对应的 HCD 驱动(如 "snps,dwc3" 对应 DWC3 控制器驱动)。
HCD 与 USB Core 交互流程 USB Core usb_submit_urb() HCD urb_enqueue() USB 主机控制器 (DMA / 寄存器操作) HCD 回调函数详解 1. urb_enqueue: 将 URB 转换为硬件可执行的传输描述符(TD),并挂入硬件调度链表。 2. urb_dequeue: 从硬件调度链表中移除一个尚未完成的 URB。 3. hub_control: 处理根集线器端口状态变化,如设备插入/拔出、复位完成。

2.4 USB 设备驱动层

设备驱动层是开发者最常接触的层次。一个 USB 设备驱动通常绑定到一个 struct usb_interface 上。驱动开发的核心工作是填充 struct usb_driver 结构体:

static struct usb_driver my_usb_driver = {
    .name       = "my_usb_device",
    .probe      = my_usb_probe,
    .disconnect = my_usb_disconnect,
    .id_table   = my_usb_id_table,
};

module_usb_driver(my_usb_driver);

设备驱动层的主要工作包括:

  • 匹配与探测: 通过 id_table 匹配设备的 VID/PID 或类代码,匹配成功后调用 probe() 函数。
  • 端点发现: 在 probe() 中遍历接口的 altsetting,获取 struct usb_host_endpoint,确定传输类型(控制、批量、中断、等时)。
  • 数据传输: 分配并提交 URB,实现与设备的业务逻辑交互。
  • 与用户空间交互: 通过创建字符设备、输入设备、网络设备等内核接口,将数据传递给用户空间。
开发建议: 对于简单的自定义 USB 设备,可以使用 usbfs(通过 libusb 库)在用户空间完成驱动开发,避免编写内核驱动。只有当性能要求极高或需要访问内核特有资源时,才考虑编写内核态 USB 设备驱动。

2.5 USB Gadget 驱动层

Gadget 驱动层使 Linux 设备能够扮演 USB 外设的角色。与主机侧架构对称,Gadget 层也分为三个子层次:

  1. UDC 驱动(USB Device Controller Driver): 最底层,直接操作 SoC 内部的 USB 设备控制器硬件。类似于主机侧的 HCD。
  2. Gadget 核心层(Gadget Core / UDC Core): 提供通用的 API,管理端点、请求和绑定操作。类似于主机侧的 USB Core。
  3. Gadget 功能驱动(Gadget Function Driver): 最上层,实现具体的 USB 功能,如串口(Serial)、以太网(Ethernet)、大容量存储(Mass Storage)。

现代 Linux 内核推荐使用 ConfigFS 方式来配置 Gadget 功能,这种方式允许在用户空间动态组合和绑定功能驱动,无需重新编译内核模块。

# 通过 ConfigFS 创建 USB 虚拟串口和虚拟网卡示例
mount -t configfs none /sys/kernel/config
mkdir /sys/kernel/config/usb_gadget/g1
echo 0x1d6b > /sys/kernel/config/usb_gadget/g1/idVendor
echo 0x0104 > /sys/kernel/config/usb_gadget/g1/idProduct
mkdir /sys/kernel/config/usb_gadget/g1/strings/0x409
echo "MyCompany" > /sys/kernel/config/usb_gadget/g1/strings/0x409/manufacturer
echo "MyGadget" > /sys/kernel/config/usb_gadget/g1/strings/0x409/product

# 创建配置
mkdir /sys/kernel/config/usb_gadget/g1/configs/c.1
mkdir /sys/kernel/config/usb_gadget/g1/configs/c.1/strings/0x409
echo "Conf1" > /sys/kernel/config/usb_gadget/g1/configs/c.1/strings/0x409/configuration

# 绑定功能:串口
mkdir /sys/kernel/config/usb_gadget/g1/functions/acm.usb0
ln -s /sys/kernel/config/usb_gadget/g1/functions/acm.usb0 /sys/kernel/config/usb_gadget/g1/configs/c.1/

# 绑定功能:以太网
mkdir /sys/kernel/config/usb_gadget/g1/functions/ecm.usb0
ln -s /sys/kernel/config/usb_gadget/g1/functions/ecm.usb0 /sys/kernel/config/usb_gadget/g1/configs/c.1/

# 启用 Gadget(绑定到 UDC 驱动)
echo "musb-hdrc.0.auto" > /sys/kernel/config/usb_gadget/g1/UDC
设备树绑定注意: 在设备树中,Gadget 模式通常通过设置 USB 控制器的 dr_mode 属性为 "peripheral" 或 "otg" 来启用。例如:dr_mode = "peripheral";。同时,需要确保 UDC 驱动(如 musb-hdrc)的 compatible 属性与设备树节点匹配。
USB Gadget 驱动层架构 Gadget 功能驱动层 (g_serial, g_ether, g_mass_storage, f_acm, f_ecm ...) Gadget 核心层 (UDC Core) (usb_gadget, usb_ep, usb_request, configfs 接口) UDC 驱动层 (dwc3-udc, musb-hdrc, chipidea-udc ...) 数据流方向:USB 主机 ← UDC 硬件 ← UDC 驱动 ← Gadget 核心 ← 功能驱动 ConfigFS 允许在用户空间动态组合功能驱动,无需编写内核代码

2.6 四层架构对比总结

下表从职责、数据流方向、典型驱动和硬件接口四个维度,对比主机侧和设备侧的架构层次:

对比维度 主机侧(Host) 设备侧(Device / Gadget)
顶层驱动 USB 设备驱动(usb-storage, usbhid) Gadget 功能驱动(g_serial, g_ether)
核心层 USB Core(urb, usb_device, usb_interface) Gadget Core(usb_gadget, usb_ep, usb_request)
底层硬件抽象 HCD(ehci-hcd, xhci-hcd) UDC 驱动(dwc3-udc, musb-hdrc)
数据流方向 用户空间 → 设备驱动 → Core → HCD → 硬件 硬件 → UDC 驱动 → Core → 功能驱动 → 用户空间
设备树角色 配置主机控制器(dr_mode = "host") 配置设备控制器(dr_mode = "peripheral")
架构设计启示: 无论是主机侧还是设备侧,Linux USB 子系统都遵循“核心层 + 硬件抽象层 + 功能驱动层”的三层模式。这种设计使得驱动开发人员可以专注于功能逻辑,而将硬件差异和协议细节交给核心层和硬件抽象层处理。在后续章节中,我们将深入探讨如何编写一个实际的 USB 设备驱动,并为其配置设备树绑定。