2. USB数据传输模型
USB数据传输模型是理解Linux USB设备驱动开发的核心基础。本章深入剖析USB主机控制器(OHCI/UHCI/EHCI/xHCI)、USB设备端控制器以及USB协议栈的分层架构(硬件层、HCD层、USBCore层、设备驱动层),帮助开发者建立从物理信号到驱动接口的完整认知。
2.1 USB主机控制器规范演进
USB主机控制器是系统与USB总线之间的硬件接口,负责执行总线事务、管理传输调度、处理错误恢复。不同USB版本对应不同的主机控制器规范:
| 规范 | USB版本 | 传输速率 | 特点 |
|---|---|---|---|
| OHCI | USB 1.x | 1.5 Mbps / 12 Mbps | 硬件管理事务列表,CPU负载低 |
| UHCI | USB 1.x | 1.5 Mbps / 12 Mbps | 软件管理调度,CPU负载高,成本低 |
| EHCI | USB 2.0 | 480 Mbps | 高速传输,兼容OHCI/UHCI |
| xHCI | USB 3.x | 5 Gbps / 10 Gbps | 统一架构,支持所有速率,可扩展 |
关键区别:OHCI与UHCI都用于USB 1.x,但OHCI将调度逻辑固化在硬件中,UHCI则依赖软件驱动完成调度。EHCI仅处理高速传输,低速/全速设备通过配套控制器(companion controller)接管。xHCI彻底统一了所有速率等级的传输管理。
2.1.1 OHCI与UHCI对比
- OHCI(Open Host Controller Interface):由Compaq、Microsoft、National Semiconductor联合制定。硬件维护周期性帧列表(Frame List)和中断列表,软件只需填充端点描述符(Endpoint Descriptor, ED)和传输描述符(Transfer Descriptor, TD)。
- UHCI(Universal Host Controller Interface):由Intel主导。硬件只提供基本帧定时,软件必须手动构建队列头(Queue Head, QH)和传输描述符(TD),调度逻辑完全在驱动中实现。
开发建议:在嵌入式系统中,OHCI因硬件卸载调度而更受欢迎;UHCI多见于x86平台,因其硬件成本更低。现代系统已全面转向xHCI。
2.1.2 EHCI与xHCI架构
EHCI引入异步列表(Async List)和周期性列表(Periodic List)分离调度,支持高速批量传输和中断传输。xHCI则采用命令环(Command Ring)、事件环(Event Ring)和传输环(Transfer Ring)的环形缓冲区模型,极大简化了驱动开发。
注意:xHCI的环形缓冲区模型与OHCI/UHCI/EHCI的链表模型完全不同,驱动开发时不能复用旧有数据结构。
2.2 USB协议栈分层架构
Linux USB协议栈采用经典的分层设计,从下至上依次为:硬件层、HCD层、USBCore层、设备驱动层。每一层封装下层细节,向上层提供抽象接口。
2.2.1 硬件层
硬件层包含USB主机控制器芯片及其寄存器接口。主机控制器通过系统总线(PCI、AHB等)与CPU连接,管理USB端口的电气信号、包传输、错误检测和流量控制。硬件层对外暴露MMIO寄存器或I/O端口,供HCD驱动访问。
2.2.2 HCD层(Host Controller Driver)
HCD层是硬件与USBCore之间的桥梁。每个主机控制器规范对应一个HCD驱动:
- ohci-hcd:实现OHCI规范,管理帧列表和中断列表。
- uhci-hcd:实现UHCI规范,软件调度队列头和传输描述符。
- ehci-hcd:实现EHCI规范,管理异步列表和周期性列表。
- xhci-hcd:实现xHCI规范,管理命令环、事件环和传输环。
HCD层向上注册struct hc_driver结构体,提供start、stop、urb_enqueue、urb_dequeue等回调函数。
// hc_driver结构体核心回调(简化)
struct hc_driver {
const char *description;
int (*start)(struct usb_hcd *hcd);
void (*stop)(struct usb_hcd *hcd);
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);
// ... 其他回调
};
2.2.3 USBCore层
USBCore层是协议栈的中枢,提供以下核心功能:
- URB管理:分配、提交、取消、完成回调。
- 设备枚举:检测设备插入/拔出,分配地址,读取描述符。
- 配置解析:解析设备、配置、接口、端点描述符。
- 驱动匹配:根据
id_table匹配设备和驱动。 - 电源管理:挂起/恢复、远程唤醒。
USBCore层对外暴露usb_submit_urb、usb_alloc_urb、usb_kill_urb等API,供设备驱动层调用。
2.2.4 设备驱动层
设备驱动层是开发者最常接触的层次。它通过USBCore提供的接口与USB设备通信,实现特定设备的功能。设备驱动层注册struct usb_driver或struct usb_class_driver,处理URB完成回调,解析设备数据。
// USB设备驱动注册示例
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);
2.3 USB设备端控制器
USB设备端控制器(Device Controller)位于USB设备侧,负责响应主机控制器的请求。常见的设备端控制器包括:
- UDC(USB Device Controller):集成在SoC或微控制器中,如Synopsys DesignWare、Chipidea、Freescale USB。
- Gadget框架:Linux通过Gadget框架将设备端控制器抽象为
struct usb_gadget,支持多种功能(串口、存储、网络等)。
主机侧 vs 设备侧:主机侧使用HCD驱动管理主机控制器,设备侧使用UDC驱动管理设备控制器。两者通过USB总线上的包交换实现通信。
2.4 URB传输机制概述
URB(USB Request Block)是Linux USB协议栈中数据传输的基本单元。它封装了一次USB传输的所有信息:目标端点、传输方向、数据缓冲区、传输类型、完成回调等。
2.5 分层数据流实例
以USB鼠标为例,数据从设备到应用程序的完整路径:
- 硬件层:鼠标通过USB线缆发送中断包,主机控制器接收并触发DMA传输。
- HCD层:xhci-hcd从事件环中读取完成事件,将数据填入URB缓冲区。
- USBCore层:调用URB完成回调,通知HID驱动数据就绪。
- 设备驱动层:HID驱动解析报告描述符,将鼠标移动/按键事件上报到输入子系统。
调试技巧:使用usbmon工具可以捕获USB总线上的原始包,帮助定位分层问题。启用CONFIG_USB_MON内核选项后,通过/sys/kernel/debug/usbmon接口读取数据。
2.6 本章小结
| 层次 | 核心职责 | 关键数据结构/接口 |
|---|---|---|
| 硬件层 | 物理信号收发、包传输 | MMIO寄存器、DMA引擎 |
| HCD层 | 硬件抽象、传输调度 | struct hc_driver、struct usb_hcd |
| USBCore层 | URB管理、设备枚举、驱动匹配 | usb_submit_urb、struct usb_device |
| 设备驱动层 | 设备功能实现、数据解析 | struct usb_driver、struct urb |