2. USB协议基础回顾:USB总线拓扑结构、USB传输类型、USB描述符体系

各位同学,咱们今天聊点基础但极其重要的东西。USB协议,说白了就是一套让设备跟主机“对话”的规矩。我做了这么多年驱动,发现很多问题其实都出在基础没打牢。你想想看,如果连USB怎么连的、数据怎么传的、设备怎么描述自己的都不清楚,那写出来的驱动大概率是跑不起来的。

好,咱们直接进入正题。

2.1 USB总线拓扑结构

USB的拓扑结构,其实就是一个“树形”结构。主机(Host)是根,下面挂Hub,Hub再挂设备或者下一级Hub。我刚开始接触USB时,总觉得这玩意儿跟网络很像,但后来发现区别很大——USB是主从结构,所有通信必须由主机发起。

核心要点:USB系统中只有一个主机,所有设备都是“从机”。设备不能主动发数据,只能等主机来问。

具体来说,拓扑结构分三层:

  • 主机(Host):通常是PC、手机或嵌入式主控。它负责调度所有传输。
  • Hub(集线器):用来扩展端口。一个USB口最多可以级联7层Hub。
  • 设备(Device):就是咱们要驱动的那些玩意儿,比如声卡、麦克风、扬声器。

我记得有一次调试一个USB音频设备,死活枚举不过去。查了半天,发现是Hub级联太多,信号质量不行。嗯,这里要注意:实际项目中,级联超过3层就容易出问题,尤其是高速设备。

2.2 USB传输类型

USB定义了四种传输类型。每种类型都有自己的脾气。咱们做音频驱动,最关心的其实是同步传输和中断传输。但其他两种也得懂,不然枚举阶段就卡住了。

2.2.1 控制传输(Control Transfer)

这是USB的“官话”。所有设备必须支持。枚举阶段全靠它。控制传输的特点是:可靠,但慢。我习惯用它来读取描述符、配置设备。

  • 用于:设备枚举、命令下发
  • 特点:保证送达,有重试机制
  • 带宽占用:最多10%

个人经验:控制传输的包长有限制。全速设备最大64字节,高速设备最大64字节。别想着一次传大数据。

2.2.2 批量传输(Bulk Transfer)

批量传输,说白了就是“尽力而为”。数据量大,但没带宽保证。打印机、U盘喜欢用这个。音频设备一般不用,因为延迟不可控。

  • 用于:打印机、存储设备
  • 特点:可靠,但延迟不确定
  • 带宽:空闲时全占,忙时排队

2.2.3 中断传输(Interrupt Transfer)

名字叫“中断”,其实不是硬件中断。它是主机定期轮询设备,看有没有数据。我做过一个HID音频控制面板,就是用中断传输来传音量旋钮的状态。

  • 用于:HID设备、音频控制端点
  • 特点:保证延迟,但数据量小
  • 轮询间隔:1ms~255ms可配

2.2.4 同步传输(Isochronous Transfer)

重点来了!音频设备的核心传输方式。同步传输不保证数据一定送到,但保证带宽和延迟。你想想看,音频数据晚到几毫秒,声音就卡了。所以USB音频几乎都用同步传输。

避坑指南:我曾经在一个项目里,同步传输的端点描述符配错了,导致音频数据一直有爆音。查了三天才发现是同步类型(Sync Type)设成了异步。记住:音频设备通常用自适应同步或异步同步。

  • 用于:音频、视频流
  • 特点:带宽保证,无重传
  • 带宽:最高90%可用
传输类型 可靠性 带宽保证 延迟 典型应用
控制 高 无 高 枚举、配置
批量 高 无 不确定 U盘、打印机
中断 中 有 低 鼠标、控制面板
同步 低 有 极低 音频、视频

2.3 USB描述符体系

描述符是什么?就是设备的“身份证”和“简历”。主机通过读取描述符,才知道你是什么设备、需要多少带宽、用什么协议。我见过不少新手,描述符写错了,设备死活枚举不过。

描述符是层级结构的。从大到小依次是:

  1. 设备描述符(Device Descriptor):最顶层,描述设备的基本信息,比如VID、PID、USB版本。
  2. 配置描述符(Configuration Descriptor):一个设备可以有多个配置,但同一时间只能激活一个。每个配置描述符下面挂接口。
  3. 接口描述符(Interface Descriptor):描述一个功能单元。比如音频设备可能有音频控制接口、音频流接口。
  4. 端点描述符(Endpoint Descriptor):描述数据传输的端点。音频设备至少有一个同步输出端点或输入端点。
  5. 字符串描述符(String Descriptor):可选的,提供人类可读的字符串,比如厂商名、产品名。

注意:描述符的顺序不能乱!主机枚举时是按固定顺序读取的。我曾经把接口描述符和端点描述符的顺序搞反了,结果主机直接报“描述符错误”。

咱们做音频驱动,最常打交道的是音频控制接口描述符(AC Interface)和音频流接口描述符(AS Interface)。这些是USB Audio Class标准定义的,后面章节会详细讲。

这里给个简单的设备描述符例子,大家感受一下:

// USB设备描述符示例
const uint8_t device_descriptor[] = {
    0x12,       // bLength: 18字节
    0x01,       // bDescriptorType: 设备描述符
    0x00, 0x02, // bcdUSB: USB 2.0
    0x00,       // bDeviceClass: 由接口定义
    0x00,       // bDeviceSubClass
    0x00,       // bDeviceProtocol
    0x40,       // bMaxPacketSize0: 64字节
    0x34, 0x12, // idVendor: 0x1234
    0x56, 0x78, // idProduct: 0x7856
    0x00, 0x01, // bcdDevice: 1.00
    0x01,       // iManufacturer: 字符串索引1
    0x02,       // iProduct: 字符串索引2
    0x00,       // iSerialNumber: 无序列号
    0x01        // bNumConfigurations: 1个配置
};

我建议:刚开始写描述符时,先用USB分析仪抓一个标准设备的描述符看看。对着抄,再改。比自己从头写靠谱得多。

好了,USB协议基础就回顾到这里。这些内容虽然基础,但后面讲音频类特定描述符、同步传输调度时,全都要用上。下一章咱们直接进入USB Audio Class的核心——音频控制描述符和音频流描述符的详细解析。