3. USB包结构与传输类型

USB 通信的底层由一系列定义严格的包(Packet)构成,而高层的数据流动则通过四种传输类型(Transfer Type)来承载。理解包结构是解析 USB 总线流量的基础,掌握传输类型则是设计 USB 设备与驱动的关键。本章将深入剖析 USB 包的字节级格式,并详细对比四种传输类型的机制与适用场景。

3.1 USB 包结构

USB 总线上的所有通信都以包为最小单位。一个完整的 USB 包由多个字段按固定顺序组成,主机与设备通过解析这些字段来完成寻址、握手与数据交换。

3.1.1 包格式总览

USB 包分为令牌包( Packet)、数据包(Data Packet)和握手包(Handshake Packet)三大类。所有包都遵循以下通用结构:

通用包字段顺序: SOP(同步域) → PID(包标识符) → 可选字段(ADDR/ENDP/数据) → CRC(循环冗余校验) → EOP(包结束)

其中 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 状态
实战提示: 在 Linux USB 驱动中,struct usb_ctrlrequest 和 urb 结构体封装了这些底层字段。驱动开发者通常不需要手动构造 PID 或 CRC,但理解包结构对调试 USB 分析仪抓包数据至关重要。

3.1.3 PID 类型与分类

PID 是包的核心标识,决定了包的角色。USB 规范定义了以下主要 PID 类型:

  • 令牌类(): 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)
避坑指南: PID 的低 4 位是校验位,由高 4 位取反得到。如果接收端发现 PID 校验错误,会直接丢弃该包。在驱动调试中,如果遇到大量 CRC 或 PID 校验错误,应优先检查 USB 信号完整性和线缆质量。

3.1.4 包结构示意图

下图展示了 USB 总线上三种典型包的字节级结构,帮助理解字段在总线上的实际排列顺序:

USB 包结构示意图(三种典型包) 令牌包 ( Packet) SOP PID ADDR ENDP CRC5 EOP 数据包 (Data Packet) SOP PID DATA (0~1024 字节) CRC16 EOP 握手包 (Handshake Packet) SOP PID EOP 字段说明: • SOP/EOP:由 USB 控制器硬件自动插入与解析,软件不可见 • PID:决定包类型,低 4 位为高 4 位的取反校验 • ADDR+ENDP:唯一标识一个端点,主机通过这对组合寻址

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)组成,而事务是包序列的完整交换。下图展示了四种传输类型在总线上的典型事务流程:

四种传输类型的事务流程对比 控制传输 SETUP 阶段 DATA 阶段 STATUS 阶段 批量传输 OUT 令牌 DATA 包 ACK/NAK 中断传输 IN 令牌 DATA 包 ACK/NAK 同步传输 OUT 令牌 DATA 包 (无握手) 关键差异总结: • 控制传输:三阶段模型,用于枚举和配置,可靠性最高 • 批量传输:数据量大,无带宽保证,适合存储类设备 • 中断传输:固定轮询间隔,保证最大延迟,适合 HID 设备 • 同步传输:无握手无重试,预分配带宽,适合音视频流

3.4 驱动开发中的传输选择策略

实战决策树: 在 Linux USB 驱动中,选择传输类型时遵循以下原则:
  • 设备枚举和标准请求 → 控制传输(usb_control_msg())
  • 大块数据无实时要求 → 批量传输(usb_bulk_msg() 或 URB)
  • 周期性小数据需要低延迟 → 中断传输(usb_interrupt_msg() 或 URB)
  • 音视频流允许丢帧 → 同步传输(usb_submit_urb() 设置 URB_ISO_ASAP)
代码示例: 在 Linux 内核中,控制传输的 setup_packet 构造如下:
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 驱动的关键前提。