四、USB 协议中的描述符(Descriptor)详解
USB 协议学习目录
点击标题可跳转到对应的网络文章
- 一、USB 协议结构详解
- 二、USB 协议中的设备类
- 三、USB 协议通信过程
- 四、USB 协议中的描述符
- 五、USB 协议中的请求
- 六、USB 协议中的接口与端点
- 七、USB 协议中的事务
- 八、USB 协议分析与调试实战
目录
- 一、概述
- [1.1 描述符的作用](#1.1 描述符的作用)
- [1.2 描述符的级联结构](#1.2 描述符的级联结构)
- [1.3 描述符通用格式](#1.3 描述符通用格式)
- [二、设备描述符(Device Descriptor)](#二、设备描述符(Device Descriptor))
- [2.1 结构详解](#2.1 结构详解)
- [2.2 关键字段解析](#2.2 关键字段解析)
- [三、配置描述符(Configuration Descriptor)](#三、配置描述符(Configuration Descriptor))
- [3.1 结构详解](#3.1 结构详解)
- [3.2 配置属性解析](#3.2 配置属性解析)
- [四、接口描述符(Interface Descriptor)](#四、接口描述符(Interface Descriptor))
- [4.1 结构详解](#4.1 结构详解)
- [4.2 接口类速查](#4.2 接口类速查)
- [五、端点描述符(Endpoint Descriptor)](#五、端点描述符(Endpoint Descriptor))
- [5.1 结构详解](#5.1 结构详解)
- [5.2 端点地址解析](#5.2 端点地址解析)
- [5.3 端点属性解析](#5.3 端点属性解析)
- [六、字符串描述符(String Descriptor)](#六、字符串描述符(String Descriptor))
- [6.1 语言 ID 描述符](#6.1 语言 ID 描述符)
- [6.2 Unicode 字符串描述符](#6.2 Unicode 字符串描述符)
- [七、接口关联描述符 IAD](#七、接口关联描述符 IAD)
- 八、类特定描述符
- [8.1 HID 描述符](#8.1 HID 描述符)
- [8.2 CDC 功能描述符](#8.2 CDC 功能描述符)
- [8.3 Hub 描述符](#8.3 Hub 描述符)
- 九、描述符获取流程
- 十、描述符实例分析
- 十一、总结
一、概述
1.1 描述符的作用
USB 设备通过描述符(Descriptor)向主机自描述自身的能力。描述符是一种层次化的数据结构,Host 在枚举阶段通过控制传输读取这些描述符,从而了解设备的一切信息。
自描述
读取
解析
USB Device
描述符集
USB Host
加载驱动
配置端点
描述符回答的核心问题:
- 这是什么设备?(VID/PID/设备类)
- 支持什么 USB 版本?(bcdUSB)
- 有多少种配置?(bNumConfigurations)
- 每个配置有哪些接口?(bNumInterfaces)
- 每个接口有哪些端点?(bNumEndpoints)
- 端点支持什么传输类型?(bmAttributes)
- 设备叫什么名字?(字符串描述符)
1.2 描述符的级联结构
Device Descriptor
设备描述符
18字节
Configuration Descriptor 1
配置描述符
9字节 + 子描述符
Configuration Descriptor 2
(可选)
Interface Descriptor 0
接口描述符
9字节
Interface Descriptor 1
(可选)
HID Descriptor
HID描述符
(如为HID设备)
Endpoint Descriptor 0-1
端点描述符
7字节
Endpoint Descriptor 0-2
(可选)
CDC Functional Descriptor
CDC功能描述符
(如为CDC设备)
Endpoint Descriptor 1-1
描述符层级关系:
- 1 个设备描述符 → 包含
bNumConfigurations个配置描述符 - 每个配置描述符 → 包含
bNumInterfaces个接口描述符 - 每个接口描述符 → 包含
bNumEndpoints个端点描述符 - 接口描述符 → 可能附带类特定描述符(HID、CDC 等)
1.3 描述符通用格式
所有 USB 描述符都以相同的 2 字节头部开始:
| 偏移 | 大小 | 字段 | 说明 |
|---|---|---|---|
| 0 | 1 | bLength | 描述符长度(字节) |
| 1 | 1 | bDescriptorType | 描述符类型 |
标准描述符类型值:
| 类型值 | 名称 | 长度 |
|---|---|---|
| 0x01 | Device Descriptor | 18 |
| 0x02 | Configuration Descriptor | 9 |
| 0x03 | String Descriptor | 可变 |
| 0x04 | Interface Descriptor | 9 |
| 0x05 | Endpoint Descriptor | 7 |
| 0x0B | Interface Association Descriptor (IAD) | 8 |
| 0x21 | HID Descriptor | 9+ |
| 0x29 | Hub Descriptor | 9+ |
| 0x2A | SuperSpeed Hub Descriptor | 12 |
二、设备描述符(Device Descriptor)
设备描述符是根描述符,位于描述符树的顶层,Host 首先获取的就是它。
2.1 结构详解
c
typedef struct {
uint8_t bLength; // 描述符长度 (18)
uint8_t bDescriptorType; // 描述符类型 (0x01)
uint16_t bcdUSB; // USB 规范版本号 (如 0x0200 = USB 2.0)
uint8_t bDeviceClass; // 设备类代码
uint8_t bDeviceSubClass; // 设备子类代码
uint8_t bDeviceProtocol; // 设备协议代码
uint8_t bMaxPacketSize0; // 端点 0 最大包大小
uint16_t idVendor; // 厂商 ID (VID)
uint16_t idProduct; // 产品 ID (PID)
uint16_t bcdDevice; // 设备版本号 (BCD)
uint8_t iManufacturer; // 厂商字符串索引
uint8_t iProduct; // 产品字符串索引
uint8_t iSerialNumber; // 序列号字符串索引
uint8_t bNumConfigurations; // 配置描述符数量
} USB_DeviceDescriptor;
2.2 关键字段解析
bcdUSB - USB 版本号(BCD 编码):
| 值 | USB 版本 |
|---|---|
| 0x0100 | USB 1.0 |
| 0x0110 | USB 1.1 |
| 0x0200 | USB 2.0 |
| 0x0250 | USB 2.1 (LPM) |
| 0x0300 | USB 3.0 |
| 0x0310 | USB 3.1 |
| 0x0320 | USB 3.2 |
bDeviceClass - 设备类:
| 值 | 含义 |
|---|---|
| 0x00 | 每接口定义类(复合设备) |
| 0x02 | CDC 通信设备 |
| 0x03 | HID 人机接口设备 |
| 0x08 | Mass Storage 大容量存储 |
| 0x09 | Hub 集线器 |
| 0x0E | Video 视频设备 |
| 0xE0 | Wireless 无线控制器 |
| 0xEF | Miscellaneous 杂项 |
| 0xFF | Vendor Specific 厂商自定义 |
bMaxPacketSize0 - 端点 0 最大包大小:
| 速度 | 有效值 |
|---|---|
| Low Speed | 8 |
| Full Speed | 8, 16, 32, 64 |
| High Speed | 64 |
idVendor / idProduct:
- VID 由 USB-IF 统一分配(如 0x046D = Logitech)
- PID 由厂商自行定义
- Host 通过 VID/PID 匹配特定驱动
字符串索引字段:
iManufacturer:厂商名称字符串索引(0 = 无字符串)iProduct:产品名称字符串索引iSerialNumber:序列号字符串索引
三、配置描述符(Configuration Descriptor)
配置描述符定义了设备的一种工作模式。一个设备可以有多个配置(如"总线供电模式"和"自供电模式"),但同一时间只能激活一个配置。
3.1 结构详解
c
typedef struct {
uint8_t bLength; // 描述符长度 (9)
uint8_t bDescriptorType; // 描述符类型 (0x02)
uint16_t wTotalLength; // 配置总长度(含所有子描述符)
uint8_t bNumInterfaces; // 接口数量
uint8_t bConfigurationValue; // 配置值(SET_CONFIGURATION 参数)
uint8_t iConfiguration; // 配置描述字符串索引
uint8_t bmAttributes; // 配置属性
uint8_t bMaxPower; // 最大功耗(单位:2mA)
} USB_ConfigurationDescriptor;
3.2 配置属性解析
bmAttributes 字段:
| 位 | 名称 | 值 | 说明 |
|---|---|---|---|
| Bit7 | 保留 | 1 | 必须置 1(历史兼容) |
| Bit6 | 自供电 | 1 | 设备支持自供电 |
| 0 | 设备仅总线供电 | ||
| Bit5 | 远程唤醒 | 1 | 支持远程唤醒 |
| 0 | 不支持远程唤醒 | ||
| Bit4~0 | 保留 | 0 | 必须置 0 |
bMaxPower:
- 单位 = 2mA
- 例如:值 = 50,表示最大功耗 = 50 × 2mA = 100mA
- USB 2.0 最大值为 250(500mA)
- USB 3.0 最大值为 250(500mA),但 SuperSpeed 设备可支持 900mA
wTotalLength:
- 这是整个配置描述符集的总长度
- 包含:配置描述符 + 所有接口描述符 + 所有端点描述符 + 所有类特定描述符
- Host 通过此值一次性获取完整配置信息
四、接口描述符(Interface Descriptor)
接口描述符定义了设备的一个逻辑功能。一个配置可包含多个接口,每个接口对应一个独立功能(如键盘 + 鼠标复合设备)。
4.1 结构详解
c
typedef struct {
uint8_t bLength; // 描述符长度 (9)
uint8_t bDescriptorType; // 描述符类型 (0x04)
uint8_t bInterfaceNumber; // 接口编号(从 0 开始)
uint8_t bAlternateSetting; // 备用设置编号
uint8_t bNumEndpoints; // 端点数量(不含 EP0)
uint8_t bInterfaceClass; // 接口类代码
uint8_t bInterfaceSubClass; // 接口子类代码
uint8_t bInterfaceProtocol; // 接口协议代码
uint8_t iInterface; // 接口描述字符串索引
} USB_InterfaceDescriptor;
bInterfaceNumber:
- 接口在配置中的唯一编号,从 0 开始递增
- 复合设备中,每个功能对应一个独立的接口编号
bAlternateSetting:
- 同一接口的不同设置(Alternate Setting)
- 用于动态切换接口配置(如 USB 音频中切换采样率)
- 默认设置 = 0,通过
SET_INTERFACE请求切换
bNumEndpoints:
- 该接口使用的非零端点数量
- 控制端点 EP0 是所有接口共用的,不计入此值
4.2 接口类速查
| 类代码 | 名称 | 典型应用 | 子类示例 |
|---|---|---|---|
| 0x00 | 保留 | - | - |
| 0x02 | CDC-Control | 串口/调制解调器 | ACM=0x02 |
| 0x03 | HID | 键盘/鼠标/手柄 | Boot=0x01 |
| 0x08 | Mass Storage | U盘/读卡器 | SCSI=0x06, BOT=0x50 |
| 0x0A | CDC-Data | CDC 数据接口 | - |
| 0x0B | Smart Card | 读卡器 | CCID=0x00 |
| 0x0E | Video | 摄像头 | UVC=0x01 |
| 0x01 | Audio | 声卡/耳机 | UAC |
| 0x09 | Hub | 集线器 | - |
| 0xE0 | Wireless | 蓝牙/WiFi | Bluetooth=0x01 |
| 0xFF | Vendor Specific | 自定义 | - |
五、端点描述符(Endpoint Descriptor)
端点描述符定义了数据传输的通道属性,包括方向、传输类型、最大包大小和轮询间隔。
5.1 结构详解
c
typedef struct {
uint8_t bLength; // 描述符长度 (7)
uint8_t bDescriptorType; // 描述符类型 (0x05)
uint8_t bEndpointAddress; // 端点地址
uint8_t bmAttributes; // 端点属性
uint16_t wMaxPacketSize; // 最大包大小
uint8_t bInterval; // 轮询间隔
} USB_EndpointDescriptor;
5.2 端点地址解析
bEndpointAddress:
Bit7 Bit6~4 Bit3~0
方向 保留 端点编号
0=OUT 000 0~15
1=IN
| 值 | 含义 |
|---|---|
| 0x00 | 控制端点 0 (OUT) |
| 0x80 | 控制端点 0 (IN) |
| 0x01 | 端点 1 (OUT) |
| 0x81 | 端点 1 (IN) |
| 0x02 | 端点 2 (OUT) |
| 0x82 | 端点 2 (IN) |
5.3 端点属性解析
bmAttributes:
Bit1~0: 传输类型
00 = Control 控制传输
01 = Isochronous 同步传输
10 = Bulk 批量传输
11 = Interrupt 中断传输
Bit3~2: 同步类型 (仅同步传输)
00 = None 无同步
01 = Asynchronous 异步
10 = Adaptive 自适应
11 = Synchronous 同步
Bit5~4: 用法类型 (仅同步传输)
00 = Data Endpoint
01 = Feedback Endpoint
10 = Implicit Feedback
11 = Reserved
wMaxPacketSize:
| 速度 | 控制 | 批量 | 中断 | 同步 |
|---|---|---|---|---|
| Low Speed | 8 | - | 8 | - |
| Full Speed | 8/16/32/64 | 8/16/32/64 | 64 | 1023 |
| High Speed | 64 | 512 | 1024 | 1024 |
| SuperSpeed | 512 | 1024 | 1024 | 1024 |
bInterval:
| 速度 | 含义 | 典型值 |
|---|---|---|
| Full Speed 中断 | 轮询间隔(ms) | 1~255 ms |
| High Speed 中断 | 轮询间隔(125μs × 2^(bInterval-1)) | 1~16 |
| Full Speed 同步 | 轮询间隔(ms) | 1 ms |
| High Speed 同步 | 轮询间隔(125μs × 2^(bInterval-1)) | 1~16 |
| 批量/控制 | 忽略 | - |
六、字符串描述符(String Descriptor)
字符串描述符提供设备的可读文本信息 (厂商名、产品名、序列号),采用 UTF-16LE 编码。
6.1 语言 ID 描述符
字符串描述符 0 是特殊的,它返回设备支持的语言 ID 列表。
c
// 字符串描述符 0 结构
uint8_t bLength; // 描述符长度 (2 + 2*N)
uint8_t bDescriptorType; // 0x03
uint16_t wLANGID[0]; // 语言 ID 数组
// ...
uint16_t wLANGID[N-1];
常用语言 ID:
| 语言 | LANGID |
|---|---|
| 英语(美国) | 0x0409 |
| 简体中文 | 0x0804 |
| 繁体中文 | 0x0404 |
| 日语 | 0x0411 |
| 韩语 | 0x0412 |
6.2 Unicode 字符串描述符
c
// 字符串描述符 N (N >= 1)
uint8_t bLength; // 描述符长度 (2 + 字符串字节数)
uint8_t bDescriptorType; // 0x03
uint16_t bString[]; // UTF-16LE 编码字符串 (不含结尾 \0)
示例:字符串 "Kimi USB Device"
bLength = 0x22 // 2 + 16×2 = 34 字节
bDescriptorType = 0x03
bString[0] = 'K' = 0x004B (小端: 4B 00)
bString[1] = 'i' = 0x0069 (小端: 69 00)
...
七、接口关联描述符 IAD
当多个接口组成一个复合功能时,需要使用 IAD(Interface Association Descriptor)进行关联声明。
c
typedef struct {
uint8_t bLength; // 描述符长度 (8)
uint8_t bDescriptorType; // 描述符类型 (0x0B)
uint8_t bFirstInterface; // 第一个接口编号
uint8_t bInterfaceCount; // 关联的接口数量
uint8_t bFunctionClass; // 功能类
uint8_t bFunctionSubClass; // 功能子类
uint8_t bFunctionProtocol; // 功能协议
uint8_t iFunction; // 功能描述字符串索引
} USB_IADDescriptor;
典型应用 - CDC 设备:
IAD
bFirstInterface=0
bInterfaceCount=2
FunctionClass=0x02 CDC
Interface 0
CDC-Control
bInterfaceClass=0x02
Interface 1
CDC-Data
bInterfaceClass=0x0A
中断端点
通知端点
CDC Functional Descriptors
Header/ACM/Union/CallMgmt
批量端点 IN
数据接收
批量端点 OUT
数据发送
八、类特定描述符
8.1 HID 描述符
HID 接口必须附带 HID 描述符,定义 HID 规范版本和报告描述符信息。
c
typedef struct {
uint8_t bLength; // 描述符长度 (9)
uint8_t bDescriptorType; // 0x21 = HID
uint16_t bcdHID; // HID 规范版本 (如 0x0111 = 1.11)
uint8_t bCountryCode; // 国家代码 (0=未本地化)
uint8_t bNumDescriptors; // 附属描述符数量 (>=1)
uint8_t bDescriptorType2; // 0x22 = Report Descriptor
uint16_t wDescriptorLength; // 报告描述符长度
// 可选:Physical Descriptor
// uint8_t bDescriptorType3;
// uint16_t wDescriptorLength2;
} USB_HIDDescriptor;
8.2 CDC 功能描述符
CDC 接口附带一组功能描述符(Functional Descriptor),定义通信参数。
| 描述符子类型 | 值 | 说明 |
|---|---|---|
| Header | 0x00 | CDC 版本信息 |
| Call Management | 0x01 | 呼叫管理 |
| Abstract Control Management | 0x02 | ACM 管理 |
| Direct Line Management | 0x03 | 直路管理 |
| Union | 0x06 | 接口关联 |
Union Functional Descriptor:
c
typedef struct {
uint8_t bLength; // 4
uint8_t bDescriptorType; // 0x24 (CS_INTERFACE)
uint8_t bDescriptorSubtype;// 0x06 (UNION)
uint8_t bMasterInterface; // 控制接口编号
uint8_t bSlaveInterface0; // 数据接口编号
} CDC_UnionFunctionalDescriptor;
8.3 Hub 描述符
Hub 设备特有的描述符,定义下行端口数量、电源特性等。
c
typedef struct {
uint8_t bLength; // 描述符长度 (9)
uint8_t bDescriptorType; // 0x29 = Hub
uint8_t bNbrPorts; // 下行端口数量
uint16_t wHubCharacteristics; // Hub 特性
uint8_t bPwrOn2PwrGood; // 端口上电到就绪时间 (2ms 单位)
uint8_t bHubContrCurrent; // Hub 控制器最大电流 (mA)
uint8_t DeviceRemovable; // 设备可移除位图
uint8_t PortPwrCtrlMask; // 端口电源控制掩码
} USB_HubDescriptor;
wHubCharacteristics 字段:
Bit1~0: 逻辑电源切换模式
00 = Ganged power switching (所有端口一起)
01 = Individual port power switching (独立)
1x = 无电源切换
Bit2: 复合设备标志
0 = Hub 不是复合设备的一部分
1 = Hub 是复合设备的一部分
Bit4~3: TT (Transaction Translator) Think Time
00 = <=8 FS bit times
01 = <=16 FS bit times
10 = <=24 FS bit times
11 = <=32 FS bit times
Bit5: TT 端口指示器
0 = 不支持端口指示器
1 = 支持端口指示器
九、描述符获取流程
Host 在枚举阶段按以下顺序获取描述符:
USB Device USB Host USB Device USB Host 阶段1: 获取设备描述符 阶段2: 获取配置描述符 阶段3: 获取字符串描述符 阶段4: 设置配置 GET_DESCRIPTOR(Device, 8) 前 8 字节 (含 bMaxPacketSize0) SET_ADDRESS(addr) ACK GET_DESCRIPTOR(Device, 18) 完整设备描述符 GET_DESCRIPTOR(Config, 9) 配置描述符 (含 wTotalLength) GET_DESCRIPTOR(Config, wTotalLength) 完整配置描述符集 GET_DESCRIPTOR(String, 0) 语言 ID 列表 GET_DESCRIPTOR(String, iManufacturer) 厂商名称 GET_DESCRIPTOR(String, iProduct) 产品名称 SET_CONFIGURATION(value) ACK
GET_DESCRIPTOR 请求格式:
bmRequestType = 0x80 (Device→Host, Standard, Device)
bRequest = 0x06 (GET_DESCRIPTOR)
wValue = (描述符类型 << 8) | 描述符索引
如: 设备描述符 = 0x0100
配置描述符 = 0x0200
字符串描述符(厂商) = 0x0301
wIndex = 0 (设备/配置) 或语言 ID (字符串)
wLength = 期望返回的字节数
十、描述符实例分析
以下是一个USB HID 键盘的完整描述符字节流实例:
设备描述符(18 字节)
偏移 值 说明
---- ---- ----
00 0x12 bLength = 18
01 0x01 bDescriptorType = Device
02 0x00 bcdUSB = 0x0200 (USB 2.0)
03 0x02
04 0x00 bDeviceClass = 0 (每接口定义)
05 0x00 bDeviceSubClass = 0
06 0x00 bDeviceProtocol = 0
07 0x08 bMaxPacketSize0 = 8 (Full Speed)
08 0x83 idVendor = 0x0483 (ST Microelectronics)
09 0x04
10 0x10 idProduct = 0x5710
11 0x57
12 0x00 bcdDevice = 0x0100
13 0x01
14 0x01 iManufacturer = 1 (字符串1)
15 0x02 iProduct = 2 (字符串2)
16 0x00 iSerialNumber = 0 (无)
17 0x01 bNumConfigurations = 1
配置描述符及子描述符(34 字节)
偏移 值 说明
---- ---- ----
00 0x09 bLength = 9 (Configuration)
01 0x02 bDescriptorType = Configuration
02 0x22 wTotalLength = 0x0022 = 34 字节
03 0x00
04 0x01 bNumInterfaces = 1
05 0x01 bConfigurationValue = 1
06 0x00 iConfiguration = 0 (无)
07 0xA0 bmAttributes = 10100000 (自供电, 远程唤醒)
08 0x32 bMaxPower = 50 × 2mA = 100mA
09 0x09 bLength = 9 (Interface)
10 0x04 bDescriptorType = Interface
11 0x00 bInterfaceNumber = 0
12 0x00 bAlternateSetting = 0
13 0x01 bNumEndpoints = 1
14 0x03 bInterfaceClass = 0x03 (HID)
15 0x01 bInterfaceSubClass = 0x01 (Boot)
16 0x01 bInterfaceProtocol = 0x01 (Keyboard)
17 0x00 iInterface = 0 (无)
18 0x09 bLength = 9 (HID)
19 0x21 bDescriptorType = HID
20 0x11 bcdHID = 0x0111 (HID 1.11)
21 0x01
22 0x00 bCountryCode = 0
23 0x01 bNumDescriptors = 1
24 0x22 bDescriptorType = Report
25 0x3F wDescriptorLength = 0x003F = 63 字节
26 0x00
27 0x07 bLength = 7 (Endpoint)
28 0x05 bDescriptorType = Endpoint
29 0x81 bEndpointAddress = 0x81 (EP1 IN)
30 0x03 bmAttributes = 0x03 (Interrupt)
31 0x08 wMaxPacketSize = 8
32 0x00
33 0x0A bInterval = 10 ms
字符串描述符
字符串 0(语言 ID):
00 0x04 bLength = 4
01 0x03 bDescriptorType = String
02 0x09 wLANGID[0] = 0x0409 (英语-美国)
03 0x04
字符串 1(厂商名 "STMicroelectronics"):
00 0x26 bLength = 38 (2 + 18×2)
01 0x03 bDescriptorType = String
02~ ... "STMicroelectronics" in UTF-16LE
十一、总结
Level 4
Level 3
Level 2
Level 1
Level 0
Device Descriptor
18字节
设备全局信息
Configuration Descriptor
9字节 + 子描述符
一种工作模式
Interface Descriptor
9字节
一个逻辑功能
IAD
8字节
接口关联
Endpoint Descriptor
7字节
数据传输通道
Class-Specific
HID/CDC/Hub...
类特定描述符
String Descriptor
可变
可读文本信息
描述符设计核心思想:
- 自描述:设备通过描述符告知主机"我是谁、我能做什么"
- 分层级联:从设备 → 配置 → 接口 → 端点,层层细化
- 灵活扩展:通过类特定描述符支持各种设备类
- 动态配置:同一设备可有多套配置/接口,按需切换