4. Linux USB 子系统架构:核心层、HCD 层、设备驱动层、Gadget 层

Linux USB 子系统采用分层的模块化架构设计,将复杂的 USB 协议栈划分为四个清晰的层级。这种设计使得上层驱动开发者无需关心底层硬件细节,而底层硬件厂商也只需提供标准化的接口即可融入系统。理解这四层架构是编写 USB Host 驱动、处理热插拔与中断传输的基础。

核心概念: Linux USB 子系统从上到下依次为:Gadget 层(仅用于 Device 模式)、设备驱动层(如键盘、U盘驱动)、USB 核心层(协议管理与枚举)、HCD 层(Host Controller Driver,直接操作硬件)。本章重点聚焦 Host 侧,即核心层、HCD 层与设备驱动层。
Linux USB 子系统四层架构 Linux USB 子系统四层架构 Gadget 层(仅 Device 模式) gadgetfs / configfs / FunctionFS 设备驱动层(Device Driver) usb-storage / usbhid / usb-serial / 自定义驱动 USB 核心层(USB Core) 设备枚举 / 总线管理 / 协议抽象 / urb 路由 HCD 层(Host Controller Driver) ehci-hcd / xhci-hcd / ohci-hcd / uhci-hcd USB 硬件控制器(Host Controller) Host 侧 Device 侧

4.1 USB 核心层(USB Core)

USB Core 是 Linux USB 子系统的中枢神经,位于设备驱动层与 HCD 层之间。它负责实现 USB 协议中与硬件无关的公共逻辑,包括设备枚举、配置管理、urb 分配与路由、电源管理以及热插拔事件分发。

USB Core 核心职责
功能模块描述关键接口/文件
设备枚举检测设备插入/拔出,分配地址,读取描述符hub_port_connect_change()
urb 管理分配、提交、取消 urb,协调各层数据传输usb_submit_urb()
总线驱动管理 USB 总线拓扑,处理 hub 事件drivers/usb/core/hub.c
电源管理挂起/恢复、选择性挂起、远程唤醒usb_suspend()
设备模型维护 usb_device、usb_interface 等内核对象struct usb_device
开发提示: 在编写 USB 设备驱动时,你几乎不会直接调用 HCD 层的函数。所有与硬件的交互都通过 USB Core 提供的 API 完成,例如 usb_control_msg()、usb_bulk_msg() 和 usb_submit_urb()。USB Core 负责将这些请求转化为 HCD 层可识别的 urb。

4.2 HCD 层(Host Controller Driver)

HCD 层是 Linux USB 子系统中最接近硬件的一层,直接与 USB 主机控制器(如 EHCI、xHCI、OHCI、UHCI)的寄存器交互。它负责将 USB Core 下发的 urb 转换为特定控制器硬件能够执行的传输描述符(TD),并处理硬件中断、完成回调。

4.2.1 主流 HCD 驱动类型

HCD 驱动对应规范速度支持典型硬件
ehci-hcdEHCI 1.0High-Speed (480 Mbps)Intel/PCH 南桥
xhci-hcdxHCI 1.1/1.2SuperSpeed (5/10 Gbps) + 向下兼容Intel/AMD 原生 USB 3.x
ohci-hcdOHCI 1.0aFull/Low-Speed (12/1.5 Mbps)非 x86 平台、旧芯片组
uhci-hcdUHCI 1.1Full/Low-Speed (12/1.5 Mbps)Intel 旧款南桥

4.2.2 HCD 与 USB Core 的接口

HCD 通过 struct hc_driver 结构体向 USB Core 注册其能力。该结构体定义了所有必须实现的操作函数指针:

// 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);

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

    /* 端口状态控制 */
    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);
    /* ... 更多回调 */
};
关键约束: HCD 层的 urb_enqueue() 回调运行在中断上下文或持有自旋锁的上下文中。因此,在该回调中不能调用可能导致睡眠的函数(如 kmalloc(GFP_KERNEL)、mutex_lock())。所有内存分配必须使用 GFP_ATOMIC 标志。
HCD 层与 USB Core 交互流程 HCD 层与 USB Core 交互流程 USB Core usb_submit_urb() HCD 层 urb_enqueue() urb 提交 USB 硬件控制器 寄存器 / DMA 写 TD / 触发 中断回调 → urb 完成 → 唤醒等待队列

4.3 设备驱动层(Device Driver Layer)

设备驱动层是 Linux USB 子系统中最接近应用开发者的层级。它负责与具体的 USB 设备功能进行交互,例如键盘、鼠标、存储设备、串口转换器或自定义 HID 设备。设备驱动通过 USB Core 提供的接口与硬件通信,而无需关心底层主机控制器的差异。

