2. USB协议基础:包结构、传输类型与帧/微帧
USB(Universal Serial Bus)协议采用主机-从机(Host-Device)架构,所有通信均由主机发起。理解USB协议的基础——包结构、四种传输类型以及帧/微帧机制——是开发USB Host驱动的先决条件。本章将深入剖析这些核心概念,为后续的热插拔检测与中断传输处理奠定坚实的理论基础。
2.1 USB包结构:通信的最小单元
USB总线上的所有数据交换都以“包(Packet)”为单位进行。一个USB包由多个字段按顺序组成,其基本格式如下:
| 字段 | 长度(位) | 说明 |
|---|---|---|
| SYNC | 8 | 同步序列,用于接收器与发送器时钟同步。 |
| PID | 8 | 包标识符,由4位类型和4位校验组成,定义包类型(如令牌、数据、握手)。 |
| ADDR | 7 | 设备地址,范围0~127,地址0用于默认控制管道。 |
| ENDP | 4 | 端点号,每个设备最多支持16个端点(0~15)。 |
| DATA | 0~1024 | 数据负载,长度取决于传输类型和速度。 |
| CRC | 5或16 | 循环冗余校验,用于检测传输错误。 |
| EOP | — | 包结束符,由单端信号(SEO)表示。 |
根据PID的不同,USB包主要分为以下三类:
- 令牌包(Token Packet):由主机发出,用于启动一次传输事务。包括SETUP、IN、OUT和SOF(帧起始)包。
- 数据包(Data Packet):携带实际数据,分为DATA0、DATA1、DATA2(高速)和MDATA(高速)包。
- 握手包(Handshake Packet):用于确认传输状态,包括ACK(确认)、NAK(忙)、STALL(错误)和NYET(未准备好)。
2.2 四种传输类型
USB协议定义了四种传输类型,分别针对不同的应用场景。每种传输类型在带宽、延迟、错误重试等方面具有不同的特性。
| 传输类型 | 典型应用 | 带宽保证 | 错误重试 | 延迟要求 |
|---|---|---|---|---|
| 控制传输 | 设备枚举、配置、命令 | 10% 保留 | 硬件自动重试 | 中等 |
| 批量传输 | U盘、打印机、扫描仪 | 无保证 | 硬件自动重试 | 低 |
| 中断传输 | 键盘、鼠标、游戏手柄 | 有保证(轮询间隔) | 硬件自动重试 | 高 |
| 同步传输 | 音频、视频、摄像头 | 有保证(固定带宽) | 无重试 | 极高 |
2.2.1 控制传输
控制传输是USB中最复杂的传输类型,用于主机与设备之间的配置、命令和状态交换。它由两个或三个阶段组成:
- 建立阶段(Setup Stage):主机发送SETUP令牌包 + DATA0数据包(包含8字节请求描述符)。
- 数据阶段(Data Stage,可选):主机或设备发送数据,使用DATA1/DATA0交替。
- 状态阶段(Status Stage):用于确认整个控制传输完成,设备返回ACK/NAK/STALL。
usb_control_msg() 函数实现。该函数封装了URB(USB Request Block)的构建和提交过程,驱动开发者只需指定请求类型、请求码、数据缓冲区和超时时间。
2.2.2 批量传输
批量传输用于传输大量数据,但不保证带宽和延迟。它利用总线空闲时间进行传输,当总线繁忙时会被延迟。批量传输具有硬件级别的错误重试机制,确保数据完整性。
2.2.3 中断传输
中断传输是本章的重点,用于需要定期轮询的设备(如HID设备)。主机以固定的时间间隔向设备发起IN事务,查询是否有数据需要传输。中断传输具有以下特点:
- 轮询间隔:由设备端点描述符中的
bInterval字段指定,单位为帧(全速/低速)或微帧(高速)。 - 带宽保证:主机控制器会为中断传输预留带宽,确保在轮询间隔内能够完成传输。
- 错误重试:如果传输失败,主机控制器会自动重试,直到成功或达到重试次数上限。
2.2.4 同步传输
同步传输用于对时间敏感的数据流(如音频、视频),它保证固定的带宽和低延迟,但不提供错误重试。如果传输过程中发生错误,数据将被丢弃。同步传输使用DATA0和DATA1包交替,但不需要握手包确认。
2.3 帧与微帧
USB总线的时间被划分为固定长度的“帧(Frame)”或“微帧(Microframe)”,用于同步和带宽分配。
2.3.1 帧(全速/低速模式)
- 帧长度:1毫秒(ms)。
- 帧起始包(SOF):主机在每个帧开始时发送SOF包,用于同步所有设备。
- 帧号:SOF包中包含一个11位的帧号(0~2047),用于设备同步和错误检测。
- 带宽分配:每个帧的总带宽为1ms,主机控制器在帧内分配时间片给不同的传输事务。
2.3.2 微帧(高速模式)
- 微帧长度:125微秒(μs)。
- 微帧数量:每个帧包含8个微帧(8 × 125μs = 1ms)。
- 微帧起始包:每个微帧开始时发送SOF包,帧号每8个微帧递增一次。
- 优势:微帧机制允许更精细的带宽分配和更低的延迟,特别适合高速中断传输和同步传输。
bInterval = 4 表示每4个微帧(即500μs)轮询一次。驱动开发者在解析端点描述符时,必须根据设备速度正确解释 bInterval 字段。
2.4 传输事务与URB
在USB协议中,一次“传输事务(Transaction)”由令牌包、数据包(可选)和握手包(可选)组成。而Linux内核使用URB(USB Request Block)来抽象一次完整的USB传输请求。
URB是USB驱动开发的核心数据结构,它封装了以下信息:
- 目标设备:设备地址和端点号。
- 传输类型:控制、批量、中断或同步。
- 数据缓冲区:指向数据内存的指针和长度。
- 回调函数:传输完成或出错时调用的函数。
- 标志位:如是否允许DMA、是否使用中断等。
以下是一个典型的中断传输URB提交代码片段:
/* 分配中断传输URB */
struct urb *urb = usb_alloc_urb(0, GFP_KERNEL);
if (!urb) {
dev_err(&udev->dev, "Failed to allocate URB\n");
return -ENOMEM;
}
/* 填充URB */
usb_fill_int_urb(urb, udev,
usb_rcvintpipe(udev, endpoint->bEndpointAddress),
buffer, buffer_size,
complete_callback, /* 回调函数 */
context, /* 回调上下文 */
endpoint->bInterval); /* 轮询间隔 */
/* 提交URB */
retval = usb_submit_urb(urb, GFP_KERNEL);
if (retval) {
dev_err(&udev->dev, "Failed to submit URB: %d\n", retval);
usb_free_urb(urb);
return retval;
}
2.5 本章小结
本章详细介绍了USB协议的基础知识,包括:
- 包结构:SYNC、PID、ADDR、ENDP、DATA、CRC和EOP字段,以及令牌包、数据包和握手包三种类型。
- 四种传输类型:控制传输(配置/命令)、批量传输(大块数据)、中断传输(HID设备)和同步传输(音视频),每种类型在带宽、延迟和错误重试方面具有不同特性。
- 帧与微帧:全速/低速模式使用1ms帧,高速模式使用125μs微帧,微帧机制提供了更精细的带宽调度能力。
- URB:Linux内核中用于抽象USB传输请求的核心数据结构,支持异步提交和回调。