3. USB描述符家族:结构与字段深度解析
USB描述符是设备向主机报告自身能力与属性的结构化数据块,是枚举过程中主机获取设备信息的唯一途径。任何描述符的格式错误、长度不匹配或字段值异常,都会导致枚举失败或功能受限。本章逐一拆解五大核心描述符的结构与关键字段。
bLength(描述符长度),第二个字节均为 bDescriptorType(描述符类型代码)。主机通过这两个字段验证描述符的完整性与类型。
3.1 设备描述符 (Device Descriptor)
设备描述符是枚举过程中主机读取的第一个描述符,位于描述符树的根节点。它定义了设备的整体属性,包括USB规范版本、设备类/子类/协议、厂商与产品标识等。
| 偏移 | 字段 | 大小 | 说明 |
|---|---|---|---|
| 0 | bLength | 1 | 描述符长度,固定为18字节 (0x12) |
| 1 | bDescriptorType | 1 | 描述符类型代码,设备描述符为0x01 |
| 2 | bcdUSB | 2 | USB规范版本号,BCD编码,如0x0200 (USB 2.0) |
| 4 | bDeviceClass | 1 | 设备类代码,0x00表示在接口描述符中定义 |
| 5 | bDeviceSubClass | 1 | 设备子类代码,与bDeviceClass配合使用 |
| 6 | bDeviceProtocol | 1 | 设备协议代码,0x00表示无协议 |
| 7 | bMaxPacketSize0 | 1 | 端点0的最大包大小,USB 2.0通常为64 |
| 8 | idVendor | 2 | 厂商ID (VID),由USB-IF分配 |
| 10 | idProduct | 2 | 产品ID (PID),由厂商自行分配 |
| 12 | bcdDevice | 2 | 设备版本号,BCD编码 |
| 14 | iManufacturer | 1 | 厂商字符串描述符索引,0表示无字符串 |
| 15 | iProduct | 1 | 产品字符串描述符索引 |
| 16 | iSerialNumber | 1 | 序列号字符串描述符索引 |
| 17 | bNumConfigurations | 1 | 支持的配置描述符数量,通常为1 |
3.2 配置描述符 (Configuration Descriptor)
配置描述符描述设备的电源管理能力与接口数量。一个设备可以有多个配置,但同一时刻只能激活一个配置。主机通过标准请求 Get_Descriptor(Configuration) 获取完整配置树,包括配置描述符本身及其下属的所有接口描述符和端点描述符。
| 偏移 | 字段 | 大小 | 说明 |
|---|---|---|---|
| 0 | bLength | 1 | 描述符长度,固定为9字节 (0x09) |
| 1 | bDescriptorType | 1 | 描述符类型代码,配置描述符为0x02 |
| 2 | wTotalLength | 2 | 整个配置树的总长度(含所有子描述符) |
| 4 | bNumInterfaces | 1 | 该配置支持的接口数量 |
| 5 | bConfigurationValue | 1 | 用于Set_Configuration请求的配置值 |
| 6 | iConfiguration | 1 | 配置字符串描述符索引 |
| 7 | bmAttributes | 1 | 配置特性:D7=总线供电,D6=自供电,D5=远程唤醒 |
| 8 | bMaxPower | 1 | 最大电流,单位2mA,值×2即为毫安数 |
3.3 接口描述符 (Interface Descriptor)
接口描述符定义了一个功能单元,包含一组端点。一个配置可以包含多个接口,每个接口可以有一个或多个备用设置(Alternate Setting)。主机通过 Set_Interface 请求切换备用设置,以改变接口的带宽或功能。
| 偏移 | 字段 | 大小 | 说明 |
|---|---|---|---|
| 0 | bLength | 1 | 描述符长度,固定为9字节 (0x09) |
| 1 | bDescriptorType | 1 | 描述符类型代码,接口描述符为0x04 |
| 2 | bInterfaceNumber | 1 | 接口编号,从0开始递增 |
| 3 | bAlternateSetting | 1 | 备用设置编号,0为默认设置 |
| 4 | bNumEndpoints | 1 | 该接口使用的端点数量(不含端点0) |
| 5 | bInterfaceClass | 1 | 接口类代码,如0x08为Mass Storage |
| 6 | bInterfaceSubClass | 1 | 接口子类代码 |
| 7 | bInterfaceProtocol | 1 | 接口协议代码 |
| 8 | iInterface | 1 | 接口字符串描述符索引 |
3.4 端点描述符 (Endpoint Descriptor)
端点描述符定义数据传输的端点属性,包括传输方向、传输类型、最大包大小和轮询间隔。除端点0外,每个非0端点都必须有对应的端点描述符。
| 偏移 | 字段 | 大小 | 说明 |
|---|---|---|---|
| 0 | bLength | 1 | 描述符长度,固定为7字节 (0x07) |
| 1 | bDescriptorType | 1 | 描述符类型代码,端点描述符为0x05 |
| 2 | bEndpointAddress | 1 | 端点地址:Bit7=方向(0:OUT,1:IN),Bit3-0=端点号 |
| 3 | bmAttributes | 1 | 传输类型:0x00=控制,0x01=等时,0x02=批量,0x03=中断 |
| 4 | wMaxPacketSize | 2 | 最大包大小,USB 2.0高速批量端点最大512字节 |
| 6 | bInterval | 1 | 轮询间隔:中断端点单位ms,等时端点单位125μs |
3.5 字符串描述符 (String Descriptor)
字符串描述符提供人类可读的文本信息,如厂商名称、产品名称和序列号。字符串描述符使用Unicode编码(UTF-16LE),主机通过 Get_Descriptor(String, Index) 请求获取。字符串描述符索引0为特殊语言ID描述符,用于获取设备支持的语言列表。
| 偏移 | 字段 | 大小 | 说明 |
|---|---|---|---|
| 0 | bLength | 1 | 描述符长度,等于2 + 字符串字节数 |
| 1 | bDescriptorType | 1 | 描述符类型代码,字符串描述符为0x03 |
| 2 | bString | N | Unicode字符串,UTF-16LE编码,无NULL终止符 |
3.6 描述符家族关系总览
五大描述符构成严格的树形层级:设备描述符 → 配置描述符 → 接口描述符 → 端点描述符。字符串描述符作为辅助节点,通过索引被其他描述符引用。主机枚举时按此层级逐级读取,任何一级的异常都会导致枚举中断。
3.7 枚举日志中的描述符解析实战
以下是一段真实的USB枚举日志,展示了主机读取设备描述符和配置描述符的原始数据。注意观察字段值与实际设备属性的对应关系。
// 设备描述符原始数据 (18字节)
// 主机