4.3.1 设备驱动注册模型

每个 USB 设备驱动都需要定义一个 struct usb_driver 结构体,并调用 usb_register() 向 USB Core 注册。USB Core 在枚举新设备时,会根据设备的 idVendor、idProduct、bInterfaceClass 等匹配字段,自动调用驱动的 probe() 回调。

// 典型的 USB 设备驱动注册示例
static struct usb_device_id my_device_table[] = {
    { USB_DEVICE(0x1234, 0x5678) },  // VID:PID 匹配
    { USB_DEVICE_INFO(0xFF, 0x00, 0x00) }, // 类匹配
    { } /* 终止项 */
};
MODULE_DEVICE_TABLE(usb, my_device_table);

static int my_probe(struct usb_interface *intf,
                    const struct usb_device_id *id)
{
    struct usb_device *udev = interface_to_usbdev(intf);
    struct usb_host_interface *iface_desc = intf->cur_altsetting;
    // 获取端点信息,分配 urb,提交中断传输
    return 0;
}

static void my_disconnect(struct usb_interface *intf)
{
    // 释放 urb,取消传输,清理资源
}

static struct usb_driver my_driver = {
    .name       = "my_usb_device",
    .id_table   = my_device_table,
    .probe      = my_probe,
    .disconnect = my_disconnect,
};

module_usb_driver(my_driver);

4.3.2 设备驱动与中断传输

中断传输(Interrupt Transfer)是 USB 规范中为周期性、低延迟数据交换设计的传输类型,常用于 HID 设备(键盘、鼠标)和部分自定义设备。设备驱动通过 usb_fill_int_urb() 初始化 urb,然后调用 usb_submit_urb() 提交给 USB Core。

中断传输 urb 关键参数
参数含义典型值
pipe端点管道,由 usb_rcvintpipe() 或 usb_sndintpipe() 构造方向 + 端点号
transfer_buffer数据缓冲区指针kmalloc 分配
transfer_buffer_length缓冲区大小端点 wMaxPacketSize
interval轮询间隔(单位:帧/微帧)1~255(全速:1ms,高速:125μs)
complete传输完成回调函数自定义回调
热插拔关联: 设备驱动层的 probe() 回调是热插拔检测的终点。当 USB Core 完成设备枚举并找到匹配驱动后,probe() 被调用。驱动在此函数中提交中断 urb,从而开始接收设备上报的数据。当设备拔出时,disconnect() 被调用,驱动必须取消所有未完成的 urb 并释放资源。

4.4 Gadget 层(仅 Device 模式)

Gadget 层是 Linux USB 子系统中用于 Device(设备)模式的部分,与 Host 侧的 HCD 层对称。它允许嵌入式 Linux 设备模拟成 USB 外设(如虚拟串口、U 盘、以太网卡)。虽然本课程聚焦 Host 驱动,但理解 Gadget 层有助于完整把握 USB 子系统的对称设计。

对比维度Host 侧(HCD + Core)Device 侧(Gadget)
角色总线主控,发起传输外设,响应传输
核心结构struct usb_hcdstruct usb_gadget
驱动注册usb_hcd_register()usb_gadget_probe_driver()
传输接口urbusb_request
典型应用PC、嵌入式 Host手机、嵌入式 Device
Host 侧与 Device 侧对称架构对比 Host 侧与 Device 侧对称架构对比 Host 侧 设备驱动层 USB Core HCD 层 Device 侧 Gadget Function 驱动 Gadget API / UDC Core UDC 驱动(Gadget Controller) USB 总线

4.5 层级协作:热插拔事件流

当 USB 设备插入 Host 时,四个层级按以下顺序协作完成热插拔检测与驱动绑定:

  1. HCD 层:检测到端口状态变化(Port Status Change),触发硬件中断。
  2. USB Core:Hub 驱动轮询端口状态,调用 hub_port_connect_change(),启动设备枚举流程。
  3. USB Core:读取设备描述符、配置描述符,分配 struct usb_device,创建 usb_interface 对象。
  4. USB Core:遍历已注册的 usb_driver,匹配 id_table,调用匹配驱动的 probe() 回调。
  5. 设备驱动层:在 probe() 中初始化设备,提交中断 urb,开始正常数据传输。
调试技巧: 使用 lsusb -t 查看 USB 设备树,usbmon 捕获 USB 总线事务,cat /sys/kernel/debug/usb/devices 查看设备描述符详情。这些工具可以帮助你验证四层架构是否正常工作。