USB描述符详解:设备的"身份证"和"能力说明书"
一、USB设备的多层次结构:一个身体,多重身份

核心概念:USB设备就像"变形金刚"
想象一下,一个USB设备可以像变形金刚 一样,在不同的场合展现不同的形态和能力。这种灵活性是通过USB的分层描述机制实现的。
二、生动的例子:理解"物理设备"与"逻辑功能"
例子1:4G上网卡------同一硬件,两种形态
详细解释:
-
第一次插入 :电脑识别为U盘
-
为什么?设备激活了"配置1"(U盘模式)
-
你可以拷贝驱动程序和安装文件
-
-
安装驱动后再次插入 :电脑识别为上网卡
-
驱动程序告诉设备:"切换到配置2"
-
设备重新配置,变成网络设备
-
关键点:
-
两种配置不能同时激活,就像人不能同时是"司机"和"厨师"
-
切换配置需要主机发送
SET_CONFIGURATION命令
例子2:USB耳机------一个设备,多种功能
详细解释:
-
音频功能:处理声音的播放和录制
-
按键控制:处理音量调节、静音按钮等
-
为什么分开?因为不同的功能需要不同的驱动程序管理
关键点:
-
多个接口可以同时工作,就像耳机一边播放音乐一边响应按键
-
每个接口是独立的"逻辑设备"
三、四层结构详解:从宏观到微观

