4. 标准设备请求:GET_DESCRIPTOR、SET_ADDRESS、SET_CONFIGURATION 等请求的格式与作用
USB 枚举过程的核心是 Host 通过 默认控制管道(Default Control Pipe,端点 0) 向设备发送一系列标准设备请求。这些请求的格式、字段含义以及设备必须遵循的响应行为,构成了 USB 设备枚举的“通用语言”。本章将详细解析最关键的三个标准请求:GET_DESCRIPTOR、SET_ADDRESS 和 SET_CONFIGURATION,并涵盖其他辅助请求。
4.1 标准设备请求的数据包格式
所有标准设备请求均通过 Setup 数据包(Setup Packet) 发起,该数据包固定为 8 字节,由 Host 在控制传输的 Setup 阶段 发送。其格式如下表所示:
| 偏移量(字节) | 字段名 | 长度(字节) | 描述 |
|---|---|---|---|
| 0 | bmRequestType | 1 | 请求特性:方向(Host→Device / Device→Host)、类型(标准/类/厂商)、接收者(设备/接口/端点/其他) |
| 1 | bRequest | 1 | 请求代码(如 GET_DESCRIPTOR = 0x06,SET_ADDRESS = 0x05) |
| 2 | wValue | 2 | 请求参数(小端序),含义因请求而异 |
| 4 | wIndex | 2 | 索引或偏移(小端序),通常用于指定接口或端点号 |
| 6 | wLength | 2 | 数据阶段期望传输的字节数(小端序);若为 0 则无数据阶段 |
关键点: bmRequestType 的 D7 位决定数据方向:0 = Host 输出(设置),1 = Host 输入(获取)。D6~D5 位决定类型:00 = 标准,01 = 类,10 = 厂商。D4~D0 位决定接收者:00000 = 设备,00001 = 接口,00010 = 端点,00011 = 其他。
4.2 GET_DESCRIPTOR(获取描述符)
作用: Host 请求设备返回指定的描述符数据,用于识别设备类型、能力、配置和端点信息。这是枚举过程中 最频繁 使用的请求。
请求格式:
- bmRequestType: 0x80(Device → Host,标准,设备接收者)
- bRequest: 0x06
- wValue(高字节): 描述符类型(如 1 = 设备描述符,2 = 配置描述符,3 = 字符串描述符)
- wValue(低字节): 描述符索引(对于字符串描述符,表示字符串编号)
- wIndex: 语言 ID(仅对字符串描述符有效;其他描述符填 0)
- wLength: 期望返回的字节数
典型枚举流程中的 GET_DESCRIPTOR 调用:
- 获取设备描述符(前 8 字节): Host 先请求 8 字节,获取
bMaxPacketSize0字段,以确定端点 0 的最大包长度。 - 复位并重新枚举: 设备收到
SET_ADDRESS后,Host 再次请求完整设备描述符(通常 18 字节)。 - 获取配置描述符(完整结构): Host 先请求配置描述符(9 字节),获取总长度字段
wTotalLength,然后请求完整配置描述符集(包括接口描述符、端点描述符等)。 - 获取字符串描述符(可选): 若设备支持字符串,Host 请求厂商、产品、序列号等字符串。
移植适配提示: 不同 Host 驱动在
GET_DESCRIPTOR 请求的 wLength 值上存在差异。例如,某些 Host 在获取设备描述符时请求 64 字节,而设备实际只返回 18 字节;设备必须能正确处理这种“请求大于实际”的情况,不能导致 STALL 或挂起。
4.3 SET_ADDRESS(设置地址)
作用: Host 为设备分配一个唯一的 USB 总线地址(1~127)。设备在收到此请求后,必须在 Status 阶段完成后 立即启用新地址。这是枚举过程中 第一个 改变设备状态的请求。
请求格式:
- bmRequestType: 0x00(Host → Device,标准,设备接收者)
- bRequest: 0x05
- wValue: 新地址(低字节有效,范围 1~127;高字节为 0)
- wIndex: 0x0000
- wLength: 0x0000(无数据阶段)
时序要求:
- 设备在收到 Setup 包后,必须立即记录新地址,但 不能立即切换。
- 设备完成 Status 阶段(Host 发送 0 长度 OUT 并收到 ACK)后,在 2 个帧(Full/Low Speed)或 2 个微帧(High Speed)内 切换到新地址。
- 切换后,设备使用新地址响应后续所有请求。
常见移植问题: 某些设备固件在
SET_ADDRESS 后过早切换地址,导致 Host 发送的 Status 阶段 ACK 无法被正确识别。设备必须严格遵循 USB 规范:在 Status 阶段完成前,仍使用默认地址 0 响应。
4.4 SET_CONFIGURATION(设置配置)
作用: Host 选择设备的一个配置(Configuration),使设备进入该配置所定义的工作状态。设备可以有多个配置(如高功耗模式与低功耗模式),但同一时刻只能激活一个。
请求格式:
- bmRequestType: 0x00(Host → Device,标准,设备接收者)
- bRequest: 0x09
- wValue: 配置值(bConfigurationValue,来自配置描述符;若为 0 则使设备进入未配置状态)
- wIndex: 0x0000
- wLength: 0x0000(无数据阶段)
设备响应行为:
- 验证
wValue是否等于某个配置描述符中的bConfigurationValue。 - 若匹配,设备根据该配置初始化所有接口和端点(分配缓冲区、使能端点等)。
- 若
wValue为 0,设备进入 未配置状态,禁用所有非端点 0 的端点。 - 若
wValue不匹配任何配置,设备应 STALL 该请求。
枚举顺序: 典型的枚举流程中,
SET_CONFIGURATION 是 最后一个 标准请求。Host 在获取并解析所有描述符后,调用此请求使设备进入可用状态。之后,设备才能进行正常的 I/O 数据传输。
4.5 其他标准设备请求
除了上述三个核心请求,USB 规范还定义了以下标准请求,它们在枚举和运行时管理中也扮演重要角色:
| 请求名称 | bRequest | 作用 | 数据方向 |
|---|---|---|---|
| GET_STATUS | 0x00 | 获取设备、接口或端点的状态(如自供电、远程唤醒使能等) | Device → Host |
| CLEAR_FEATURE | 0x01 | 清除指定的特性(如端点 HALT、设备远程唤醒) | Host → Device |
| SET_FEATURE | 0x03 | 设置指定的特性(与 CLEAR_FEATURE 对应) | Host → Device |
| SET_DESCRIPTOR | 0x07 | (可选)Host 向设备写入描述符,用于更新或添加描述符 | Host → Device |
| GET_CONFIGURATION | 0x08 | 获取当前激活的配置值(bConfigurationValue) | Device → Host |
| GET_INTERFACE | 0x0A | 获取指定接口的当前备用设置(bAlternateSetting) | Device → Host |
| SET_INTERFACE | 0x0B | 选择指定接口的备用设置(用于切换带宽或功能模式) | Host → Device |
| SYNC_FRAME | 0x0C | (已废弃,用于同步帧)设置或报告帧号 | Device → Host |
4.6 标准请求在枚举中的完整调用序列
以下 SVG 图展示了 Host 在枚举过程中调用标准设备请求的典型顺序,以及设备在每个阶段的状态变化:
移植适配要点: 不同 Host 驱动在枚举序列中可能插入额外的
GET_DESCRIPTOR 请求(如请求字符串描述符),或改变请求顺序(如某些 Host 在 SET_ADDRESS 前请求完整设备描述符)。设备固件必须能够容忍这些变化,不能假设固定的请求顺序。
4.7 设备固件实现要点
在移植 USB 设备固件时,处理标准设备请求需要关注以下关键点:
- Setup 包解析: 必须正确解析
bmRequestType的每一位,以区分标准/类/厂商请求和方向。 - 描述符缓冲区: 设备描述符、配置描述符集、字符串描述符必须按规范格式存储在 ROM 或 RAM 中,并能通过
GET_DESCRIPTOR返回。 - 地址切换时机:
SET_ADDRESS的地址切换必须在 Status 阶段完成后,且不能早于 Host 的 ACK。 - 配置切换:
SET_CONFIGURATION后,设备必须正确初始化所有端点(包括分配 FIFO、使能中断等)。 - STALL 处理: 对于不支持的请求或无效参数,设备应返回 STALL 握手,而不是忽略或返回错误数据。
常见错误: 设备在
GET_DESCRIPTOR 中返回的数据长度与 wLength 不匹配,或返回的描述符格式错误(如配置描述符中的 wTotalLength 与实际数据不符),会导致 Host 枚举失败或驱动加载错误。