USB-HID协议中文版 下载本文

196 计算机高级接口实践

8.3.3 接口描述符

接口描述符的代码如下。

;========================================= ; Interface descriptor 接口描述符 ;========================================= InterfaceDescriptor0: DB 0x09 ; bLength = 9,该描述符长度 DB 0x04 ; bDescriptorType = 4,表明是接口描述符 DB 0x00 ; bInterfaceNumber = 0,此接口的识别标识符 DB 0x00 ; bAlternateSetting = 0,表示此接口无替代设置值 DB 0x01 ; bNumEndpoints = 1,本接口的端点数目,HID设备使用端点1 DB 0x03 ; bInterfaceClass = 3,表示该设备是HID类别 DB 0x01 ; bInterfaceSubClass = 1,表示支持启动接口 DB 0x01 ; bInterfaceProtocol = 1,表示支持键盘协议 DB 0x00 ; iInterface = 0,接口描述符说明字符串的索引值,0表示无字符串 8.3.4 HID描述符

HID描述符的代码如下。

;========================================= ; HID descriptor HID描述符 ;========================================= HIDDescriptor0: DB 0x09 ; bLength = 9,该描述符长度 DB 0x21 ; bDescriptorType = 21h,表明是HID描述符 DB 0x00, 0x01 ; bcdHID = 0100,HID规范版本为1.00 DB 0x00 ; bCountryCode = 0,硬件设备所在国家的国家代码,0表示未指明 DB 0x01 ; nNumDescriptors = 1,表示支持的描述符有1个,即一个报表描述符 DB 0x22 ; bDescriptorType = 22h,描述符类别,表示支持的描述符是报表描述符 DB 0x3F, 0x00 ; wDescriptorLength = 63,表示支持的报表描述符的长度 8.3.5 端点描述符

端点描述符的代码如下。

;========================================= ; EndPoint descriptor 端点描述符 ;========================================= EndpointDescriptor0: DB 0x07 ; bLength = 7,该描述符长度 DB 0x05 ; bDescriptorType = 5,表明是端点描述符 DB 0x81 ; bEndpointAddress = 1000 0001b,表示1号输入端点 DB 0X03 ; bmAttributes = 00000011b,表示中断类型端点 DB 0x08, 0x00 ; wMaxPacketSize = 8,端点发送和接收的最大包尺寸为8 DB 10 ; bInterval = 10,表示中断端点轮询时间间隔为10ms 8.3.6 字符串描述符

字符串描述符的代码如下。

第8章 USB接口HID设备 197

;========================================= ; String descriptor 字符串描述符

;========================================= StringDescriptor0: DB 0x04 ; bLength = 4,字符串描述符0的长度为4 DB 0x03 ; bDescriptorType = 3,表明是字符串描述符 DB 0x09, 0x00 ; wLANGID = 0009h,表明是英语 DB 0x0A ; bLength = 10,字符串描述符的长度为10 DB 0x03 ; bDescriptorType = 3,表明是字符串描述符 DB 0x41, 0x00, 0x43, 0x00, 0x4D, 0x00, 0x45, 0x00 ; bString = “ACME“,Unicode编码的字符串 DB 0x22 ; bLength = 34,字符串描述符的长度为34 DB 0x03 ; bDescriptorType = 3,表明是字符串描述符 DB 0x4C, 0x00, 0x6F, 0x00, 0x63, 0x00, 0x61, 0x00 DB 0x74, 0x00, 0x6F, 0x00, 0x72, 0x00, 0x20, 0x00 DB 0x4B, 0x00, 0x65, 0x00, 0x79, 0x00, 0x62, 0x00 DB 0x6F, 0x00, 0x61, 0x00, 0x72, 0x00, 0x64, 0x00 ; bString = “Locator Keyboard“,Unicode编码的字符串 DB 0x0E ; bLength = 14,字符串描述符的长度为14 DB 0x03 ; bDescriptorType = 3,表明是字符串描述符 DB 0x41, 0x00, 0x42, 0x00, 0x43, 0x00, 0x21, 0x00 DB 0x22, 0x00, 0x23, 0x00 ; bString = “ABC123“,Unicode编码的字符串

8.3.7 报表描述符

报表描述符的代码如下。

;========================================= ;HID Reports Descriptor 报表描述符

