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 调用:

  1. 获取设备描述符(前 8 字节): Host 先请求 8 字节,获取 bMaxPacketSize0 字段,以确定端点 0 的最大包长度。
  2. 复位并重新枚举: 设备收到 SET_ADDRESS 后,Host 再次请求完整设备描述符(通常 18 字节)。
  3. 获取配置描述符(完整结构): Host 先请求配置描述符(9 字节),获取总长度字段 wTotalLength,然后请求完整配置描述符集(包括接口描述符、端点描述符等)。
  4. 获取字符串描述符(可选): 若设备支持字符串,Host 请求厂商、产品、序列号等字符串。
移植适配提示: 不同 Host 驱动在 GET_DESCRIPTOR 请求的 wLength 值上存在差异。例如,某些 Host 在获取设备描述符时请求 64 字节,而设备实际只返回 18 字节;设备必须能正确处理这种“请求大于实际”的情况,不能导致 STALL 或挂起。
GET_DESCRIPTOR 请求流程 GET_DESCRIPTOR 请求流程(控制传输) Setup 阶段 Host 发送 8 字节 Setup 包 Data IN 阶段 设备返回描述符数据 Status 阶段 Host 发送 0 长度 OUT 关键字段示例(获取设备描述符) bmRequestType = 0x80 | bRequest = 0x06 | wValue = 0x0100(类型=1,索引=0) wIndex = 0x0000 | wLength = 0x0012(18 字节)或 0x0040(64 字节,视 Host 而定) 设备必须返回实际描述符数据,即使 wLength 大于实际长度; 若 wLength 小于实际长度,设备只返回 wLength 指定的字节数。

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(无数据阶段)

设备响应行为:

  1. 验证 wValue 是否等于某个配置描述符中的 bConfigurationValue。
  2. 若匹配,设备根据该配置初始化所有接口和端点(分配缓冲区、使能端点等)。
  3. 若 wValue 为 0,设备进入 未配置状态,禁用所有非端点 0 的端点。
  4. 若 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 在枚举过程中调用标准设备请求的典型顺序,以及设备在每个阶段的状态变化:

USB 枚举标准请求序列 USB 枚举标准请求序列(Host 视角) 1. 总线复位 2. GET_DESCRIPTOR (设备, 8B) 3. SET_ADDRESS 4. GET_DESCRIPTOR (设备, 18B) 5. GET_DESCRIPTOR (配置完整) 6. SET_CONFIGURATION
移植适配要点: 不同 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 枚举失败或驱动加载错误。