3. USB 包结构与传输类型
USB 通信的底层由一系列定义严格的包(Packet)构成,而高层的数据流动则通过四种传输类型(Transfer Type)来承载。理解包结构是解析 USB 总线流量的基础,掌握传输类型则是设计 USB 设备与驱动的关键。本章将深入剖析 USB 包的字节级格式,并详细对比四种传输类型的机制与适用场景。
3.1 USB 包结构
USB 总线上的所有通信都以包为最小单位。一个完整的 USB 包由多个字段按固定顺序组成,主机与设备通过解析这些字段来完成寻址、握手与数据交换。
3.1.1 包格式总览
USB 包分为令牌包(Token Packet)、数据包(Data Packet)和握手包(Handshake Packet)三大类。所有包都遵循以下通用结构:
其中 SOP 和 EOP 由底层硬件自动处理,软件驱动主要关注 PID、ADDR、ENDP 和 CRC 字段。
3.1.2 关键字段详解
| 字段 | 全称 | 长度 | 说明 |
|---|---|---|---|
| SOP | Start of Packet | 8 bit | 同步序列,用于接收端时钟同步,硬件自动处理 |
| PID | Packet Identifier | 8 bit | 高 4 位为标识符,低 4 位为校验位,标识包类型 |
| ADDR | Device Address | 7 bit | 目标设备地址,范围 0~127,地址 0 用于枚举阶段 |
| ENDP | Endpoint Number | 4 bit | 端点号,范围 0~15,控制端点 0 为默认端点 |
| CRC | Cyclic Redundancy Check | 5 bit 或 16 bit | 令牌包使用 5 位 CRC,数据包使用 16 位 CRC |
| EOP | End of Packet | 2 bit | 包结束信号,由硬件插入 SE0 状态 |
struct usb_ctrlrequest 和 urb 结构体封装了这些底层字段。驱动开发者通常不需要手动构造 PID 或 CRC,但理解包结构对调试 USB 分析仪抓包数据至关重要。
3.1.3 PID 类型与分类
PID 是包的核心标识,决定了包的角色。USB 规范定义了以下主要 PID 类型:
- 令牌类(Token): OUT (0xE1)、IN (0x69)、SETUP (0x2D)、SOF (0xA5)
- 数据类(Data): DATA0 (0xC3)、DATA1 (0x4B)、DATA2 (0x87)、MDATA (0x0F)
- 握手类(Handshake): ACK (0xD2)、NAK (0x5A)、STALL (0x1E)、NYET (0x96)
- 特殊类(Special): PRE (0x3C)、ERR (0x3C)、SPLIT (0x78)、PING (0xB4)
3.1.4 包结构示意图
下图展示了 USB 总线上三种典型包的字节级结构,帮助理解字段在总线上的实际排列顺序:
3.2 四种传输类型
USB 规范定义了四种传输类型,分别对应不同的带宽、延迟和可靠性需求。每种传输类型由一组特定的事务(Transaction)组成,事务则由上述的包序列构成。
3.2.1 控制传输(Control Transfer)
控制传输是 USB 最核心的传输类型,用于设备枚举、配置和命令控制。它采用“建立-数据-状态”三阶段模型:
- 建立阶段(Setup Stage): 主机发送 SETUP 令牌 + DATA0 包,包含 8 字节的
setup_packet(请求类型、请求码、值、索引、长度)。 - 数据阶段(Data Stage): 可选,根据建立阶段的方向,进行 IN 或 OUT 数据传输,使用 DATA0/DATA1 交替翻转。
- 状态阶段(Status Stage): 用于确认传输完成,方向与数据阶段相反,使用 DATA1 包。
| 特性 | 说明 |
|---|---|
| 端点类型 | 控制端点(Endpoint 0 必须支持) |
| 最大包长 | 低速 8 字节,全速 8/16/32/64 字节,高速 64 字节 |
| 带宽保证 | 保留 10% 总线带宽 |
| 错误重试 | 硬件自动重试,直到成功或超时 |
| 适用场景 | 设备枚举、获取描述符、设置配置、类特定命令 |
3.2.2 批量传输(Bulk Transfer)
批量传输用于传输大量数据,但不保证实时性。它利用空闲总线带宽,在总线繁忙时可能被延迟。
- 事务组成: 令牌包(IN/OUT) + 数据包(DATA0/DATA1) + 握手包(ACK/NAK/STALL)
- 数据翻转: 使用 DATA0/DATA1 交替翻转机制保证数据完整性
- 流控机制: 设备通过 NAK 握手通知主机尚未准备好
| 特性 | 说明 |
|---|---|
| 端点类型 | 批量端点(Bulk Endpoint) |
| 最大包长 | 全速 8/16/32/64 字节,高速 512 字节,超高速 1024 字节 |
| 带宽保证 | 无保证,使用剩余带宽 |
| 错误重试 | 硬件自动重试,基于超时和重试次数 |
| 适用场景 | U 盘读写、打印机数据、大容量存储 |
3.2.3 中断传输(Interrupt Transfer)
中断传输并非硬件中断,而是主机以固定轮询间隔查询设备是否有数据需要传输。它保证最大延迟时间。
- 轮询机制: 主机在每帧(全速)或微帧(高速)中查询中断端点
- bInterval: 端点描述符中的字段,定义轮询间隔(1~255 帧/微帧)
- 数据保证: 与批量传输一样使用 DATA0/DATA1 翻转和错误重试
| 特性 | 说明 |
|---|---|
| 端点类型 | 中断端点(Interrupt Endpoint) |
| 最大包长 | 低速 8 字节,全速 64 字节,高速 1024 字节 |
| 带宽保证 | 保证最大延迟,全速每帧最多 1 次,高速每微帧最多 3 次 |
| 适用场景 | HID 设备(键盘、鼠标)、游戏手柄、人机交互设备 |
3.2.4 同步传输(Isochronous Transfer)
同步传输用于对时间敏感但对数据完整性要求不高的场景。它不保证数据送达,没有握手阶段和重试机制。
- 无握手: 发送方只发送数据,不等待 ACK/NAK
- 无重试: 数据丢失或损坏不会重传
- 预分配带宽: 在总线调度中预留固定带宽
| 特性 | 说明 |
|---|---|
| 端点类型 | 同步端点(Isochronous Endpoint) |
| 最大包长 | 全速 1023 字节,高速 1024 字节 |
| 带宽保证 | 预分配带宽,最多占 80% 总线带宽 |
| 错误处理 | 无重试,CRC 错误时丢弃数据 |
| 适用场景 | 音频流、视频流、USB 摄像头实时数据 |
3.2.5 四种传输类型对比
| 对比维度 | 控制传输 | 批量传输 | 中断传输 | 同步传输 |
|---|---|---|---|---|
| 可靠性 | 高(硬件重试) | 高(硬件重试) | 高(硬件重试) | 低(无重试) |
| 实时性 | 中等 | 低 | 高(轮询保证) | 最高(预分配带宽) |
| 数据量 | 小(通常 ≤64 字节) | 大(批量传输) | 中等(周期性小数据) | 大(流式数据) |
| 带宽预留 | 10% | 剩余带宽 | 按需预留 | 最多 80% |
| 握手阶段 | 有 | 有 | 有 | 无 |
| 典型设备 | 所有 USB 设备 | U 盘、硬盘 | 键盘、鼠标 | 摄像头、音箱 |
3.3 传输类型与事务流程
每种传输类型由多个事务(Transaction)组成,而事务是包序列的完整交换。下图展示了四种传输类型在总线上的典型事务流程:
3.4 驱动开发中的传输选择策略
- 设备枚举和标准请求 → 控制传输(
usb_control_msg()) - 大块数据无实时要求 → 批量传输(
usb_bulk_msg()或 URB) - 周期性小数据需要低延迟 → 中断传输(
usb_interrupt_msg()或 URB) - 音视频流允许丢帧 → 同步传输(
usb_submit_urb()设置 URB_ISO_ASAP)
struct usb_ctrlrequest req;
req.bRequestType = USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE;
req.bRequest = USB_REQ_GET_DESCRIPTOR;
req.wValue = cpu_to_le16(USB_DT_DEVICE << 8);
req.wIndex = 0;
req.wLength = cpu_to_le16(sizeof(struct usb_device_descriptor));
// 然后通过 usb_control_msg() 发送
3.5 本章小结
USB 包结构是总线通信的原子单元,PID、ADDR、ENDP 和 CRC 构成了包的核心字段。四种传输类型分别面向不同的应用场景:控制传输保障枚举与配置的可靠性,批量传输优化大块数据吞吐,中断传输保证人机交互的实时响应,同步传输满足音视频流的带宽需求。在驱动开发中,正确选择传输类型并理解其事务流程,是编写高效稳定 USB 驱动的关键前提。