USB 枚举通讯过程

USB 设备在正常工作之前,第一件要做的事情就是枚举。枚举的作用就是让设备从上述状态图中的 Powered 逐步进入
Configured 模式。
USB 枚举的主要目的是读出设备的所有配置信息。
Transaction 1 ~ Transaction 3 (Data Stage)
可以看到 Transaction 1 ~ Transaction 3 联合起来从 Device
传递回了 18 个字节的数据给 Host, Transaction 1 和 Transaction
2 分别传输了 8 个字节数据, Transaction 2 传递了 2 个字节数据。
12010002000000086D0418C0014301020001
这 18 个字节数据就是 Transfer 0 指定要读取的 Device Descriptor
,其具体的格式如 Table 9-8 所示:

注意在这个阶段当中的几个全局 Field 的值:
-
ADDR:Device Address = 0 -
ENDP:EndPoint = 0 -
DATA0/DATA1:如果多次 Data Transaction 传输的是一段连续数据,DATA0DATA1连续翻转。如果多次 Data Transaction 传输的数据是不相关的,则不会翻转。
读回的具体 Device Descriptor 解析如下:

2.3. Transaction 4 (Status Stage)
状态阶段用于表示一次控制传输的结束。
首先发送一个 OUT 包,注意令牌包主要是指明传输类型,这里就为 OUT 类型。然后发一个大小为 0 的 DATA 包,Device 回一个 ACK 握手包。本次传输结束。
Reset (Powered → Default)

Host 向 Device 发送了一个 Reset 信号,由上边的状态图可以看出,USB 由 Powered 模式进入了
Default 模式。
Tranfser 1 (Control No Data) (Set Device Address) (Default →
Address)
Tranfser 1 的主要作用是设置 Device Address ,USB 由状态图中的
Default 模式进入了 Address 模式,是一个 Control
No Data 类型的 Transfer 。其中:
-
Transaction 5:Setup Stage -
Transaction 6:Status Stage

4.1. Transaction 5 (Setup Stage)
Packet 275 是核心,其中的 Setup Data 具体解析如下:
| Offset | Field | Size | Value | Description |
|---|---|---|---|---|
| 0 | bmRequestType | 1 | 0x00 | 表示期望的 数据传输方 向为主机传 输给设备。 |
| 1 | bmRequest | 1 | 0x05 | 代表了一个命令,根据 Table 9-4 可以得知代表
SET_ADDRESS |
| 2 | wValue | 2 | 0x03 0x00 | 根据 Table 9-3 可以得知,此时 代表的是: Device
Address 即 : Device Address =
0x03 |
| 4 | wIndex | 2 | 0x00 0x00 | 根据 Table 9-3 可以得知,此时 代表的是:
Zero |
| 6 | wLength | 2 | 0x00 0x00 | 根据 Table 9-3 可以得知,此时 代表的是:
Zero |
4.2. Transaction 6 (Status Stage)
状态阶段用于表示一次控制传输的结束。
Tranfser 2 (Control Read) (Get Device Descriptor)
Transfer 2 的作用是重新获取了一遍设备描述符 Get Device Descriptor
,不同之处不是用默认地址 0 获取的,而是用刚才配置的 Device Address 0x03 来获取的。它是一个 Control
Read 类型的 Transfer 。其中:
-
Transaction 7:Setup Stage -
Transaction 8~10:Data Stage -
Transaction 11:Status Stage

Transfer 2 和 Transfer 0 的主要区别在于,一是有了明确的设置地址。另外:
-
Transfer 0第一次获得设备描述符主要为了得到端点 0 可以发送的数据的大小,所以只要一个Transaction 1的 8 个字节数据就可。 -
Transfer 2完成了整个设备描述符的读取工作。
6. Tranfser 3 (Control Read) (Get Config Descriptor)
Transfer 3 的作用是获取配置描述符 Get Configuration Descriptor
,它是一个 Control Read 类型的 Transfer 。其中:
-
Transaction 12:Setup Stage -
Transaction 13~14:Data Stage -
Transaction 15:Status Stage

