3. Linux USB子系统架构
批量传输(Bulk Transfer)是 USB 协议中为数据完整性设计的传输类型,在 Linux 驱动开发中广泛应用于 U 盘、网卡、打印机等大容量非实时设备。理解批量传输的协议特点、端点描述符结构、最大包大小与带宽预留机制,是编写高性能批量驱动的基础。
3.1 批量传输的协议特点
批量传输在 USB 协议中具有以下核心特征:
- 数据完整性优先:硬件层自动执行 CRC 校验与重传,保证数据无差错到达。
- 无固定带宽保证:总线空闲时批量传输可占满带宽,但等时与中断传输优先占用。
- 流控机制:通过 NYET(Not Yet)握手与数据包 Ping 协议实现端点级流量控制。
- 单向或双向:每个批量端点仅支持 IN(设备到主机)或 OUT(主机到设备)一个方向。
- 数据包分帧:批量传输数据被拆分为多个数据包(Data Packet),每个包以 DATA0/DATA1 交替同步。
关键区别:批量传输与中断传输的最大差异在于——批量传输没有轮询间隔约束,主机控制器在每帧(微帧)的剩余时间中调度批量事务;中断传输则保证每 N 个微帧至少有一次服务机会。
驱动开发提示:批量端点常用于块存储与批量数据流场景。在 Linux 内核中,批量 URB 的完成回调(complete callback)可能被延迟调度,驱动不应假设实时响应。
3.2 批量端点描述符
在 USB 描述符体系中,批量端点通过 端点描述符(Endpoint Descriptor) 中的 bmAttributes 字段标识。Linux 内核通过 struct usb_endpoint_descriptor 访问这些信息。
| 字段 | 偏移 | 大小 | 说明 |
|---|---|---|---|
| bLength | 0 | 1 字节 | 描述符长度,固定为 7 |
| bDescriptorType | 1 | 1 字节 | 端点描述符类型,值为 0x05 |
| bEndpointAddress | 2 | 1 字节 | 端点号(bit 3-0)与方向(bit 7:0=OUT,1=IN) |
| bmAttributes | 3 | 1 字节 | bit 1-0 = 0x02 表示批量传输 |
| wMaxPacketSize | 4 | 2 字节 | 最大包大小(字节),高速模式含额外事务数位 |
| bInterval | 6 | 1 字节 | 批量端点忽略此字段(设为 0) |
常见误区:批量端点的
bInterval 字段在 USB 2.0 规范中定义为“忽略”,但某些主机控制器会检查该值。驱动开发时建议将其初始化为 0,避免兼容性问题。
Linux 内核中解析批量端点描述符的典型代码片段:
/* 遍历接口的端点描述符,查找批量端点 */
struct usb_host_endpoint *ep;
int i;
for (i = 0; i < udev->actconfig->desc.bNumEndpoints; i++) {
ep = &udev->actconfig->interface[0]->altsetting[0]->endpoint[i];
if (usb_endpoint_is_bulk_in(&ep->desc)) {
bulk_in_pipe = usb_rcvbulkpipe(udev, ep->desc.bEndpointAddress);
bulk_in_maxp = usb_endpoint_maxp(&ep->desc);
break;
}
}
3.3 最大包大小与带宽预留
批量传输的最大包大小(MaxPacketSize)由端点描述符的 wMaxPacketSize 字段定义,不同 USB 速度模式下取值不同:
| USB 速度 | 最大包大小 | 每微帧事务数 | 理论峰值带宽 |
|---|---|---|---|
| 低速 (1.5 Mbps) | 8 字节 | 1 | 8 字节/帧 ≈ 0.8 KB/s |
| 全速 (12 Mbps) | 8/16/32/64 字节 | 1 | 64 字节/帧 ≈ 64 KB/s |
| 高速 (480 Mbps) | 512 字节 | 1/2/3(微帧) | 512×3/125μs ≈ 12.288 MB/s |
| 超高速 (5 Gbps) | 1024 字节 | 1(突发模式) | 1024×N/125μs(取决于突发长度) |
带宽预留机制:批量传输不预留固定带宽。主机控制器在每帧(或微帧)中,先服务等时传输和中断传输,剩余时间全部用于批量传输。这意味着批量传输的瞬时带宽可以很高,但延迟不可预测。
高速模式下,wMaxPacketSize 的高 2 位(bit 12-11)编码了每微帧的额外事务数:
- 00:每微帧 1 个事务(基础模式)
- 01:每微帧 2 个事务
- 10:每微帧 3 个事务
- 11:保留
Linux 内核通过 usb_endpoint_maxp() 宏获取最大包大小,通过 usb_endpoint_maxp_mult() 获取额外事务数:
/* 获取批量端点的最大包大小与额外事务数 */
u16 max_packet = usb_endpoint_maxp(&ep->desc);
int extra_txns = usb_endpoint_maxp_mult(&ep->desc);
/* 计算实际每微帧可传输的数据量 */
u32 per_microframe = max_packet * (1 + extra_txns);
pr_info("Bulk EP: maxp=%u, extra_txns=%d, per_microframe=%u\n",
max_packet, extra_txns, per_microframe);
3.4 批量传输性能影响因素
在 Linux 驱动中,批量传输的实际性能受以下因素制约:
- URB 缓冲区大小:较大的 URB 缓冲区(如 64 KB)可减少 URB 提交次数,降低 CPU 开销。
- 端点最大包大小:全速设备若使用 64 字节最大包,理论吞吐仅为高速 512 字节的 1/8。
- 主机控制器调度策略:不同 EHCI/xHCI 控制器对批量事务的排队深度不同。
- 总线竞争:多个批量端点同时传输时,主机控制器按轮询或优先级调度。
- DMA 对齐:缓冲区未对齐可能导致额外的数据拷贝,降低吞吐。
性能测试建议:在测试批量传输性能时,应使用
usbmon 或 ftrace 跟踪 URB 提交与完成时间,结合 perf 分析 CPU 开销。典型批量驱动吞吐目标:高速 USB 设备应达到 30-40 MB/s 以上。