UEFI开发探索82- YIE002USB开发板(05 制作HID设备)

请保留-> 【原文:  https://blog.csdn.net/luobing4365 和 http://yiiyee.cn/blog/author/luobing/】

从软件的角度,制作USB HID设备,需要理解的知识包括几大块:
1) USB协议的基本架构和软件架构;
2) USB描述符,包括标准描述符和类描述符;
3) USB命令,包括标准命令和类命令。

当然,如果能从字节序上(比如USB包的构成)了解USB通信的过程,对理解整个USB协议的构成也很有好处。但在编程中,不需要理解到这个地步。大部分介绍USB协议的书籍,以及USB规范中,都很详细地描述了这些过程,非常建议读一读。

在前一篇中,已经简要地概述了USB协议的基本架构和软件架构。本篇主要介绍USB描述符中的标准描述符,这是所有USB设备都要支持的描述符。

1 USB描述符概述

为了方便USB主机对USB设备进行管理,USB-IF对USB设备的功能采用了分层结构,包括设备层、配置层、接口层和端点层。图1给出了一个复合设备的例子,展示了USB设备的分层结构。

图1 USB设备的功能分层结构

这四层的作用分别为:

  1. 设备层。说明USB设备的主要类型特征(如设备类别、接口、端点等属性),保障设备枚举过程的正常进行。
  2. 配置层。选择不同的失败配置满足USB主机对设备功能的选择,可选择复式的设备接口功能,如图1展示的选择鼠标、键盘和游戏杆的复合功能。
  3. 接口层。将具体功能分类,不同的功能对用不同的操作方式。
  4. 端点层。针对特定的设备功能,选择不同的端点,提供不同的数据管道,与USB主机进行数据通讯。

为了描述USB设备的这些特征,USB规范定义了相应结构的描述符,包括设备描述符、配置描述符、接口描述符、端点描述符和字符串描述符等。表1给出了USB1.1下各种USB描述符的类型值。

表1 USB1.1的描述符类型值

类型 描述符 描述符值
标准描述符设备描述符(Device Descriptor)0x01
配置描述符(Configuration Descriptor) 0x02
字符串描述符(String Descriptor) 0x03
接口描述符(Interface Descriptor) 0x04
端点描述符(Endpoint Descriptor) 0x05
类描述符 集线器类描述符(hub descriptor) 0x29
人机接口类描述符(HID) 0x21
厂商自定义0xFF

其他版本的USB规范,还定义了其他类型的描述符,比如USB 2.0中的设备限定描述符(Device_Qualifier)、USB 3.2中的二进制设备对象存储描述符(Binary Device Object Store,简称BOS)等。这些内容在博客中不会涉及,可在USB-IF的官网下载相关的USB规范文档了解。

下面对标准描述符进行详细介绍。

2 USB标准描述符

不管哪种USB设备,都必须提供标准描述符,用于告知主机设备本身的属性。以下介绍的内容,会比较枯燥,建议使用Bus Hound或USB逻辑分析仪等工具,去抓取USB设备的识别和通信包,实际体会这些描述符的用法。

如图2,抓取的是自制的USB HID设备信息。设备描述符中,含有自定义的厂商ID和产品ID,分别为0x8765和0x4321。

图2 BUS Hound抓取USB包

USB主机会发送USB命令给USB设备,图2中的GET_DESCRIPTOR是常用的获取描述符命令。USB设备根据命令所要求的,给出对应的描述符。本篇主要讲述描述符的结构,USB命令将在后续的博客中讲述。

2.1 设备描述符

USB的设备描述符用于表示USB设备的一般信息,如制造商ID、产品序列号等。一个USB设备有且只有一个设备描述符,它是USB主机所读取的第一个描述符,其结构如表2所示。

表2 设备描述符的结构

偏移大小描述
0bLength1数字描述符字节数长度(0x12)
1bDescriptor1常量描述符的类型(0x01)
2bcdUSB2BCD码USB设备支持的协议版本号
4bDeviceClass1设备类代码
5bDeviceSubClass1子类子类代码,更加bDeviceClass来定
6bDevicePortocol1协议协议码
7bMaxPacketSize01数字端点0的最大包长度
8idVendor2ID厂商ID(由USB-IF赋值)
10idProduct2ID产品ID(由厂商赋值)
12bcdDevice2BCD码设备发行号(BCD码)
14iManufacturer1索引厂商信息的字符串描述符索引值
15iProduct1索引产品信息的字符串描述符索引值
16iSerialNumber1索引设备序列号信息的字符串描述符索引值
17bNumConfigurations1数字配置描述符数目

设备描述符结构中的bMaxPacketSize0,它用来告知USB主机设备所支持的最大数据长度。

bDeviceClass表示设备所述的类别,如果此值为0,则表示每一个配置中的每个接口来指明它所属的类别(即在接口描述符中给出设备类),并且各接口独立工作。如果此值为0xFF,则由供应商自定义该设备类。介于两者之间的值0x1~0xFE,表示USB规范中定义的某个设备类,比如0x03表示HID设备类。它和bDeviceSubClass、bDeviceProtocol共同规定了设备的类别和采用的协议,更具体的分类定义,可以参考USB-IF官网。

设备描述符中的iManufacturer、iProduct和iSerialNumber,使用字符串描述符的索引值来进行描述,索引值为0表示没有字符串描述符对其进行描述。通过此索引值和USB命令Get_Descriptor,可以得到对应的字符串描述符。