6.1. Transaction 12 (Setup Stage)
Packet 275 是核心,其中的 Setup Data 具体解析如下:
| Offset | Field | Size | Value | Description |
|---|---|---|---|---|
| 0 | bmRequestType | 1 | 0x80 | 表示期望的数据传输方向为设备传输给 主机,这条命令的接收者为设备。 |
| 1 | bmRequest | 1 | 0x06 | 代表了一个命令,根据 Table 9-4 可以得知代表的命令为获取描述符
GET_DESCRIPTOR |
| 2 | wValue | 2 | 0x00 0x02 | 根据 Table 9-3 可以得知,此时 代表的是: Descriptor
Type + Descriptor Index |
| 2 | Descriptor Index | 1 | 0x00 | 想要获取的描述符 index 为 0 |
| 3 | Descriptor Type | 1 | 0x02 | 根据 Table 9-5 可以得知,想要 获取的描述符为
Configuration Descriptor |
| 4 | wIndex | 2 | 0x00 0x00 | 根据 Table 9-3 可以得知,此时 代表的是: Zero
or Language ID |
| 6 | wLength | 2 | 0x09 0x00 | 根据 Table 9-3 可以得知,此时 代表的是:Description
Length 即:请求 Device 发送 Configuration
Descriptor 的 9 个字节 |
6.2. Transaction 13~14 (Data Stage)
可以看到 Transaction 13~14 联合起来从 Device 传递回了 9 个字节的数据给 Host,
Transaction 13 传输了 8 个字节数据, Transaction 14 传递了
1 个字节数据。
09022200010100A032
这 9 个字节数据就是 Transfer 12 指定要读取的 Configuration
Descriptor ,其具体的格式如 Table 9-10 所示:

读回的具体 Configuration Descriptor 解析如下:

6.3. Transaction 15 (Status Stage)
状态阶段用于表示一次控制传输的结束。
7. Tranfser 4 (Control Read) (Get 4 Descriptors)
Transfer 4 的作用是一次性获取了 4 个描述符 Get 4 Descriptors ,它是一个
Control Read 类型的 Transfer 。其中:
-
Transaction 16:Setup Stage -
Transaction 17~21:Data Stage -
Transaction 22:Status Stage
从格式上看它使用的命令 Setup Data 和 Transfer 3 一样,仅仅读取长度从
0x09 改成了 0x22 ,就一次性读出了 4 个描述符。
Transfer 3 的主要作用是读取 Descriptors 的总长度,
Transfer 4 根据这个长度读取了所有 Descriptors 。

7.1. Configuration Descriptor
09022200010100A032
Transaction 17~18 提供了 9 字节的 Configuration
Descriptor 数据,具体内容和解析如上一节一样。
7.2. Interface Descriptor
090400000103010200
Transaction 18~19 提供了 9 字节的 Interface Descriptor
数据,具体内容和解析如下:

Interface Descriptor 具体的格式如 Table 9-12 所示:

7.3. HID Descriptor
092111010001223400
Transaction 19~20 提供了 9 字节的 HID Descriptor
数据,具体内容和解析如下:

HID Descriptor 具体的格式如下所示:

7.4. Endpoint Descriptor
0705810305000A
Transaction 20~21 提供了 7 字节的 Endpoint Descriptor
数据,具体内容和解析如下:

Endpoint Descriptor 具体的格式如 Table 9-13 所示:

8. Tranfser 5 (Control Read) (Get String 0 Descriptor)
Transfer 5 的作用是获取了 index 0 的 String Descriptor
,它是一个 Control Read 类型的 Transfer 。其中:
-
Transaction 23:Setup Stage -
Transaction 24:Data Stage -
Transaction 25:Status Stage

8.1. Transaction 23 (Setup Stage)
800600030000FF00
Packet 366 是核心,其中的 Setup Data 具体解析如下:
| Offset | Field | Size | Value | Description |
|---|---|---|---|---|
| 0 | bmRequestType | 1 | 0x80 | 表示期望的数据传输方向为设备传输给 主机,这条命令的接收者为设备。 |
| 1 | bmRequest | 1 | 0x06 | 代表了一个命令,根据 Table 9-4 可以得知代表的命令为获取描述符
GET_DESCRIPTOR |
| 2 | wValue | 2 | 0x00 0x03 | 根据 Table 9-3 可以得知,此时 代表的是: Descriptor
Type + Descriptor Index |
| 2 | Descriptor Index | 1 | 0x00 | 想要获取的描述符 index 为 0 |
| 3 | Descriptor Type | 1 | 0x03 | 根据 Table 9-5 可以得知,想要获取 的描述符为 String
Descriptor |
| 4 | wIndex | 2 | 0x00 0x00 | 根据 Table 9-3 可以得知,此时 代表的是: Zero
or Language ID |
| 6 | wLength | 2 | 0xFF 0x00 | 根据 Table 9-3 可以得知,此时 代表的是: Description
Length 即:请求 Device 发送 String
Descriptor 最大长度 255 个字节 |
8.2. Transaction 24 (Data Stage)
可以看到 Transaction 24 联合起来从 Device 传递回了 4 个字节的数据给 Host。
04030904
index 0 String Descriptor ,表示的是 设备支持的语言。解析格式如下:

