原文地址:www.beyondlogic.org/usbnutshell…
原文作者:
发布时间:
USB描述符
所有的USB设备都有一个描述符的层次结构,它向主机描述了一些信息,如设备是什么,谁制造的,它支持什么版本的USB,它可以有多少种配置方式,端点的数量及其类型等。
比较常见的USB描述符有
USB设备只能有一个设备描述符。设备描述符包括诸如设备符合的USB修订版、用于加载适当驱动程序的产品和供应商ID,以及设备可以拥有的配置数量等信息。配置数量表示有多少个配置描述符分支要遵循。
配置描述符指定了一些值,例如这个特定配置使用的功率,设备是自供电还是总线供电,以及它拥有的接口数量。当一个设备被枚举时,主机读取设备描述符,可以决定启用哪个配置。它一次只能启用一个配置。
例如,可以有一个大功率总线供电配置和一个自供电配置。如果设备被插入带有主电源的主机,设备驱动程序可能会选择启用高功率总线供电配置,使设备无需连接到主电源即可供电,但如果它被连接到笔记本电脑或个人整理器,它可以启用第二种配置(自供电),要求用户将设备插入电源点。
配置设置并不限于电源的差异。每种配置都可以以相同的方式供电,消耗相同的电流,但却有不同的接口或端点组合。不过需要注意的是,改变配置需要停止每个端点的所有活动。虽然USB提供了这种灵活性,但很少有设备有1种以上的配置。
接口描述符可以被看作是一个头或将端点分组成一个功能组,执行设备的单一功能。例如你可以有一个多功能的传真/扫描/打印机设备。接口描述符一可以描述传真功能的端点,接口描述符二描述扫描仪功能,接口描述符三描述打印机功能。与配置描述符不同,一次只启用一个接口没有限制。一个设备可以同时启用一个或多个接口描述符。
接口描述符有一个bInterfaceNumber字段,指定接口号,还有一个bAlternateSetting字段,允许接口在运行中改变设置。例如我们可以有一个设备有两个接口,接口一和接口二。接口一的bInterfaceNumber设置为0,表示它是第一个接口描述符,bAlternativeSetting为0。
接口二的bInterfaceNumber设置为1,表示它是第二个接口,bAlternativeSetting为0(默认)。然后我们可以抛出另一个描述符,也是bInterfaceNumber设为1,表示它是第二个接口,但这次将bAlternativeSetting设为1,表示这个接口描述符可以是另一个接口描述符二的替代设置。
启用此配置后,使用bAlternativeSettings等于0的前两个接口描述符。但是在操作过程中,主机可以发送一个SetInterface请求,直接指向接口一的替代设置,以启用另一个接口描述符。
这样做的好处是比有两个配置更有优势,因为我们在改变与接口一相关的端点设置时,可以通过接口零传输数据,而不影响接口零。
每个端点描述符用于指定每个端点的传输类型、方向、轮询间隔和最大数据包大小。端点零,即默认的控制端点总是被假定为控制端点,因此从来没有描述符。
USB描述符的组成
所有的描述符都由一个共同的格式组成。第一个字节指定描述符的长度,第二个字节表示描述符的类型。如果一个描述符的长度小于规范定义的长度,那么主机将忽略它。但是,如果描述符的大小大于预期,则主机将忽略多余的字节,并在返回的实际长度的最后开始寻找下一个描述符。
| 偏移 | 字段 | 大小 | 值 | 说明 |
|---|---|---|---|---|
| 0 | bLength | 1 | Number | 描述符的大小(字节) |
| 1 | bDescriptionType | 1 | 常数 | DescriptorType |
| 2 | ... | n | 描述符参数的开始 |
设备描述符
一个USB设备的设备描述符代表了整个设备。因此,一个USB设备只能有一个设备描述符。它指定了有关设备的一些基本但重要的信息,如支持的USB版本、最大数据包大小、供应商和产品ID以及设备可以拥有的配置数量。设备描述符的格式如下所示。
| 偏移 | 字段 | 大小 | 值 | 说明 |
|---|---|---|---|---|
| 0 | bLength | 1 | Number | 描述符的大小,以字节为单位(18字节)。 |
| 1 | bDescriptorType | 1 | 常量 | 设备描述符 (0x01) |
| 2 | bcdUSB | 2 | BCD | 裝置符合的 USB 規格編號。 |
| 4 | bDeviceClass | 1 | Class | 类别代码(由USB组织指定)。如果等于零,每个接口都会指定自己的类代码。如果等于0xFF,则类代码是供应商指定的。否则,该字段为有效的类代码。 |
| 5 | bDeviceSubClass | 1 | 子类 | 子类代码(由USB组织分配) |
| 6 | bDeviceProtocol | 1 | Protocol | 协议代码(由USB组织指定) |
| 7 | bMaxPacketSize | 1 | Number | 零端点的最大数据包大小,有效大小为8、16、32、64。有效大小为8、16、32、64。 |
| 8 | idVendor | 2 | ID | 供应商ID(由USB组织指定) |
| 10 | id产品2 | ID | 产品ID(由制造商指定) | |
| 12 | bcdDevice | 2 | BCD | 设备发布号 |
| 14 | iManufacturer | 1 | Index | 制造商索引字符串描述符 |
| 15 | iProduct | 1 | Index | 产品字符串描述符的索引 |
| 16 | iSerialNumber | 1 | 索引 | 序列号的索引 字符串描述符 |
| 17 | bNumConfigurations | 1 | 整数 | 可能的配置数量 |
-
bcdUSB字段报告设备支持的USB最高版本。该值以二进制编码的十进制为单位,格式为0xJJMN,其中JJ是主要版本号,M是次要版本号,N是次要版本号。例如,USB 2.0报告为0x0200,USB 1.1报告为0x0110,USB 1.0报告为0x0100。
-
bDeviceClass、bDeviceSubClass和bDeviceProtocol被操作系统用来为你的设备找到一个类驱动程序。通常只有bDeviceClass是在设备级设置的。大多数类规范选择在接口级别上标识自己,因此将bDeviceClass设置为0x00。这样,一个设备就可以支持多个类。
-
bMaxPacketSize字段报告端点零的最大数据包大小。所有设备都必须支持端点零。
-
idVendor和idProduct被操作系统用来为你的设备寻找驱动程序。Vendor ID是由USB-IF分配的。
-
bcdDevice的格式与bcdUSB相同,用于提供设备版本号。这个值是由开发者分配的。
-
存在三个字符串描述符,以提供制造商、产品和序列号的细节。对字符串描述符没有要求。如果没有字符串描述符,应使用零的索引。
-
bNumConfigurations 定义了设备在其当前速度下支持的配置数量。
配置描述符
一个USB设备可以有几种不同的配置,尽管大多数设备都很简单,只有一种配置。配置描述符指定了设备的供电方式,最大功耗是多少,它有多少个接口。因此,可以有两种配置,一种是设备总线供电时的配置,另一种是主电源供电时的配置。由于这是接口描述符的 "头",因此也可以让一个配置与另一个配置使用不同的传输模式。
一旦主机检查了所有配置,主机将发送一个SetConfiguration命令,该命令的值与其中一个配置的bConfigurationValue相匹配的非零值。这将用于选择所需的配置。
| 偏移 | 字段 | 大小 | 值 | 说明 |
|---|---|---|---|---|
| 0 | bLength | 1 | Number | 描述符的大小(字节) |
| 1 | bDescriptorType | 1 | 常量 | 配置描述符 (0x02) |
| 2 | w总长度 | 2 | 数量 | 返回的数据总长度(字节) |
| 4 | bNumInterfaces | 1 | 数量 | 接口数量 |
| 5 | bConfigurationValue | 1 | Number | 选择此配置时作为参数使用的值。 |
| 6 | iConfiguration | 1 | 索引 | 描述此配置的字符串描述符的索引。 |
| 7 | bmAttributes | 1 | Bitmap | D7 保留,设置为 1。(USB 1.0总线供电)。D6自供电。D5远程唤醒。D4..0 保留,设置为 0。 |
| 8 | bMaxPower | 1 | mA | 最大功耗(2mA单位) |
- 读取配置描述符时,会返回整个配置层次结构,其中包括所有相关的接口和端点描述符。wTotalLength字段反映的是层次结构中的字节数。
-
bNumInterfaces指定该配置存在的接口数量。
-
bConfigurationValue被SetConfiguration请求用来选择这个配置。
-
iConfiguration是指向以人类可读形式描述配置的字符串描述符的索引。
-
bmAttributes指定配置的电源参数。如果设备是自供电,则设置D6。在USB 1.0中,D7位用来表示总线供电设备,但现在由bMaxPower完成。如果设备使用总线供电,无论是作为总线供电设备还是作为自供电设备,都必须在bMaxPower中报告其功耗。设备还可以支持远程唤醒,当主机处于暂停状态时,设备可以唤醒主机。
-
bMaxPower定义了设备将从总线上消耗的最大功率。这是以2mA为单位,因此可以指定最大约500mA的功率。该规范允许一个高功率总线供电的设备从Vbus中消耗的功率不超过500mA。如果一个器件失去了外部电源,那么它的耗电量不能超过bMaxPower中所指示的数值。在没有外部电源的情况下,它不能执行的任何操作都应该失败。
接口描述符
接口描述符可以被看作是一个头或将端点分组为一个功能组,执行设备的单一功能。接口描述符符合以下格式:
| 偏移 | 字段 | 大小 | 值 | 说明 |
|---|---|---|---|---|
| 0 | bLength | 1 | Number | 描述符的大小,以字节为单位(9字节) |
| 1 | bDescriptorType | 1 | 常量 | 接口描述符 (0x04) |
| 2 | bInterfaceNumber | 1 | Number | 接口数量 |
| 3 | bAlternateSetting | 1 | Number | 用于选择替代设置的值 |
| 4 | bNumEndpoints | 1 | Number | 该接口使用的端点数量 |
| 5 | bInterfaceClass | 1 | 类 | 类别代码(由USB组织指定 |
| 6 | bInterfaceSubClass | 1 | 子类 | 子类代码(由USB组织分配) |
| 7 | bInterfaceProtocol | 1 | 协议 | 协议代码(由USB组织指定) |
| 8 | iInterface | 1 | 索引 | 描述该接口的字符串描述符的索引。 |
-
bInterfaceNumber表示接口描述符的索引。这应该以零为基础,每增加一个新的接口描述符就递增一次。
-
bNumEndpoints表示接口使用的端点数量。这个值应该不包括端点零,用于指示后续的端点描述符的数量。
-
bInterfaceClass、bInterfaceSubClass和bInterfaceProtocol可以用来指定支持的类(如HID、通信、大容量存储等),这允许许多设备使用类驱动程序,防止需要为您的设备编写特定的驱动程序。
-
iInterface允许对接口进行字符串描述。
端点描述符
端点描述符用于描述端点零以外的端点。端点零总是被假定为控制端点,并且在请求任何描述符之前就已经配置好了。主机将使用这些描述符返回的信息来确定总线的带宽需求。
| 偏移 | 字段 | 大小 | 值 | 说明 |
|---|---|---|---|---|
| 0 | bLength | 1 | Number | 描述符的大小,以字节为单位(7字节) |
| 1 | bDescriptorType | 1 | 常量 | 端点描述符 (0x05) |
| 2 | bEndpointAddress | 1 | 端点 | 注2 |
| 3 | bmAttributes | 1 | 位图 | 注3 |
| 4 | wMaxPacketSize | 2 | Number | 此端点能够发送或接收的最大数据包大小。 |
| 6 | bInterval | 1 | Number | 轮询端点数据传输的时间间隔。以帧数为单位的值。对于批量和控制端点,忽略。对于中断端点,异步必须等于1,该字段的范围为1至255。 |
注2:
端点地址
Bits 0...3b Endpoint Number.
Bits 4..6b 保留。设置为零
Bits 7 方向 0 = 出,1 = 入(控制端点忽略)。
注3:
Bits 0...1 = 传输类型
00 = 控制
01 = 异步法
10 = 散装
11 = 中断
Bits 2..7为保留位。如果是异步端点。
Bits 3..2 = 同步类型(Iso模式)
00 = 无同步化
01 = 异步
10 = 自适应
11 = 同步
Bits 5..4 = 使用类型(Iso模式)。
00 = 数据端点
01 = 反馈端点
10 = 显式反馈数据端点
11 = 保留
-
bEndpointAddress表示这个描述符描述的是什么端点。
-
bmAttributes指定传输类型。这可以是控制、中断、异步或批量传输。如果指定了Isochronous端点,可以选择其他属性,如同步和使用类型。
-
wMaxPacketSize表示该端点的最大有效载荷大小。
-
bInterval用于指定某些传输的轮询间隔。单位以帧为单位,因此对于低速/全速设备来说相当于1ms,对于高速设备来说相当于125us。
字符串描述符
字符串描述符提供人可读的信息,是可选的。如果不使用它们,描述符的任何字符串索引字段必须设置为零,表示没有可用的字符串描述符。
字符串以Unicode格式编码,产品可以支持多种语言。字符串索引0应返回支持的语言列表。通用串行总线语言标识符(LANGIDs)1.0版本中可以找到USB语言ID的列表。
| 偏移 | 字段 | 大小 | 值 | 说明 |
|---|---|---|---|---|
| 0 | bLength | 1 | Number | 描述符的大小(字节) |
| 1 | bDescriptorType | 1 | 常量 | 字符串描述符 (0x03) |
| 2 | wLANGID[0] | 2 | 数字 | 支持的语言代码为零(例如:0x0409 英文 - 美国) |
| 4 | wLANGID[1] | 2 | 数字 | 支持的语言代码一(例如:0x0c09英语-澳大利亚语) |
| n | wLANGID[x] | 2 | 数字 | 支持的语言代码 x(例如 0x0407 德语 - 标准) |
上面的字符串描述符显示了零号字符串描述符的格式。主机应该阅读这个描述符来确定哪些语言是可用的。如果支持某种语言,那么可以通过在Get Descriptor(String)请求的wIndex字段中发送语言ID来引用它。
所有后续字符串的格式如下。
| 偏移 | 字段 | 大小 | 值 | 说明 |
|---|---|---|---|---|
| 0 | bLength | 1 | Number | 描述符的大小(字节) |
| 1 | bDescriptorType | 1 | 常量 | 字符串描述符 (0x03) |
| 2 | bString | n | Unicode | 统一码编码字符串 |