;========================================= DB 0x05, 1 ; Usage Page (1: Generic Desktop) DB 0x09, 6 ; Usage (6: Keyboard) 表示报表定义的是HID键盘 DB 0xA1, 1 ; Collection (1: Application) ====================集合开始 ; ; 以下定义了键盘的修饰键输入报表,共有8个键,组成一个字节 ; 用法见HID Usage Table中的第10节中的键盘用法定义 DB 0x05, 7 ; Usage page (7: Key Codes) DB 0x19, 224 ; Usage Minimum (224) DB 0x29, 231 ; Usage Maximum (231) DB 0x15, 0 ; Logical Minimum (0) DB 0x25, 1 ; Logical Maximum (1) DB 0x75, 1 ; Report Size (1) DB 0x95, 8 ; Report Count (8) DB 0x81, 2 ; Input (Data,Variable,Absolute) ; ; 以下定义了一个保留字节的输入报表 DB 0x95, 1 ; Report Count (1) DB 0x75, 8 ; Report Size (8), DB 0x81, 1 ; Input (Constant) = Reserved Byte ; ; 以下定义了键盘的LED指示灯输出报表项目,共有5个指示灯 ; 用法见HID Usage Table中的第11节中的LED用法定义 DB 0x95, 5 ; Report Count (5)