所以 Transaction 24 读回的 Language ID 为
0x0409 即美国英语。
9. Tranfser 6 (Control Read) (Get String 2 Descriptor)
Transfer 6 的作用是获取了 index 2 的 String Descriptor
,它是一个 Control Read 类型的 Transfer 。其中:
-
Transaction 26:Setup Stage -
Transaction 27~31:Data Stage -
Transaction 32:Status Stage

9.1. Transaction 26 (Setup Stage)
800602030904FF00
Packet 366 是核心,其中的 Setup Data 具体解析如下:
| Offset | Field | Size | Value | Description |
|---|---|---|---|---|
| 0 | bmRequestType | 1 | 0x80 | 表示期望的数据传输方向为设备传输给主机,这条 命令的接收者为设备。 |
| 1 | bmRequest | 1 | 0x06 | 代表了一个命令,根据 Table 9-4 可以得知代 表的命令为获取描述符
GET_DESCRIPTOR |
| 2 | wValue | 2 | 0x02 0x03 | 根据 Table 9-3 可以得知,此时代表的是: Descriptor
Type + Descriptor Index |
| 2 | Descriptor Index | 1 | 0x02 | 想要获取的描述符 index 为 2 |
| 3 | Descriptor Type | 1 | 0x03 | 根据 Table 9-5 可以得知,想要获取的描述符为 String
Descriptor |
| 4 | wIndex | 2 | 0x09 0x04 | 根据 Table 9-3 可以得知,此时代表的是: Language
ID 即 0x0409 美国英语 |
| 6 | wLength | 2 | 0xFF 0x00 | 根据 Table 9-3 可以得知,此时代表的是: Description
Length 即:请求 Device 发送 String Descriptor
最大长度 255 个字节 |
9.2. Transaction 27~31 (Data Stage)
可以看到 Transaction 27~31 联合起来从 Device 传递回了 36 个字节的数据给 Host。
240355005300420020004F00700074006900630061006C0020004D006F00750073006500
index 2 String Descriptor ,表示的是一个字符串。解析格式如下:

即读回了一个 34 字节的 unicode 字符串 55 00 53 00 42 00 20 00 4F 00 70 00 74 00 69 00 63
00 61 00 6C 00 20 00 4D 00 6F 00 75 00 73 00 65 00 转成 Ascii 码为
USB Optical Mouse 。
在上几节读取 Device Descriptor 时, iProduct 字段的值为 0x2 即
index 2 String Descriptor ,所以 iProduct 就是
USB Optical Mouse 。
0. Tranfser 7 (Control Read) (Get String 1 Descriptor)
Transfer 7 的作用是获取了 index 1 的 String Descriptor
,它是一个 Control Read 类型的 Transfer 。其中:
-
Transaction 33:Setup Stage -
Transaction 34~36:Data Stage -
Transaction 37:Status Stage

解析方式和上一节一样,最终读出了 16 字节的 unicode 字符串 4C 00 6F 00 67 00 69 00 74 00 65 00 63 00
68 00 转成 Ascii 码为 Logitech 。
即 Device Descriptor 中的 iManufacturer 字段为
Logitech 。
1. Tranfser 8 (Control No Data) (Set Configured) (Address →
Configured)
Tranfser 8 的主要作用是设置 Configured ,USB 由状态图中的
Address 模式进入了 Configured 模式,是一个
Control No Data 类型的 Transfer 。其中:
-
Transaction 38:Setup Stage -
Transaction 39:Status Stage

Transaction 38 (Setup Stage)
0009010300000000
Packet 439 是核心,其中的 Setup Data 具体解析如下:
| Offset | Field | Size | Value | Description |
|---|---|---|---|---|
| 0 | bmRequestType | 1 | 0x00 | 表示期望的数据传输方向为主机传输给设备 |
| 1 | bmRequest | 1 | 0x09 | 代表了一个命令,根据 Tab le 9-4 可以得知 代表的命令为
SET_CONFIGURATION |
| 2 | wValue | 2 | 0x01 0x00 | 根据 Table 9-3 可以得知,此时代表的是: Configuration
Value 即配置 0x01 |
| 4 | wIndex | 2 | 0x00 0x00 | 根据 Table 9-3 可以得知,此时
Zero |
| 6 | wLength | 2 | 0x00 0x00 | 根据 Table 9-3 可以得知,此时
Zero |
Tranfser 9
好像也没干成什么事。
Tranfser 10
获得 HID 描述符。
Tranfser 11
是枚举成功后,两次 host 与 device 之间传输数据。这里只截了部分图。Host 每个 bInterval 这么多时间就对 device 查询一下,看有没有数据要传,比如有没有键子被按下。每次都是,host 向 device 发送一个 IN 令牌包,如果没有数据,device 就回一个 NAK。

Tranfser 12

