2. USB协议体系:数据包结构与传输机制

USB协议采用分层拓扑 + 主从轮询的通信模型。主机(Host)始终作为事务发起方,设备(Device)被动响应。本章聚焦USB协议最核心的两个维度:数据包结构(传输的最小原子单元)与传输类型(面向不同场景的通信契约)。

学习提示:USB协议栈分为物理层(电气信号)、数据链路层(包/事务)、传输层(管道/端点)。本章内容对应数据链路层与传输层,是驱动开发中编写URB(USB Request Block)和配置端点的基础。

2.1 USB数据包结构

USB总线上的所有通信都以数据包(Packet)为基本单位。每个包由SYNC同步域、PID包标识符、数据域(可选)、CRC校验组成。根据PID的不同,USB数据包分为四大类:

包类型 PID值(低4位) 方向 功能描述
令牌包(Token) 0x1 / 0x9 / 0xD Host → Device 标识事务开始,指定端点号、方向和设备地址
数据包(Data) 0x3 / 0xB 双向 携带实际有效载荷(DATA0 / DATA1交替翻转)
握手包(Handshake) 0x2 / 0xA / 0xE Device → Host 确认传输状态:ACK/NAK/STALL/NYET
特殊包(Special) 0x0 / 0x8 / 0xC / 0xF Host → Device PRE(前导包)、ERR(拆分事务错误)、SPLIT(高速拆分)

2.1.1 令牌包(Token Packet)

令牌包是USB事务的发起信号,由主机在每帧起始时发送。其结构固定为:SYNC + PID + 7位地址 + 4位端点号 + 5位CRC。三种核心令牌:

  • OUT令牌(PID=0x1):通知设备主机即将发送数据。
  • IN令牌(PID=0x9):请求设备向主机发送数据。
  • SETUP令牌(PID=0xD):仅用于控制传输,启动设置阶段。

2.1.2 数据包(Data Packet)

数据包紧跟在令牌包之后,最大有效载荷为1024字节(高速模式)。USB协议使用数据切换(Data Toggle)机制保证可靠性:

  • DATA0(PID=0x3):事务序列中的第一个数据包。
  • DATA1(PID=0xB):事务序列中的后续数据包,交替翻转。

主机和设备各自维护一个Toggle位,只有PID匹配时数据才被接受,否则丢弃并重传。

2.1.3 握手包(Handshake Packet)

握手包是USB协议中最短的包(仅SYNC + PID),用于反馈事务结果:

握手类型 PID 含义 触发场景
ACK 0x2 数据正确接收 正常完成
NAK 0xA 设备忙,无法处理 端点未准备好
STALL 0xE 端点挂起/错误 不支持请求或端点halt
NYET 0x6 尚未准备好(高速) 拆分事务中

2.1.4 特殊包(Special Packet)

特殊包用于扩展总线管理能力,常见于高速/低速混合拓扑:

  • PRE(前导包):主机在低速传输前发送,通知高速集线器切换端口。
  • SPLIT(拆分事务包):用于高速主机与低速/全速设备之间的拆分事务。
  • ERR(错误包):集线器向主机报告拆分事务错误。
驱动开发要点:在Linux USB子系统中,数据包结构对驱动开发者是透明的——USB核心层自动处理PID、CRC和Toggle同步。驱动只需通过struct urb描述传输方向、端点和缓冲区,底层由usb_submit_urb()完成包级封装。
USB事务序列:数据包结构交互 令牌包 OUT/IN/SETUP 数据包 DATA0 / DATA1 握手包 ACK/NAK/STALL 事务时序说明: 1. 主机发送令牌包,指定端点与方向 2. 数据包携带有效载荷,PID交替翻转 3. 设备回复握手包,ACK成功 / NAK重试 / STALL错误 特殊包 PRE/SPLIT/ERR

2.2 USB传输类型

USB协议定义了四种传输类型,分别对应不同的带宽、延迟和可靠性需求。每种传输类型绑定到特定的端点(Endpoint),端点在设备枚举时通过端点描述符声明其传输类型和最大包大小。

传输类型 端点类型 带宽保证 错误重试 延迟 典型应用
控制传输 控制端点(EP0) 10% 保留 自动重试 中等 设备枚举、配置、命令
批量传输 批量端点 尽力而为 自动重试(硬件) 大 U盘、打印机、网络
中断传输 中断端点 ≤90% 帧内 自动重试 低(轮询间隔) 鼠标、键盘、HID
等时传输 等时端点 固定带宽 不重试 最低 音频、视频、摄像头

2.2.1 控制传输(Control Transfer)

控制传输是USB协议中唯一必须支持的传输类型,每个设备至少有一个默认控制端点(端点0)。它采用2~3阶段的握手式事务:

  1. 设置阶段(Setup Stage):主机发送SETUP令牌 + DATA0包(8字节标准请求)。
  2. 数据阶段(Data Stage)(可选):主机或设备发送数据,使用DATA1/DATA0交替。
  3. 状态阶段(Status Stage):接收方返回握手包,确认整个控制传输完成。

Linux驱动中,控制传输通过usb_control_msg()封装,驱动只需填充struct usb_ctrlrequest中的bRequestType、bRequest、wValue、wIndex、wLength字段。

2.2.2 批量传输(Bulk Transfer)

