USB 设备描述符(USB Device Descriptor)是 USB 设备在枚举早期返回给主机的固定结构,用来说明设备的基础身份、协议版本、类信息、VID:PID 和配置数量。
它是主机认识一个 USB 设备的第一层元数据。后续的配置描述符、接口描述符、端点描述符和类特定描述符都建立在这一步之后。
核心问题
USB 主机不能靠猜测理解新插入设备。它必须先读一段标准格式的数据,知道:
- 设备遵循哪个 USB 版本。
- 设备由哪个厂商和产品编号标识。
- 设备类是在设备级声明,还是要到接口级再判断。
- 有多少个可选配置。
- 是否提供厂商名、产品名、序列号等字符串索引。
USB 设备描述符解决的就是“主机用统一格式获取设备基础身份”的问题。
核心对象
| 字段 | 含义 | 工程关注点 |
|---|---|---|
bLength | 该描述符长度 | 设备描述符通常是 18 字节 |
bDescriptorType | 描述符类型 | device descriptor 的类型值为 1 |
bcdUSB | USB 规范版本,BCD 编码 | 例如 USB 2.0 常见为 0x0200 |
bDeviceClass | 设备级 class | 0x00 常表示 class 在 interface 级声明 |
bDeviceSubClass | 设备级 subclass | 与 class 一起解释 |
bDeviceProtocol | 设备级 protocol | 与 class/subclass 一起决定通用驱动匹配 |
bMaxPacketSize0 | 控制端点 0 最大包长 | 枚举控制传输的基础参数 |
idVendor | Vendor ID | [[VID-PID(USB 设备标识) |
idProduct | Product ID | [[VID-PID(USB 设备标识) |
bcdDevice | 设备版本号,BCD 编码 | 常表示硬件或固件版本 |
iManufacturer | 厂商字符串索引 | 索引为 0 表示没有字符串 |
iProduct | 产品字符串索引 | 展示名,不适合作唯一识别 |
iSerialNumber | 序列号字符串索引 | 可用于区分同型号多设备,但设备可能不提供 |
bNumConfigurations | 配置数量 | 主机之后会读取 configuration descriptor |
BCD 是 Binary-Coded Decimal,不是普通二进制整数。例如 0x0200 按 USB 版本语义读作 2.00,而不是十进制 512。
核心机制
1. 主机通过控制传输读取描述符
设备刚连接时,主机会通过默认控制端点 0 发起标准请求:
GET_DESCRIPTOR(Device)设备返回固定格式的 device descriptor。这个过程不依赖厂商驱动,因为它是 USB 标准控制请求的一部分。
2. 描述符提供下一步枚举线索
主机读到设备描述符后,典型决策路径是:
read device descriptor
-> learn VID/PID and basic class fields
-> read configuration descriptor
-> inspect interfaces and endpoints
-> bind class driver or vendor-specific driver如果 bDeviceClass 是 0x00,主机通常要继续看每个 interface descriptor 的 class/subclass/protocol。很多复合设备都采用这种方式,因为一个设备可以同时提供多个功能。
3. 字符串索引不是字符串本身
iManufacturer、iProduct、iSerialNumber 不是直接存放文本,而是字符串描述符的索引。主机需要再发起 GET_DESCRIPTOR(String, index) 才能读取具体文字。
这就是为什么一些工具能显示厂商名和产品名,而另一些场景只能看到 VID:PID:字符串描述符可能不存在、读取失败,或语言 ID 未匹配。
工程用途
- 用
lsusb -v检查设备返回的idVendor、idProduct、bcdDevice、class 和字符串索引。 - 在固件开发中确认 USB device stack 生成的 descriptor 是否与预期一致。
- 排查设备不被识别的问题:描述符长度错误、端点 0 包长错误、class 字段错误都可能导致枚举失败。
- 区分设备级 class 与接口级 class,避免把复合设备误判成单一功能设备。
- 写 udev 规则 或驱动匹配表时,确认匹配字段来自哪一层描述符。
边界与常见坑
- 设备描述符不是完整能力清单:端点、接口、带宽、视频格式、HID report 等能力在后续描述符中。
- 产品字符串不是稳定 ID:
iProduct只是显示文本,可能随固件、语言或厂商习惯变化。 - 序列号可能为空:很多低成本设备不提供
iSerialNumber,同型号多设备会更难区分。 - class 字段可能在接口级:看到
bDeviceClass = 0x00不代表设备没有类别,而是要继续看 interface descriptor。 - 描述符可被伪造:安全策略不能只相信设备自报的 VID/PID 或产品名。