结构层次关系
USB设备(物理实体)
├── 设备描述符(我是谁)
│ └── 配置描述符(我有几种工作模式)
│ ├── 接口描述符(我能做什么功能1)
│ │ ├── 端点描述符(我的数据通道1)
│ │ └── 端点描述符(我的数据通道2)
│ └── 接口描述符(我能做什么功能2)
│ └── 端点描述符(我的数据通道3)
└── 字符串描述符(我的名字和说明)
第1层:设备描述符(Device Descriptor)
这是设备的"身份证",每个设备只有一份。
包含信息:
-
基础身份:厂商ID、产品ID、设备版本号
-
能力信息:设备支持的配置数量
-
通信基础:端点0的最大数据包大小(控制通道容量)
-
可选信息:厂商名、产品名、序列号的字符串索引
现实类比:
设备描述符就像你的身份证:
姓名:XXX公司USB设备
身份证号:VID=0x1234, PID=0x5678
性别:USB2.0设备
住址:端点0最大包64字节
第2层:配置描述符(Configuration Descriptor)
这是设备的"工作模式说明书",一个设备可以有多个。
包含信息:
-
模式特性:该配置下的接口数量
-
电源需求:供电方式(自供电/总线供电)、最大电流
-
配置编号:用于选择该配置的编号
关键特性:
-
同一时间只能激活一个配置,就像你同一时间只能从事一份职业
-
bmAttributes字段:第6位=1表示自供电,第5位=1表示支持远程唤醒
-
bMaxPower字段:单位是2mA,值50表示需要100mA电流
第3层:接口描述符(Interface Descriptor)
这是设备的"功能说明书",一个配置下可以有多个接口。
包含信息:
-
功能分类:接口类型(音频、HID、大容量存储等)
-
通道数量:该接口下的端点数量(不包括端点0)
-
设置选项:备用设置(Alternate Setting)数量
重要概念:
-
接口类(bInterfaceClass):
-
0x08:大容量存储类(U盘)
-
0x03:HID类(鼠标、键盘)
-
0x01:音频类
-
0x0E:视频类
-
-
备用设置(Alternate Setting):
-
同一个接口可以有不同设置,比如不同的带宽要求
-
默认设置编号为0,可以动态切换到其他设置
-
第4层:端点描述符(Endpoint Descriptor)
这是设备的"数据通道说明书",一个接口下有多个端点。
包含信息:
-
通道地址:端点号(0-15)+ 方向(IN/OUT)
-
传输类型:批量、中断、同步
-
通道容量:最大数据包大小
-
查询频率:轮询间隔(对中断/同步端点)
端点地址编码:
端点地址 = (方向 << 7) | 端点号
例如:0x81 = 10000001B
↑ ↑
方向IN 端点号1
三种端点的区别:
| 端点类型 | 数据可靠性 | 时序要求 | 典型应用 |
|---|---|---|---|
| 批量端点 | 高(有重传) | 无要求 | U盘、打印机 |
| 中断端点 | 高 | 周期性查询 | 鼠标、键盘 |
| 同步端点 | 低(无重传) | 固定间隔 | 摄像头、音响 |
特殊成员:端点0
-
地位特殊:不通过端点描述符描述
-
信息位置 :其最大包大小在设备描述符的
bMaxPacketSize0字段 -
功能固定:专门用于控制传输,所有设备都必须有
四、描述符的读取过程:主机如何了解设备
枚举过程中的描述符读取顺序
1. 读取设备描述符(至少前8字节,获取端点0最大包大小)
2. 设置设备地址(SET_ADDRESS)
3. 再次读取完整设备描述符
4. 读取配置描述符(包括所有接口和端点描述符)
5. 根据接口类加载相应驱动程序
6. 驱动程序选择配置(SET_CONFIGURATION)
关键细节:配置描述符的"打包返回"
当主机请求配置描述符时,设备会一次性返回:
-
配置描述符本身(9字节)
-
所有接口描述符(每个9字节)
-
所有端点描述符(每个7字节)
-
可能还有其他类特定描述符
为什么打包 ?因为配置描述符的wTotalLength字段告诉主机这个配置的总长度。
五、实际数据结构示例
设备描述符实例(18字节)
cs
// 假设一个USB鼠标的设备描述符
struct {
bLength = 18, // 描述符长度
bDescriptorType = 1, // 设备描述符类型
bcdUSB = 0x0110, // USB 1.1
bDeviceClass = 0, // 类在接口描述符中定义
bDeviceSubClass = 0,
bDeviceProtocol = 0,
bMaxPacketSize0 = 8, // 端点0最大包8字节
idVendor = 0x1234, // 厂商ID
idProduct = 0x5678, // 产品ID
bcdDevice = 0x0100, // 设备版本1.0
iManufacturer = 1, // 字符串描述符索引1
iProduct = 2, // 字符串描述符索引2
iSerialNumber = 0, // 无序列号
bNumConfigurations = 1 // 只有一个配置
};
配置描述符实例(9字节)
cs
struct {
bLength = 9,
bDescriptorType = 2, // 配置描述符类型
wTotalLength = 34, // 配置总长度34字节
bNumInterfaces = 1, // 1个接口
bConfigurationValue = 1,// 配置编号1
iConfiguration = 0, // 无配置字符串
bmAttributes = 0xA0, // 总线供电,支持远程唤醒
bMaxPower = 50 // 100mA (50 * 2mA)
};
接口描述符实例(9字节)
cs
struct {
bLength = 9,
bDescriptorType = 4, // 接口描述符类型
bInterfaceNumber = 0, // 接口0
bAlternateSetting = 0, // 默认设置
bNumEndpoints = 1, // 1个端点(除了端点0)
bInterfaceClass = 3, // HID类
bInterfaceSubClass = 1, // 引导接口
bInterfaceProtocol = 2, // 鼠标协议
iInterface = 0 // 无接口字符串
};
端点描述符实例(7字节)
cs
struct {
bLength = 7,
bDescriptorType = 5, // 端点描述符类型
bEndpointAddress = 0x81,// IN端点,端点1
bmAttributes = 0x03, // 中断传输
wMaxPacketSize = 4, // 最大包4字节
bInterval = 10 // 10ms轮询间隔
};
六、重要概念澄清和易错点
1. 配置 vs 接口:什么时候用哪个?
-
选择配置:当需要完全改变设备的工作模式时(如U盘↔上网卡)
-
选择接口:当需要启用/禁用某个功能时(如关闭耳机的麦克风)
2. 端点0的特殊性
-
双向性:既是IN也是OUT端点
-
无需描述符:特性在设备描述符中定义
-
固定用途:专用于控制传输
3. 字符串描述符的可选性
-
不是必须:设备可以没有字符串描述符
-
索引机制 :其他描述符中的
iManufacturer等字段是字符串索引 -
多语言支持:字符串描述符可以支持多种语言
4. 描述符的"树形结构"特性
-
不可跳跃:主机必须按层次理解设备
-
自包含:每个描述符都有长度和类型字段
-
扩展性:可以通过类特定描述符扩展功能
七、实践应用:如何查看真实设备的描述符
在Windows上可以使用USBView 工具,在Linux上可以使用lsusb -v命令查看设备的完整描述符。
示例输出解析:
cs
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 2.00
bDeviceClass 0 (Defined at Interface level)
bDeviceSubClass 0
bDeviceProtocol 0
bMaxPacketSize0 64
idVendor 0x1234
idProduct 0x5678
bcdDevice 1.00
iManufacturer 1 "Example Corp"
iProduct 2 "USB Mouse"
iSerial 0
bNumConfigurations 1
八、总结:描述符的重要性
USB描述符是USB系统的核心元数据,它们:
-
实现即插即用:主机通过读取描述符自动识别设备类型
-
提供灵活性:允许一个物理设备支持多种功能
-
保证兼容性:标准的描述符格式确保不同厂商设备的互操作性
-
支持扩展:类特定描述符允许定义新的设备类型
记忆口诀
cs
设备描述符:我是谁(身份)
配置描述符:我能怎么工作(模式)
接口描述符:我能做什么(功能)
端点描述符:我怎么交换数据(通道)
理解描述符的结构和含义,是理解USB设备工作原理的关键。无论是开发USB设备固件,还是编写USB主机驱动程序,都必须熟练掌握描述符的相关知识。