1. USB中断基础概念

1.1 USB中断传输的定义

USB中断传输(Interrupt Transfer)是USB规范定义的四种标准传输类型之一,用于保证有限延迟的数据传输。与字面含义不同,USB中断传输并非由设备主动发起的中断信号,而是主机以固定轮询周期主动查询设备是否有数据需要传输。

核心定义:中断传输是一种周期性、低延迟、有保证带宽的传输方式,主机控制器按预定时间间隔轮询设备,设备在收到IN令牌包后返回数据或NAK握手包。

1.2 中断传输的特点

特性 描述 典型值
周期性 主机以固定间隔(bInterval)轮询设备 1ms ~ 255ms(全速/低速)
延迟保证 最大延迟由轮询间隔决定,可预测 ≤ bInterval × 1ms
带宽预留 每帧/微帧预留固定比例带宽 全速≤90%,高速≤80%
错误重试 支持硬件级自动重试(最多3次) 3次重试后报告错误
数据完整性 使用CRC16校验,保证数据正确 数据阶段CRC16
最大数据载荷 受限于端点描述符wMaxPacketSize 低速8B,全速64B,高速1024B
关键区别:中断传输与批量传输(Bulk)最大的不同在于延迟确定性。批量传输没有时间保证,而中断传输保证在bInterval时间内至少被轮询一次。

1.3 中断传输的适用场景

中断传输最适合以下两类设备场景:

  • HID(人机交互设备):键盘、鼠标、触摸板、游戏手柄等需要及时响应用户输入的设备。
  • 实时数据流:传感器数据采集、工业控制信号、MIDI音频事件等对延迟敏感但数据量较小的应用。

1.4 中断传输与轮询机制

下图展示了USB中断传输的完整轮询流程:

USB中断传输轮询流程 主机控制器 bInterval 定时器 发送 IN 令牌 设备端点 数据就绪? 返回 DATA 包 返回 NAK 主机处理数据 等待下一轮询周期 是 否 说明:主机按bInterval周期发送IN令牌,设备有数据则返回DATA包,无数据则返回NAK

1.5 中断端点描述符

中断端点在USB描述符中通过以下字段定义其行为:

struct usb_endpoint_descriptor {
    __u8  bLength;            // 描述符长度(7字节)
    __u8  bDescriptorType;    // 端点描述符类型(0x05)
    __u8  bEndpointAddress;   // 端点地址(bit7:方向,0-3:端点号)
    __u8  bmAttributes;       // 传输类型(0x03 = 中断传输)
    __le16 wMaxPacketSize;    // 最大数据包大小
    __u8  bInterval;          // 轮询间隔(单位:帧/微帧)
} __attribute__ ((packed));
注意:bInterval字段在不同速度下单位不同:
  • 低速/全速:单位 = 1ms(帧),取值范围 1~255
  • 高速:单位 = 125µs(微帧),取值范围 1~16(实际间隔 = 2^(bInterval-1) × 125µs)
  • 超高速:单位 = 125µs,取值范围 1~16

1.6 中断传输与HID设备

HID(Human Interface Device)是中断传输最典型的应用场景。以USB键盘为例,其数据流如下:

USB HID键盘中断传输数据流 按键按下 HID报告 (8字节) 中断端点 USB总线 HID驱动 输入子系统 用户空间 典型HID报告:1字节修饰键 + 1字节保留 + 6字节按键数组(最多同时报告6个按键) 轮询间隔通常为8ms(125Hz),保证按键延迟在可接受范围内

1.7 中断传输的带宽计算

在设计USB中断传输时,需要计算带宽占用以确保不超过USB规范限制:

/* 中断传输带宽计算公式 */
带宽占用 = (wMaxPacketSize + 协议开销) / bInterval

/* 全速USB示例:HID键盘 */
wMaxPacketSize = 8 bytes
协议开销 = 13 bytes (SYNC+SOF+令牌+数据+握手)
bInterval = 8 ms

每帧带宽 = (8 + 13) / 8 = 2.625 bytes/frame
带宽占比 = 2.625 / 64 = 4.1% (远低于90%限制)

/* 高速USB示例:音频设备 */
wMaxPacketSize = 64 bytes
协议开销 = 13 bytes
bInterval = 1 (2^0 × 125µs = 125µs)

每微帧带宽 = (64 + 13) = 77 bytes/microframe
带宽占比 = 77 / 1024 = 7.5% (远低于80%限制)
设计建议:
  • HID设备:bInterval设为8~16ms,平衡延迟与带宽
  • 实时传感器:bInterval设为1~4ms,保证数据实时性
  • 避免将bInterval设为0(规范不允许)
  • 高速设备利用微帧机制可实现更低的延迟

1.8 中断传输与其它传输类型的对比

特性 中断传输 批量传输 等时传输 控制传输
周期性 是(固定间隔) 否 是(固定间隔) 否
延迟保证 有 无 有 无
带宽预留 有 无 有 无
错误重试 硬件自动重试 硬件自动重试 无重试 硬件自动重试
数据完整性 CRC16保证 CRC16保证 无校验 CRC16保证
典型应用 HID、传感器 存储、文件传输 音频、视频 枚举、配置

1.9 中断传输在Linux内核中的实现

在Linux USB子系统中,中断传输通过URB(USB Request Block)来管理:

/* 创建中断传输URB */
struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags);

/* 填充中断传输URB */
void usb_fill_int_urb(struct urb *urb,
                      struct usb_device *dev,
                      unsigned int pipe,
                      void *transfer_buffer,
                      int buffer_length,
                      usb_complete_t complete_fn,
                      void *context,
                      int interval);

/* 提交URB开始中断传输 */
int usb_submit_urb(struct urb *urb, gfp_t mem_flags);

/* 典型中断传输回调函数 */
static void interrupt_callback(struct urb *urb)
{
    struct usb_device *dev = urb->dev;
    int status = urb->status;

    switch (status) {
    case 0: /* 成功接收数据 */
        process_received_data(urb->transfer_buffer,
                              urb->actual_length);
        break;
    case -ENOENT: /* URB被取消 */
    case -ECONNRESET: /* 设备断开 */
        return;
    case -ESHUTDOWN: /* 主机控制器关闭 */
        return;
    default: /* 其他错误 */
        dev_err(&dev->dev, "中断传输错误: %d\n", status);
        break;
    }

    /* 重新提交URB以继续接收 */
    usb_submit_urb(urb, GFP_ATOMIC);
}
常见陷阱:
  • 中断URB的回调函数中必须重新提交URB才能持续接收数据
  • 回调函数运行在中断上下文,不能调用可能睡眠的函数
  • transfer_buffer必须使用DMA安全的缓冲区(kmalloc,非栈内存)
  • interval参数必须与端点描述符中的bInterval匹配

1.10 中断传输的故障排查要点

在开发中断传输驱动时,以下问题需要重点关注:

  • 轮询间隔不匹配:驱动中设置的interval必须与设备描述符一致,否则可能导致设备无响应
  • 数据包大小超限:实际接收数据超过wMaxPacketSize会导致数据截断
  • URB提交失败:检查设备状态、端点号、方向是否正确
  • 回调函数阻塞:中断回调中执行耗时操作会阻塞整个USB子系统
  • NAK风暴:设备频繁返回NAK会浪费总线带宽,需调整轮询间隔
调试命令:使用 lsusb -v 查看设备端点描述符,usbmon 跟踪URB传输过程,perf 分析中断处理延迟。