198 计算机高级接口实践 DB 0x75, 1 ; Report Size (1) DB 0x05, 8 ; Usage Page (Page# for LEDs) DB 0x19, 1 ; Usage Minimum (1) DB 0x29, 5 ; Usage Maximum (5) DB 0x91, 2 ; Output (Data, Variable, Absolute) ; ; 以下定义了3个填充位,与前面的5个LED指示灯数据组成一个完整的字节 DB 0x95, 1 ; Report Count (1) DB 0x75, 3 ; Report Size (3) DB 0x91, 1 ; Output (Constant) ; ; 以下定义了键盘的按键值输入报表项目,共6个字节,存放键编号(0~101) ; 用法见HID Usage Table中的第10节中的键盘用法定义 ; 这样的设计可以允许一次输入6个按键的键值 DB 0x95, 6 ; Report Count (6) DB 0x75, 8 ; Report Size (8) DB 0x15, 0 ; Logical Minimum (0) DB 0x25, 101 ; Logical Maximum (101) DB 0x05, 7 ; Usage Page (7: Key Codes) DB 0x19, 0 ; Usage Minimum (0) DB 0x29, 101 ; Usage Maximum (101) DB 0x81, 0 ; Input (Data, Array)

DB 0xC0 ; End_Collection ================================ 集合结束

通过上面的报表描述符的定义,确定了键盘的输入报表和输出报表的数据格式。其中输入报表共8个字节,输出报表只有1个字节。

键值6 字节7

键值5 字节6

键值4 键值3 键值2 字节3

键值1 保留 修饰键 字节0

字节5 字节4 字节2 字节1

图8-4 键盘的输入报表格式

7~5 4 3 2 1 0 字节0 Nnm Lock 指示灯 Caps Lock 指示灯 Scroll Lock 指示灯 Compose 指示灯 Kana 指示灯 常数,保留 图8-5 键盘的输出报表格式

第8章 USB接口HID设备 199

8.4 HID的特定请求

除了USB设备的11个标准请求外,HID规范另外还定义了6个HID特定控制请求。所有的HID设备都必须支持Get_Report请求,同时支持启动的设备必须支持Get_Protocol请求和Set_Protocol请求,其他的请求是可选择的。如果设备没有中断输出端点,此设备需要支持Get_Report请求来从主机读取数据。

在控制传输的设置阶段的数据包中的8个字节中的第一字节bmRequestType的编码含义参阅第6章中的USB标准请求。第2个字节bRequest定义请求的内容。wValue因请求的不同而不同。wIndex指明HID所在的接口。

表8-10 HID特定的请求 bmRequestType bRequest (值) 1 01 00001b 0 01 00001b 1 01 00001b 0 01 00001b 1 01 00001b 0 01 00001b Get_Report (1) Set_Report (9) Get_Idle (2) Set_Idle (10) Get_Protocol (3) Set_Protocol (11) wValue wIndex wLength 数据阶段 报表 报表 闲置时间 无 0: 启动协议 1: 报表协议 无 报表类型,报表ID 接口 报表长度 报表类型,报表ID 接口 报表长度 0,报表ID 接口 1 0 1 0 闲置时间,报表ID 接口 0 0: 启动协议 1: 报表协议 接口 接口 8.4.1 Get_Report请求

Get_Report的作用是启用主机使用控制传输,来从设备读取数据。

在使用时wValue字段的高字节是报表类型,1表示Input报表,2表示Output报表,3表示Feature报表。wValue的低字节是报表的Report ID,如果没有定义Report ID,该字节为设0。

在携带请求的控制传输的数据阶段,HID设备回传指定的报表内容。

HlD规范不建议使用该请求获得未经定时的数据,这样的数据建议使用中断输入管道获得。

该请求用来取得在主机初始化设备时的特征项目状态和其他信息。使用开机协议的主机可以使用此请求来获得按键或鼠标数据。

8.4.2 Set_Report请求

Set_Report请求的参数含义和Get_Report一样,但Set_Report请求的数据方向与Get_Report相反,在后面的数据阶段,主机传送报表到HID设备,这样的输出报表可以用于复位设备的控制,复位产生的效果取决于对应的控制的类型是相对(Reletive)的还是绝对(Absolute)的。

8.4.3 Set_Idle请求

Set_Idle请求的作用是静默一个在中断输入管道的特定的报表,直到一个发生一个相关的事件或过去了规定的时间,当数据从上一个报表后没有改变时,可以通过限制中断输入端点的报表频率来节省传输带宽。HID设备不是必需支持此请求。

wValue字段的高字节是设置的闲置时间,是报表之间的最大间隔时间。该字节为0

200 计算机高级接口实践

表示闲置时间为无限长,在这种情况下,设备只有在报表数据有改变时才传送报表,否则设备传回一个NAK。

wValue字段的低字节指示此请求应用的报表的Report ID。如果低字节是0,此请求应用到设备的所有输入报表。

闲置时间以4ms为单位,范围在4ms~1020ms之间。如果报表的数据自从上一次报表后有改变,或是接收到一个请求,设备会传送一个报表。

如果报表的数据没有改变,而且从上一次报表后过去的时间自尚未达到规定的闲置时间,设备会传回一个NAK。如果报表的数据没有改变,而且持续时间已经达到的闲置时间,设备会传送一个报表。

闲置时间设置为0表示无限长的闲置时间,设备只有在报表的数据有改变时才会传送一个报表,对于其他的中断输入请求则是传回NAK。

在检测HID设备时,Wndows的HID驱动程序会试图将闲置时间设置成0。如果HID设备不支持此请求,主机会收到传回的Stall。

8.4.4 Get_Idle请求

Get_Idle请求的作用是过的设备的当前闲置时间,在数据阶段,HID设备回传一个字节的闲置时间值。

8.4.5 Get_Protocol请求

Get_Protocol请求的作用是主机获取设备目前作用的是启动协议还是报表协议。 在数据阶段中设备回传的1个字节信息包中的数据值为0表示启动协议,为1表示报表协议。

启动设备必需支持该请求。

8.4.6 Set_Protocol请求

Set_Protocol的作用是主机指定设备使用启动协议或报表协议。

在数据阶段中主机传送的1个字节信息包中的数据值为0表示指定启动协议,为1表示指定报表协议。

启动设备必需支持该请求。

8.5 HID程序设计

HID设备是Windows系统提供了完善支持的一类,应用程序可以通过标准的API函数调用,实现与HID设备的通信。Windows系统提供了几千个API函数,作为应用程序与操作系统的接口,与HID相关的API函数被封装在hid.dll、setupapi.dll和kernal32.dll文件中。

8.5.1 HID访问使用的API函数

文件hid.dll中提供了很多个API,因为与HID设备通信有一定的复杂性。首先,在应用程序与HID传输数据之前,应用程序必须先识别该设备并且读取它的报表信息,这些动作需要调用多个API函数才可以实现。应用程序需要寻找连接到系统上的是哪些HID设备,然后读取每个设备的信息直到查找到所需的属性。如果是客户化的设备,应用程序可以寻找特定的厂商与产品ID,或者应用程序可以寻找特定类型的设备,例如键盘或鼠标。