2.2 配置描述符

USB规范中,USB设备可以有一个或者多个配置描述符,每个配置描述符提供了设备特定的配置。在设备描述符中的bNumConfigurations提供了配置描述符的个数,任何时刻只有一种配置处于工作状态。

配置描述符中提供了在该配置下设备的接口数目,一个设备的不同配置描述符可能包含不同数目和特性的设备接口。图1中的设备配置1,就包含了鼠标功能接口和键盘功能接口两种接口。此外,配置描述符中还会描述设备的供电方式(自供电/总线供电)、最大耗电量等信息。其结构如表3所示。

表3 配置描述符的结构

偏移大小描述
0bLength1数字描述符的字节数长度(0x09)
1bDescriptorType1常量配置描述符的类型(0x02)
2wTotalLength2BCD码配置信息的总长(包括配置、接口、端点和设备类及厂商定义的描述符)
4BnumInterfaces1该设备所支持的接口数目
5bConfigurationValue1子类配置值
6iConfiguration1协议描述该配置的字符串描述符索引值
7bmAttributes1数字配置特性:D7:保留 D6:自供电 D5:远程唤醒 D4…0:保留
8MaxPower1数字该配置下所需最大总线电流(2mA为单位)

2.3 接口描述符

USB设备的接口是端点的集合,负责完成该设备的特定功能,比如数据的输入和输出。接口描述符用来表示在USB设备中,各个接口的特性,包括接口的端点个数、所述的设备类和子类等。

拥有多个接口的USB设备,如果设备描述符中描述的bDeviceClass不为0,则表示接口之间是互斥关系,否则接口相互独立,每个接口有自己的类号、子类号和协议号。类号、子类号和协议号的定义,与设备描述符中的定义是一致的。接口描述符的结构如表4所示。

表4 接口描述符的结构

偏移大小描述
0bLength1数字描述符的字节数长度(0x09)
1bDescriptorType1常量接口描述符的类型(0x04)
2bInterfaceNumber1数字接口号(从0开始)
3bAlternateSetting1数字可选设置的索引值
4bNumEndpoint1数字此接口的端点数量(不计默认端点0)
5bInterfaceClass1接口所属的类值
6bInterfaceSubClass1子类接口所属子类的值
7bInterfaceProtocol1协议协议码,根据上面的两个值而定
8iInterface1索引表示此接口的字符串描述符的索引值

2.4 端点描述符

USB规范中,端点描述符用于指出USB设备端点的特性,包括其所支持的传输类型、传输方向等。端点0没有端点描述符,其他端点必须包含端点描述符。

端点是设备与主机之间进行数据传输的逻辑接口,除配置使用的端点0为双向外,其他均为单向。端点描述符描述了数据的传输类型、传输方向、数据包大小,以及端点地址,其结构如表5所示。

表5 端点描述符的结构

偏移大小描述
0bLength1数字描述符的字节数长度(0x07)
1bDescriptorType1常量端点描述符的类型(0x05)
2bEndPointAddress1端点描述了端点的地址、方向 Bit3…0:端点号 Bit6…4:保留,为0 Bit7:传输方向,如果是控制端点则忽略 0:输出端点(主机到设备) 1:输入端点(设备到主机)
3bmAttributes1位图端点传输类型 Bit1…0:传送类型 00B=控制传送 01B=实时传送 10B=批量传送 11B=中断传送
4wMaxPacketSize2数字接收/发送的最大数据包长度
6bInterval1数字周期数据传输端点的时间间隙

2.5 字符串描述符

字符串描述符是可选的,它描述了制造商、设备名称或序列号等信息。它使用的是Unicode编码,并支持多语言。USB主机要求获得字符串描述符时,需要用一个16位的语言标识出语言类别。比如,常用的语言标识1033表示美国英语,而2052表示中文。其他的语言标识,可以在微软的网站上找到 。

USB主机请求得到某个字符串描述符时分为两步,首先向USB设备发送USB命令Get_Descriptor,命令的wIndex字段设置为0,设备将返回描述语言标识的字符串描述符;然后,USB主机根据需要的语言,向USB设备发送命令Get_Descriptor,在命令对应的字段中设置字符串的索引值和语言标识,得到需要的字符串描述符。

字符串描述符有两种格式。第一种用来指明所用的语言标识,如表6所示。

表6 指明语言标识的字符串描述符

偏移大小描述
0bLength1N+2描述符的字节数长度(N+2字节)
1bDescriptorType1常量字符串描述符的类型(0x03)
2wLANGID[0]2数字语言标识(LANGID),码0
NwLANGID[x]2数字语言标识(LANGID),码x

第二种为Unicode字符串描述符,包含了非NULL结尾的Unicode字符串,如表7所示。

表7 Unicode字符串描述符

偏移大小描述
0bLength1N+2描述符的字节数长度(N+2字节)
1bDescriptorType1常量字符串描述符的类型(0x03)
2bStringN数字Unicode编码的字符串

在实际编写代码中,接口描述符、端点描述符一般是和配置描述符在同一数组中的。后续代码编写时,我们再来看实际的情况。

本篇篇幅较长,也许是目前写的最长的博客了。主要是为了后续查询方便,将标准描述符相关的细节都包含了。

下一篇讨论USB的HID类描述符。

1,110 total views, 1 views today

发表评论

电子邮件地址不会被公开。