2. Linux USB子系统架构:USB核心层、HCD、UDC分层模型
Linux USB子系统采用经典的分层架构设计,将复杂的USB协议栈抽象为三个清晰的层次:USB核心层、主机控制器驱动(HCD)和设备控制器驱动(UDC)。这种分层模型使得USB驱动开发可以专注于特定角色,同时复用核心层的通用协议处理逻辑。
核心要点:USB子系统通过分层解耦,让主机侧(HCD)和设备侧(UDC)共享同一套核心层API,而底层硬件差异被驱动层完全隔离。
2.1 分层模型总览
下图展示了USB子系统在Linux内核中的完整分层结构,从顶层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驱动至关重要。下面以主机侧发送一个批量传输为例:
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子系统在系统启动时的初始化顺序严格遵循分层依赖关系:
- USB核心层初始化:
usb_init()注册总线类型、创建sysfs文件、初始化hub驱动。 - HCD/UDC驱动注册:各平台通过
module_init()或platform_driver_register()注册HCD或UDC驱动。 - 硬件探测:驱动探测函数读取设备树或PCI配置,初始化控制器寄存器。
- 创建root hub:HCD创建虚拟root hub设备,触发USB总线枚举。
- 设备枚举:hub线程检测端口状态变化,执行USB设备枚举流程。
- 驱动绑定:核心层根据设备ID表匹配USB设备驱动,调用驱动的
probe()函数。