1. USB子系统概述:主机控制器、设备端与总线拓扑结构,URB在USB通信中的核心地位
USB(Universal Serial Bus)子系统是Linux内核中最为复杂且成熟的设备驱动框架之一。它采用树形拓扑结构,由USB主机控制器、USB设备以及集线器(Hub)三层实体构成。在软件层面,URB(USB Request Block,USB请求块)是贯穿整个通信过程的核心数据载体,所有USB事务最终都通过URB进行封装与传递。
核心要点:理解USB子系统的分层架构与URB的枢纽作用,是掌握中断端点与URB协同工作的前提。
1.1 USB总线拓扑结构
USB总线采用主从式星形拓扑,主机端(Host)作为唯一的主控节点,设备端(Device)作为从节点。集线器(Hub)负责扩展端口,形成层级化的树状网络。
- 根集线器(Root Hub):集成在主机控制器内部,是总线拓扑的起点。
- 外部集线器(External Hub):可级联,最多支持7层深度(包括根集线器)。
- 功能设备(Function Device):位于叶子节点,提供具体功能(如键盘、鼠标、摄像头)。
1.2 USB主机控制器
USB主机控制器(Host Controller)是硬件层面的核心,负责管理总线上的数据传输。Linux内核支持多种主机控制器标准,每种标准对应不同的驱动框架。
| 控制器标准 | 总线类型 | 速度支持 | Linux驱动 |
|---|---|---|---|
| UHCI | PCI | USB 1.1(全速/低速) | uhci-hcd |
| OHCI | PCI / 嵌入式 | USB 1.1(全速/低速) | ohci-hcd |
| EHCI | PCI | USB 2.0(高速) | ehci-hcd |
| xHCI | PCI / ACPI | USB 3.x(超高速) | xhci-hcd |
经验提示:在嵌入式系统中,OHCI和xHCI较为常见。xHCI是唯一向后兼容USB 2.0/1.1的控制器标准,支持所有速度等级。
1.3 USB设备端与端点
每个USB设备在逻辑上由一组端点(Endpoint)构成。端点是USB通信的最小逻辑单元,每个端点具有唯一的地址和传输方向。
- 端点0(默认控制端点):每个设备必须包含,用于设备枚举和控制传输。
- 中断端点(Interrupt Endpoint):用于周期性、低延迟的数据传输,如键盘、鼠标、游戏手柄。
- 批量端点(Bulk Endpoint):用于大块数据传输,无实时性要求,如U盘、打印机。
- 等时端点(Isochronous Endpoint):用于实时流数据,允许少量丢包,如音频、视频。
1.4 URB在USB通信中的核心地位
URB(USB Request Block)是Linux USB子系统中最核心的数据结构。它封装了一次USB事务所需的所有信息:目标设备、目标端点、传输方向、数据缓冲区、回调函数等。无论是内核中的USB设备驱动,还是主机控制器驱动,都通过URB进行交互。
URB的本质:URB是USB通信的“工作订单”。驱动提交URB,主机控制器执行URB,完成后通过回调通知驱动。这种异步模型使得USB子系统能够高效处理并发事务。
1.4.1 URB的生命周期
- 创建:驱动通过
usb_alloc_urb()分配URB结构体。 - 初始化:填充URB字段,包括目标端点、传输类型、数据缓冲区、回调函数等。
- 提交:调用
usb_submit_urb()将URB提交给主机控制器。 - 执行:主机控制器根据URB描述执行USB事务(Token、Data、Handshake阶段)。
- 完成:事务完成后,主机控制器调用URB的回调函数,驱动处理结果。
- 释放:驱动调用
usb_free_urb()释放URB资源。
1.4.2 URB数据结构核心字段
URB结构体定义在 <linux/usb.h> 中,以下是最常用的字段:
struct urb {
/* 私有字段:由USB核心使用,驱动不应直接修改 */
struct kref kref; // 引用计数
void *hcpriv; // 主机控制器私有数据
int unlinked; // 取消链接标志
/* 公共字段:驱动需要填充 */
struct usb_device *dev; // 目标USB设备
unsigned int pipe; // 管道:包含端点地址、方向、类型
int status; // 传输状态(-EINPROGRESS表示进行中)
unsigned int transfer_flags; // 传输标志(如URB_NO_TRANSFER_DMA_MAP)
void *transfer_buffer; // 数据缓冲区指针
dma_addr_t transfer_dma; // DMA缓冲区地址(如果使用DMA)
int transfer_buffer_length; // 缓冲区长度
int actual_length; // 实际传输的数据长度
unsigned char *setup_packet; // 控制传输的设置包(仅控制端点)
int interval; // 中断端点的轮询间隔(单位:ms)
int error_count; // 等时传输的错误计数
void *context; // 回调上下文指针
usb_complete_t complete; // 完成回调函数
};
注意事项:驱动在提交URB后,不应修改URB的公共字段,直到回调函数被调用。回调函数在中断上下文中执行,必须快速返回,不能睡眠。
1.5 URB与中断端点的协同关系
中断端点(Interrupt Endpoint)是USB规范中为低延迟、周期性传输设计的端点类型。在Linux USB子系统中,中断端点的数据传输完全依赖URB机制。驱动通过提交URB到中断端点,实现数据的轮询接收或发送。
- 轮询间隔(bInterval):中断端点在描述符中声明轮询间隔,主机控制器按此间隔调度事务。
- URB提交:驱动调用
usb_submit_urb()将URB提交到中断端点,主机控制器在每次轮询间隔执行一次事务。 - 自动重提交:在回调函数中,驱动可以重新提交相同的URB,实现连续的数据流接收。
典型场景:USB鼠标驱动在探测阶段分配并提交一个中断URB,每次鼠标移动或按键时,主机控制器自动将数据填入URB缓冲区并调用回调,驱动解析数据后重新提交URB,形成循环。
1.6 本章小结
本章从USB子系统的硬件拓扑出发,介绍了主机控制器、设备端点以及URB在通信中的核心地位。关键知识点总结如下:
| 知识点 | 核心内容 |
|---|---|
| USB拓扑结构 | 主机-集线器-设备的三层树形结构,最大7层深度 |
| 主机控制器 | UHCI/OHCI/EHCI/xHCI四种标准,xHCI兼容所有速度 |
| 设备端点 | 控制、中断、批量、等时四种类型,端点0为默认控制端点 |
| URB核心地位 | 封装USB事务所有信息,驱动与主机控制器通过URB交互 |
| 中断端点协同 | 驱动提交中断URB,主机控制器按间隔轮询,回调驱动处理数据 |