在上一个教程中,我们了解了 USB 设备如何与主机控制器通信。现在,我们将在本教程中了解 USB 描述符的妙处及其在枚举和配置过程中的作用,这使得 USB 设备可热插拔,因此事不宜迟,让我们深入研究它。
要理解 USB 描述符,首先我们需要很好地理解什么是 USB 请求!它们本质上只是主机发送到 USB 设备以与其通信的数据包。下面提到的是协议支持的 USB 请求类型。
- 标准请求:这些请求由 USB 规范定义,每个设备都必须理解它们。它们执行获取设备信息、设置配置和检查状态等基本任务。
- 类别请求:这些请求特定于特定设备类别(例如打印机、存储设备),并由相关类别规范定义。它们允许对设备功能进行更具体的控制。
- 供应商请求:这些请求由设备制造商定义,允许特定于供应商的控制和功能。
这里要注意的关键点是所有请求的结构都保持不变。现在了解了这一点,我们将了解 USB 描述符是什么:
USB 描述符
USB 描述符是指充当设备身份证的小信息包。这些描述符就像设备本身的手册,它们告诉主机需要了解的有关设备的所有信息,以便正确通信和使用设备。
描述符的类型
1.设备描述符
假设您刚刚将一个新的 USB 设备插入计算机,它可能是闪存驱动器、打印机、网络摄像头或任何其他使用 USB 的设备。嗯,你知道的,对吧?计算机如何知道它是什么或如何与它通信?这就是设备描述符的作用所在!
当设备插入时,主机向设备发出的第一个请求是设备描述符。它为主机提供了理解设备并与设备正确交互所需的所有基本信息。设备描述符包含下表中给出的字段。
Offset | Field | Size (Bytes) | Description |
---|---|---|---|
0 | bLength | 1 | 描述符的长度为18字节 |
1 | bDescriptorType | 1 | 描述符类型为 DEVICE (01h) |
2 | bcdUSB | 2 | USB 规范版本 (BCD) |
4 | bDeviceClass | 1 | 设备类别 |
5 | bDeviceSubClass | 1 | 设备子类 |
6 | bDeviceProtocol | 1 | 设备协议 |
7 | bMaxPacketSize0 | 1 | 端点 0 的最大数据包大小 |
8 | idVendor | 2 | 供应商 ID |
10 | idProduct | 2 | 产品 ID |
12 | bcdDevice | 2 | 设备版本号 (BCD) |
14 | iManfacturer | 1 | 制造商字符串索引 |
16 | iSerialNumber | 1 | 序列号字符串的索引 |
17 | bNumConfigurations | 1 | 支持的配置数量 |
- bLength:这是设备描述符的总长度(以字节为单位)。
- bcdUSB:这是一个二进制编码的十进制值,使用 0xAABC 格式,其中 A 是主版本号,B 是次版本号,C 是次次版本号,用于报告设备的 USB 版本,以帮助主机加载必要的驱动程序。例如,USB 1.1 的值为 0x0110。
- 主机使用bDeviceClass、bDeviceSubClass 和 bDeviceProtocol在枚举过程中识别 USB 设备的驱动程序。大多数 USB 设备在接口描述符中定义其类别,并将这些字段保留为 00h。
- bMaxPacketSize报告端点 0 支持的最大数据包数量。根据设备不同,可能的大小为 8 字节、16 字节、32 字节和 64 字节。
- iManufacturer、iProduct 和 iSerialNumber是字符串描述符的索引。字符串描述符提供有关制造商、产品和序列号的详细信息。如果存在字符串描述符,这些变量应指向其索引位置。如果不存在字符串,则应为相应字段分配零值。
- bNumConfigurations定义设备可以支持的配置总数。多个配置允许设备根据某些条件(例如总线供电或自供电)进行不同配置。
2.配置描述符
配置描述符提供了有关 USB 设备特定配置的基本信息。它概述了设备的组织方式以及设备与主机系统的交互方式。表中列出了配置描述符中涵盖的关键方面:
Offset | Field | Size (Bytes) | Description |
---|---|---|---|
0 | bLength | 1 | The length of this descriptor is 9 bytes |
1 | bDescriptorType | 1 | The descriptor type CONFIGURATION (02h). |
2 | wTotalLength | 2 | Total length, including interface and endpoint descriptors. |
4 | bNumInterfaces | 1 | The number of interfaces in this configuration |
5 | bConfigurationValue | 1 | Configuration value used by SET_CONFIGURATION to select this configuration |
6 | iConfiguration | 1 | Index of string that describes this configuration |
7 | bmAttributes | 1 | Bit 7: Reserved (set to 1) Bit 6: Self-powered Bit 5: Remote wakeup |
8 | bMaxPower | 1 | Maximum power required for this configuration. |
- wTotalLength: USB设备配置描述符的长度。
- bNumInterfaces:它定义了此特定配置中可能的接口总数,其最小值应为 1。
- bConfigurationValue:定义设备上可用配置的数量。
- bmAttributes:定义 USB 设备的参数。如果设备是总线供电的,则位 6 设置为 0;如果设备是自供电的,则位 6 设置为 1。如果 USB 设备支持远程唤醒,则位 5 设置为 1。如果不支持远程唤醒,则位 5 设置为 0。
- bMaxPower:定义设备完全运行时从总线吸收的最大功耗。
3.接口关联描述符(IAD)
IAD 的主要目的是将多个接口组合成一个功能单元。这确保主机能够识别它们并将它们作为一个统一的实体进行交互。早期的 USB 规范本身并不支持多接口功能。为了解决这一限制并增加对最新、更复杂设备的支持,引入了 IAD。
Offset | Field | Size (Bytes) | Description |
---|---|---|---|
0 | bLength | 1 | Description size in bytes |
1 | bDescriptorType | 1 | Descriptor type = INTERFACE ASSOCIATION (0Bh) |
2 | bFirstInterface | 1 | Number identifying the first interface associated with the function |
3 | bInterfaceCount | 1 | The number of contiguous interfaces associated with the function |
4 | bFunctionClass | 1 | Class code |
5 | bFunctionSubClass | 1 | Subclass code |
6 | bFunctionProtocol | 1 | Protocol code |
7 | iFunction | 1 | Index of string descriptor for the function |
- bLength:描述符的总长度(8字节)。
- bDescriptorType:将其标识为 IAD (0x0B)。
- bFirstInterface:属于该功能的第一个接口的编号。
- bInterfaceCount:函数中的接口数量。
- bFunctionClass、bFunctionSubClass、bFunctionProtocol:该函数的类、子类和协议代码。
- iFunction:函数名称的字符串描述符的可选索引。
4.接口描述符
它是一种定义 USB 设备内端点集合的数据结构。它充当设备如何与主机通信的蓝图。每个接口代表设备的不同功能。IAD 的主要目的是向主机提供有关特定接口的信息,包括:
- 类别代码(例如音频、HID、大容量存储)
- 端点(数据传输通道)
- 通信所用协议
- 备用设置(同一接口的不同配置)
下表定义了数据包中包含的内容
Offset | Field | Size (Bytes) | Description |
---|---|---|---|
0 | bLength | 1 | The length of this descriptor is 9 bytes |
1 | bDescriptorType | 1 | Descriptor type = INTERFACE (04h) |
2 | bInterfaceNumber | 1 | Zero based index of this interface |
3 | bAlternateSetting | 1 | Alternate setting value |
4 | bNumEndpoints | 1 | Number of endpoints used by this interface (not including EP0) |
5 | bInterfaceClass | 1 | Interface class |
6 | bInterfaceSubclass | 1 | Interface subclass |
7 | bInterfaceProtocol | 1 | Interface protocol |
8 | iInterface | 1 | Index to string describing this interface |
- bLength:描述符的总长度
- bDescriptorType:标识其为接口描述符
- bInterfaceNumber:接口的唯一编号
- bAlternateSetting:正在描述的替代设置的编号
- bNumEndpoints:接口bInterfaceClass使用的端点数量,
- bInterfaceSubClass、bInterfaceProtocol:定义设备类和特定协议iInterface:提供人类可读名称的字符串描述符的索引。
5.端点描述符
此描述符提供有关 USB 设备内特定端点的基本信息。它告诉主机如何与该端点通信以进行数据传输。每个端点都有一个用于特定方向(输入或输出)数据流的唯一通道。
下表表示端点描述符的结构:
Offset | Field | Size (Bytes) | Description |
---|---|---|---|
0 | bLength | 1 | The length of this descriptor is 7 bytes |
1 | bDescriptorType | 1 | The type of descriptor is ENDPOINT (05h) |
2 | bEndpointAddress | 1 | Bit 3…0: The endpoint number Bit 6…4: Reserved, reset to zero Bit 7: Direction. Ignored for Control 0 = OUT endpoint 1 = IN endpoint |
3 | bmAttributes | 1 | Bits 1…0: Transfer Type 00 = Control 01 = Isochronous 10 = Bulk 11 = Interrupt If not an isochronous endpoint, bits 5…2 are reserved and must be set to zero. If isochronous, they are defined as follows: Bits 3…2: Synchronization Type 00 = No Synchronization 01 = Asynchronous 10 = Adaptive 11 = Synchronous Bits 5…4: Usage Type 00 = Data endpoint 01 = Feedback endpoint 10 = Implicit feedback Data endpoint 11 = Reserved |
4 | wMaxPacketSize | 2 | Maximum packet size for this endpoint |
5 | bInterval | 1 | Polling interval in milliseconds for interrupt endpoints (1 for isochronous endpoints, ignored for control or bulk) |
- bLength:描述符的总长度(7 个字节)。
- bDescriptorType:将其标识为端点描述符(0x05)。
- bEndpointAddress:指定端点的地址和方向(位 7 表示 IN 或 OUT)。
- bmAttributes:定义端点的传输类型(控制、中断、批量或等时)。
- wMaxPacketSize:指示端点可以处理的最大数据包大小。
- bInterval:对于中断和等时端点,指定轮询间隔。
6.字符串描述符
此描述符提供人性化文本字符串来描述 USB 设备的各个方面。它是可选的,但为了方便用户使用和提高兼容性,建议使用。在语言方面,设备可以支持多种语言,并且可以为每种支持的语言提供不同的字符串描述符。字符串描述符可以包含以下信息:
- 设备名称
- 制造商名称
- 产品名称
- 序列号
- 接口名称
- 端点名称
- 配置名称
Offset | Field | Size (Bytes) | Description |
---|---|---|---|
0 | bLength | 1 | The length of this descriptor is 7 bytes |
1 | bDescriptorType | 1 | The descriptor type is STRING (03h). |
2 | bString -or wLangID | Varies | Unicode encoded text string -or LANGID code |
- bLength:描述符的总长度(变量)。
- bDescriptorType:标识其为字符串描述符(0x03)。
- bString:语言代码(例如,0 表示英语,4097 表示美国英语)。
- wString:以 UTF-16LE 编码的 Unicode 文本字符串。
好吧,到目前为止,本教程可能看起来有点太详细了,只有表格和定义,对吧?但现在,我们将了解这些表在枚举和配置过程中的用法,这使得 USB 协议具有通用性,并且使用此协议的设备可热插拔。
USB 枚举和配置
热插拔 USB 设备的神奇之处在于
- 动态检测
- 枚举
- 配置
动态检测
主机控制器监控 USB 端口的 D+ 和 D- 线上的转换,端口的 D+ 和 D- 线上的转换指示新连接的设备并确定设备的速度,如 USB 速度部分所述。但这里有个陷阱!主机只能确定设备是支持低速还是全速,高速设备呢?请记住这一点,这个问题的答案只在下一部分给出!
一旦 USB 主机检测到设备的速度,它就会通过将端口的 D+ 和 D- 线拉低来重置设备。这是因为端口上的 D+ 和 D- 线在主机端连接有下拉电阻。主机控制器通过将 D+ 和 D- 线拉低超过 2.5 us 来发出重置状态,主机控制器将此状态保持 10ms。在重置状态期间,高速设备发出单个 K 状态。高速集线器会检测到这种情况并以一系列“KJKJKJ”模式进行响应。设备检测到此模式并从其 D+ 线中移除上拉电阻。如果集线器未返回此模式,则表示集线器不支持高速设备,设备以全速运行。
枚举和配置
现在,主机掌握了设备速度信息,它开始通过默认地址 00h 上的控制端点 (EP0) 与设备通信。这里要注意的重点是,一次只能枚举一个设备,这意味着一次只能有一个设备获取 00h 地址。控制端点是双向的,控制事务通过此端点执行。在上一个教程中,我们了解了如何执行控制事务;在本教程中,我们将了解它们的重要性。
主机向设备发送GET_DESCRIPTOR命令,从设备获取设备描述符,从设备描述符的第八个字节(bMaxPacketSize0)中确定端点零支持的最大数据包大小。
那么,问题来了:如果事先不知道控制端点的最大数据包大小,那么主机如何接收 18 字节的设备描述符呢? 假设控制端点支持的最大数据包为 8 字节,那么设备会将描述符分成 8-8-2 字节的小块发送,这适用于所有类型的描述符。
获取设备描述符后,主机再次重置设备,并通过控制事务向设备发送 SET_ADDRESS 命令,为 USB 设备分配新地址。此后的所有通信都将使用新地址。设备从重置中返回后,主机使用新分配的地址发出命令 GET_DESCRIPTOR,以从设备读取描述符。但是,这次读取了所有描述符。主机使用此信息来了解设备及其功能。此信息包括外设接口数量、电源连接方法和所需的最大功率。此请求不仅返回配置描述符,还返回与其关联的所有其他描述符,例如接口描述符和端点描述符。
收到所有描述符后,主机使用 SET_CONFIGURATION 请求设置特定设备配置,然后主机加载设备驱动程序。主机搜索驱动程序来管理其自身与设备之间的通信。Windows 计算机使用其 .inf 文件来查找设备产品 ID 和供应商 ID 的匹配项。设备现在处于配置状态,可以从 VBUS 获得所需的功率,现在可以在应用程序中使用了。
这结束了枚举和配置过程,这使得主机控制器无需外部驱动程序或支持软件即可获得有关如何与 USB 设备通信的完整手册。
USB类
USB 类是指定义 USB 设备和接口的功能和性能的不同规范或标准。这些类可确保不同制造商生产的设备之间的兼容性。以下是一些常见的 USB 类:
标准类
-
标准类由官方 USB 规范定义,适用于常见设备类型。它们兼容不同的操作系统和主机设备。标准类的一些示例包括:
-
USB 人机接口设备 (HID):此类用于键盘、鼠标、游戏控制器和操纵杆等设备。它允许操作系统识别这些设备,而无需额外的驱动程序。
-
USB 大容量存储:USB 闪存驱动器、外部硬盘驱动器和存储卡读卡器等设备属于此类。它们可以轻松存储和检索数据。
-
USB 音频:此类用于扬声器、麦克风、耳机和声卡等音频设备。它允许通过 USB 连接传输音频数据。
-
USB 视频:网络摄像头和数码相机等用于捕捉或传输视频的设备使用此类。USB 视频设备通常遵循 USB 视频设备类 (UVC) 标准。
-
USB 打印机:支持打印、扫描和传真功能的打印机和多功能设备通常遵守 USB 打印机类规范。
-
USB 通信设备类 (CDC):此类包括调制解调器、串行端口和网络适配器等设备。它促进设备与主机之间的通信。
供应商特定类
供应商特定类不属于官方 USB 规范,而是由供应商实施,以提供其产品独有的专门功能或特性,并让制造商在设计设备时拥有更大的灵活性。这些类可能需要供应商特定的驱动程序或软件才能正常运行,并且可能与所有操作系统或主机设备不兼容。
查看 USB 描述符
在 Windows 上
我们可以使用 USB 设备树查看器在 Windows 上查看 USB 描述符,这是一个免费软件,可以通过此链接下载。以下是 USB 拇指驱动器描述符信息的几个快照。
在 Linux 上
在 Linux 上无需安装任何附加软件,我们可以使用 Linux USB 实用程序包,通过在终端上使用命令 lsusb。
在图中,您可以看到 USB 存储设备连接到总线 001,设备地址为 002。我们可以使用 lsusb 命令提供的选项来获取设备描述符。我们将使用 -s 选项和 -v 选项来定位特定设备以获取描述符。
本系列教程介绍了 USB 2.0 规范,介绍了 USB 数据传输在物理层面的实现方式、不同的 USB 速度以及总线的电力传输。接下来,我们了解了如何通过主机控制器使用的轮询机制在总线上进行通信,在本教程中,我们介绍了 USB 描述符如何充当存储在 USB 设备本身中的手册,这些手册在枚举和配置的不同阶段提供给主机控制器,以利用 USB 设备的功能。