USB中断端点特性:中断传输特点、中断端点描述符、最大包大小与间隔
中断传输是USB通信中一种重要的传输类型,主要用于传输周期性、低延迟、数据量较小的数据。与字面含义不同,USB中断传输并非由设备主动发起的中断信号,而是主机在固定的时间间隔内轮询设备,检查是否有数据需要传输。理解中断端点的特性是编写高效USB驱动的基础。
2.1 中断传输特点
中断传输在USB规范中具有明确的定位,其核心特点决定了它适用的场景:
- 周期性轮询:主机控制器保证在每个服务间隔(bInterval)内对中断端点进行一次事务处理。这是中断传输最核心的保证。
- 有限延迟:由于轮询周期固定,数据传输的最大延迟是可预测的,适合人机交互设备(HID)如键盘、鼠标,以及游戏手柄等。
- 数据可靠性:中断传输包含错误检测和重试机制(如CRC校验和握手包),确保数据在传输过程中的完整性。对于全速/低速总线,还支持数据翻转(Data Toggle)同步。
- 数据量小:每个中断事务能传输的最大数据量受限于最大包大小(wMaxPacketSize),通常较小(如64字节、512字节等),不适合批量大数据流。
- 带宽保证:在USB帧/微帧中,中断传输占用预留的带宽比例,不会因为批量传输的拥塞而无限期延迟。
驱动开发提示: 不要将“中断”理解为硬件中断信号。USB中断传输本质上是主机主动的、周期性的轮询操作。设备无法主动“打断”主机,只能等待主机在下一个服务间隔来读取数据。
2.2 中断端点描述符
中断端点在USB描述符中通过端点描述符(Endpoint Descriptor)进行定义。主机在枚举阶段解析该描述符,以获取端点的传输类型、方向、最大包大小和服务间隔等信息。其结构在Linux内核头文件 include/uapi/linux/usb/ch9.h 中定义。
| 字段 | 偏移(字节) | 大小(字节) | 说明 |
|---|---|---|---|
| bLength | 0 | 1 | 描述符长度,固定为7字节 |
| bDescriptorType | 1 | 1 | 描述符类型,端点描述符值为0x05 |
| bEndpointAddress | 2 | 1 | 端点地址:Bit 7 方向(0=OUT, 1=IN),Bit 3-0 端点号 |
| bmAttributes | 3 | 1 | 传输类型:Bit 1-0 为 0x03 表示中断传输 |
| wMaxPacketSize | 4 | 2 | 该端点支持的最大包大小(字节) |
| bInterval | 6 | 1 | 轮询服务间隔(单位:帧/微帧) |
内核数据结构对应: Linux内核使用
struct usb_endpoint_descriptor 来描述端点。驱动开发中,通常通过 struct usb_host_endpoint 的 desc 成员访问该描述符。例如:ep->desc.bInterval 获取服务间隔。
2.3 最大包大小与间隔
wMaxPacketSize 和 bInterval 是中断端点最重要的两个参数,它们直接决定了数据传输的吞吐量和实时性。
2.3.1 最大包大小(wMaxPacketSize)
该字段定义了每次中断事务能够传输的最大数据字节数。其值受USB总线速度的约束,具体限制如下:
| USB 速度 | 中断端点最大包大小 | 备注 |
|---|---|---|
| 低速 (Low-Speed, 1.5 Mbps) | ≤ 8 字节 | 仅支持控制传输和中断传输 |
| 全速 (Full-Speed, 12 Mbps) | ≤ 64 字节 | 中断传输的典型大小 |
| 高速 (High-Speed, 480 Mbps) | ≤ 1024 字节 | 支持高带宽中断端点(需额外描述符) |
| 超高速 (SuperSpeed, 5 Gbps) | ≤ 1024 字节 | 支持突发传输(Burst) |
2.3.2 服务间隔(bInterval)
该字段定义了主机轮询中断端点的频率。其单位取决于USB总线速度:
- 低速/全速:单位为帧(Frame),每帧为1毫秒。bInterval的值表示每隔多少帧轮询一次。例如,bInterval=10表示每10毫秒轮询一次。
- 高速/超高速:单位为微帧(Microframe),每微帧为125微秒。bInterval的值表示每隔多少微帧轮询一次。例如,bInterval=1表示每125微秒轮询一次。
驱动配置陷阱: 在提交URB时,必须确保URB的
interval 字段与端点描述符中的 bInterval 一致。如果设置不当,可能导致主机调度异常,出现数据丢失或驱动挂起。对于高速设备,bInterval 的值通常为 1 到 16,对应 125 µs 到 2 ms 的间隔。
2.4 中断端点与URB回调的协同基础
在驱动开发中,中断端点的配置直接决定了URB(USB Request Block)的提交方式和回调函数的执行时机。理解以下协同关系至关重要:
- URB提交时机:驱动通常在
probe()函数中,根据端点描述符的bInterval和wMaxPacketSize初始化并提交URB。URB的interval字段必须与bInterval一致。 - 回调触发:当主机完成一次中断轮询(无论设备返回数据还是NAK),URB的回调函数
complete都会被调用。驱动在回调中处理接收到的数据,并重新提交URB以维持连续的轮询。 - 数据流控制:如果设备频繁发送数据,回调函数必须快速处理并重新提交URB,以避免数据丢失。如果处理速度跟不上轮询速度,可能导致URB队列溢出。
最佳实践: 在中断URB的回调函数中,不要执行耗时操作(如内存分配、文件I/O)。应使用工作队列(workqueue)或内核线程将数据推送到上层,然后立即重新提交URB,以保证轮询的连续性。