4. 设备描述符详解:bLength、bDescriptorType、bcdUSB、idVendor、idProduct、bcdDevice等字段含义与验证方法
设备描述符(Device Descriptor)是USB枚举过程中主机从设备读取的第一个描述符,它定义了设备的整体属性,包括USB规范版本、厂商与产品标识、设备版本号以及配置数量等关键信息。该描述符位于描述符树的根节点,是所有后续描述符请求的基础。如果设备描述符解析失败,主机将无法识别设备类型,枚举过程会立即终止。
4.1 设备描述符结构总览
设备描述符的长度固定为18字节,由9个字段组成。主机通过控制传输(默认端点0)发送标准请求 GET_DESCRIPTOR(bRequest = 0x06),wValue高字节为描述符类型(0x01表示设备描述符),设备必须在5ms内响应完整数据。
| 偏移量(字节) | 字段名 | 长度(字节) | 含义 |
|---|---|---|---|
| 0 | bLength | 1 | 描述符长度,固定为0x12(18) |
| 1 | bDescriptorType | 1 | 描述符类型,设备描述符固定为0x01 |
| 2-3 | bcdUSB | 2 | USB规范版本号(BCD编码) |
| 4 | bDeviceClass | 1 | 设备类代码(0x00表示在接口描述符中定义) |
| 5 | bDeviceSubClass | 1 | 设备子类代码 |
| 6 | bDeviceProtocol | 1 | 设备协议代码 |
| 7 | bMaxPacketSize0 | 1 | 端点0最大包大小(8/16/32/64) |
| 8-9 | idVendor | 2 | 厂商ID(USB-IF分配) |
| 10-11 | idProduct | 2 | 产品ID(厂商自定义) |
| 12-13 | bcdDevice | 2 | 设备版本号(BCD编码) |
| 14 | iManufacturer | 1 | 厂商字符串描述符索引 |
| 15 | iProduct | 1 | 产品字符串描述符索引 |
| 16 | iSerialNumber | 1 | 序列号字符串描述符索引 |
| 17 | bNumConfigurations | 1 | 支持的配置描述符数量 |
4.2 核心字段深度解析
4.2.1 bLength 与 bDescriptorType
bLength 必须为0x12(十进制18),这是USB规范对设备描述符的固定长度要求。如果设备返回的长度小于18字节,主机将认为描述符截断并重试请求;如果大于18字节,主机只读取前18字节,多余数据被忽略。
bDescriptorType 必须为0x01。该字段用于主机区分描述符类型,在解析描述符树时起到路由作用。常见的描述符类型值包括:
- 0x01 — 设备描述符
- 0x02 — 配置描述符
- 0x03 — 字符串描述符
- 0x04 — 接口描述符
- 0x05 — 端点描述符
4.2.2 bcdUSB — USB规范版本号
bcdUSB采用二进制编码十进制(BCD)格式,高字节表示主版本号,低字节表示次版本号。例如:
- 0x0110 — USB 1.1(全速/低速)
- 0x0200 — USB 2.0(高速)
- 0x0201 — USB 2.0修订版1
- 0x0300 — USB 3.2 Gen 1(SuperSpeed)
该字段影响主机对设备速度能力的判断。例如,如果设备声明bcdUSB = 0x0200但实际只支持全速,主机在高速握手失败后会降级为全速枚举。验证时需使用USB分析仪检查设备在复位后的Chirp J/K序列是否与bcdUSB声明一致。
lsusb -v 命令可以查看已枚举设备的bcdUSB字段。如果显示为 bcdUSB 2.00 但设备实际运行在12Mbps,说明设备可能未正确实现高速检测握手。
4.2.3 idVendor 与 idProduct
idVendor 由USB实施者论坛(USB-IF)分配给厂商,每个厂商拥有唯一的16位标识符。常见的厂商ID包括:
| 厂商 | idVendor(十六进制) | 常见产品 |
|---|---|---|
| Microchip | 0x04D8 | PIC开发板、USB桥接器 |
| FTDI | 0x0403 | USB转串口适配器 |
| STMicroelectronics | 0x0483 | STM32开发板、虚拟串口 |
| Texas Instruments | 0x0451 | TIVA、MSP430评估板 |
| NXP | 0x1FC9 | LPC系列MCU |
idProduct 由厂商自行分配,用于区分同一厂商的不同产品型号。主机操作系统通常使用 idVendor:idProduct 对来加载对应的驱动程序。如果该字段与驱动程序的INF/kext文件不匹配,系统将提示“无法识别的设备”。
USB\VID_XXXX&PID_XXXX,其中XXXX即为idVendor和idProduct的十六进制值。如果硬件ID与预期不符,说明设备描述符中的这两个字段存在错误。
4.2.4 bcdDevice — 设备版本号
bcdDevice同样采用BCD编码,用于标识设备的固件或硬件版本。该字段在驱动匹配中起辅助作用,某些驱动程序会根据bcdDevice值加载不同的固件补丁或配置参数。
例如,一个设备可能在不同固件版本中返回:
- 0x0100 — 初始版本
- 0x0101 — 修复了端点缓冲区溢出问题
- 0x0200 — 增加了新的HID报告描述符
验证时,可以通过升级设备固件后重新枚举,检查bcdDevice是否按预期递增。如果bcdDevice始终为0x0000,说明固件未正确初始化该字段。
4.3 设备描述符验证流程
以下SVG图展示了从主机发送GET_DESCRIPTOR请求到验证设备描述符各字段的完整流程:
4.4 固件实现示例与常见错误
以下是一个基于STM32 HAL库的设备描述符定义示例,展示了各字段的正确配置:
/* USB设备描述符 - 基于STM32 USB Device库 */
__ALIGN_BEGIN uint8_t USBD_FS_DeviceDesc[USB_LEN_DEV_DESC] __ALIGN_END =
{
0x12, /* bLength: 描述符长度 */
0x01, /* bDescriptorType: 设备描述符类型 */
0x00, 0x02, /* bcdUSB: USB 2.00 */
0x00, /* bDeviceClass: 在接口描述符中定义 */
0x00, /* bDeviceSubClass */
0x00, /* bDeviceProtocol */
0x40, /* bMaxPacketSize0: 端点0最大包大小64字节 */
0x83, 0x04, /* idVendor: 0x0483 (STMicroelectronics) */
0x10, 0x57, /* idProduct: 0x5710 (自定义产品ID) */
0x00, 0x01, /* bcdDevice: 1.00 */
0x01, /* iManufacturer: 字符串索引1 */
0x02, /* iProduct: 字符串索引2 */
0x03, /* iSerialNumber: 字符串索引3 */
0x01 /* bNumConfigurations: 1个配置 */
};
- bLength错误:数组长度定义错误导致返回0x11或0x13,主机拒绝接受描述符。
- bMaxPacketSize0错误:全速设备必须为8或16,高速设备必须为64。错误值会导致控制传输分片异常。
- idVendor未注册:使用0x0000或0xFFFF等保留值,主机可能拒绝加载驱动。
- bNumConfigurations为0:主机认为设备没有可用配置,枚举终止。
4.5 使用逻辑分析仪验证设备描述符
当软件层面的枚举失败时,使用USB逻辑分析仪或协议分析仪捕获物理层数据是最终的验证手段。以下是通过分析仪捕获的典型设备描述符响应数据包:
USB Packet Capture - Device Descriptor Response
------------------------------------------------
SYNC: 00000001
PID: DATA0 (0xC3)
DATA: 12 01 00 02 00 00 00 40 83 04 10 57 00 01 01 02 03 01
CRC16: 0x4A3B (正确)
EOP: SE0 for 2 bit times
字段解析:
12 → bLength = 18
01 → bDescriptorType = 1 (设备描述符)
00 02 → bcdUSB = 0x0200 (USB 2.0)
00 → bDeviceClass = 0 (接口定义)
00 → bDeviceSubClass = 0
00 → bDeviceProtocol = 0
40 → bMaxPacketSize0 = 64
83 04 → idVendor = 0x0483
10 57 → idProduct = 0x5710
00 01 → bcdDevice = 0x0100
01 → iManufacturer = 1
02 → iProduct = 2
03 → iSerialNumber = 3
01 → bNumConfigurations = 1
4.6 字段验证检查清单
在排查设备描述符相关故障时,建议按以下清单逐项验证:
| 检查项 | 预期值 | 验证方法 | 故障影响 |
|---|---|---|---|
| bLength | 0x12 | 分析仪或lsusb -v | 描述符被拒绝,枚举失败 |
| bDescriptorType | 0x01 | 分析仪或lsusb -v | 主机无法识别描述符类型 |
| bcdUSB | 与速度匹配 | 检查Chirp序列 | 速度协商错误 |
| bMaxPacketSize0 | 8/16/32/64 | 分析仪捕获 | 控制传输分片异常 |
| idVendor | USB-IF分配值 | USB-IF数据库查询 | 驱动无法加载 |
| idProduct | 厂商自定义 | 与驱动INF匹配 | 驱动无法加载 |
| bcdDevice | 非0x0000 | lsusb -v | 驱动版本匹配错误 |
| bNumConfigurations | ≥1 | 分析仪捕获 | 无可用配置,枚举终止 |