批量传输用于大数据量、非实时的场景,利用总线空闲带宽传输。其特点:

  • 无带宽保证:仅在总线空闲时传输,可能被其他传输抢占。
  • 硬件重试:数据错误时自动重传,保证数据完整性。
  • 最大包大小:全速64字节,高速512字节,超高速1024字节。

在Linux中,批量传输使用usb_bulk_msg()或通过usb_fill_bulk_urb()构造URB提交。

2.2.3 中断传输(Interrupt Transfer)

中断传输并非硬件中断,而是主机轮询设备端点。设备在端点描述符中声明轮询间隔(bInterval):

  • 全速:1~255 ms
  • 高速:2^(bInterval-1)× 125 μs(微帧)
  • 超高速:2^(bInterval-1)× 125 μs

中断传输保证在轮询间隔内至少有一次传输机会,适用于HID设备、USB键盘、游戏手柄等低延迟外设。

2.2.4 等时传输(Isochronous Transfer)

等时传输是USB协议中唯一不保证数据正确性的传输类型,但提供固定的带宽和最低延迟:

  • 预分配带宽:在帧/微帧中预留固定时间片。
  • 无重试:数据错误直接丢弃,不重传。
  • 无握手:等时事务不包含握手阶段。

等时传输常用于USB摄像头、USB音频设备、数据采集卡等对实时性要求高、允许少量丢包的场景。Linux驱动中通过usb_fill_isoc_urb()构造等时URB,需指定每个帧描述符(struct usb_iso_packet_descriptor)。

常见误区:等时传输的“无重试”特性意味着驱动必须处理数据丢失。例如USB摄像头驱动中,如果等时URB返回-EXDEV(部分数据错误),驱动应丢弃该帧并等待下一帧,而不是重传。
USB四种传输类型对比 控制传输 端点0 / 双向 Setup+Data+Status 自动重试 ✓ 带宽保证 ✓ 批量传输 大数据 / 非实时 硬件重试 ✓ 带宽保证 ✗ 延迟:高 中断传输 轮询间隔 自动重试 ✓ 带宽保证 ✓ 延迟:低 等时传输 实时 / 音视频 自动重试 ✗ 带宽保证 ✓ 延迟:最低 传输类型选择指南: • 设备枚举/配置 → 控制传输(必须通过EP0) • 大块数据(U盘/存储) → 批量传输(高吞吐) • 人机交互(鼠标/键盘) → 中断传输(低延迟轮询) • 流媒体(音频/视频) → 等时传输(固定带宽,容忍丢包)

2.3 USB帧与微帧机制

USB总线采用时间分片的方式管理总线访问。主机控制器将时间划分为固定长度的帧(Frame)或微帧(Microframe),在每个帧/微帧内发起多个事务。

总线速度 帧周期 微帧数/帧 每帧最大事务数 帧起始包
低速(1.5 Mbps) 1 ms 1 约 8~16 SOF
全速(12 Mbps) 1 ms 1 约 100~200 SOF
高速(480 Mbps) 1 ms 8 约 800~1600 SOF + 微帧SOF
超高速(5 Gbps) 125 μs 1(微帧即帧) 约 4000+ 特殊包

2.3.1 帧起始包(SOF)

在每个帧/微帧的起始时刻,主机发送SOF(Start of Frame)令牌包。SOF包包含一个帧号(Frame Number),设备可据此同步时钟或检测帧丢失。SOF包结构:

  • PID:0x5(SOF)
  • 帧号:11位,范围0~2047,每帧递增
  • CRC:5位校验

2.3.2 微帧(Microframe)

高速模式下,每个1ms帧被划分为8个125μs的微帧。每个微帧以SOF包开始,主机可以在每个微帧内调度多个事务。微帧机制使得高速总线能够:

  • 更精细的带宽分配:等时传输可以按125μs粒度预留带宽。
  • 更低延迟:中断传输的轮询间隔可以低至125μs。
  • 更高吞吐:批量传输可以在多个微帧间交错传输。

2.3.3 帧调度与带宽管理

主机控制器(HC)负责在每帧/微帧内调度所有待处理的事务。调度策略遵循以下优先级:

  1. 等时传输:固定带宽,优先调度,不可超时。
  2. 中断传输:按轮询间隔调度,保证延迟上限。
  3. 控制传输:保留10%带宽,用于枚举和命令。
  4. 批量传输:使用剩余带宽,无时间保证。
驱动开发关联:在Linux USB子系统中,帧/微帧调度由主机控制器驱动(如ehci-hcd、xhci-hcd)自动完成。驱动开发者通过URB的interval字段(中断传输)和number_of_packets字段(等时传输)间接影响帧调度。例如,设置urb->interval = 1表示每帧轮询一次(全速1ms,高速125μs)。
USB帧与微帧结构(高速模式) 1 帧 = 1 ms μ帧0 μ帧1 μ帧2 μ帧3 μ帧4 μ帧5 μ帧6 μ帧7 125μs 125μs 125μs 125μs 125μs 125μs 125μs 125μs SOF SOF SOF SOF SOF SOF SOF SOF 每个微帧以SOF包开始,主机在微帧内调度等时、中断、控制和批量事务。帧号在每帧起始递增,设备用于同步。

2.4 本章小结

USB协议体系的核心在于包结构与传输类型的精确匹配