HID 报告描述符
概述 链接到标题
USB HID 报告描述符 ( Report Descriptor) 是 USB 主机请求于 USB 设备的一种描述符。HID 设备用报告的形式发送数据到主机,描述符告诉主机如何解释数据。由于 USB HID 设备种类太多且支持多种自定义数据格式,很难定义出一种适用于所以 HID 设备的数据结构。如果定义出一个全都包的数据结构必然有很多冗余数据,会影响 HID 设备传输数据的实时性。因此 HID 的报告描述符采用不固定的数据结构,以项目 ( ITEM) 为基本单位组成, 不通的 HID 设备用不通数量和不同种类的 ITEM 来描述数据格式。
ITEM 链接到标题
ITEM 是报告描述符最基本的单位,有如下两种:
- long item
- short item
通常只会用用 short item, short item 的结构如下, 参考hid-6.2.2.2 :
各字段的含义:
- bSize: 指定可选数据 data 的长度
- bType: item 的类型
- bTag: item 的功能,不同类型下 bTag 定义不一样
- [data]: 可选数据
bSize 占用两个 bit,取值和对应可选数据的长度
- 0: 无可选数据
- 1:1 个字节的可选数据
- 2:2 个字节的可选数据
- 3:4 个字节的可选数据
bType 占用两个 bit,对应含义如下
- 0: Main
- 1: Global
- 2: Local
- 3: Reserved
Main Item 链接到标题
Main Item 用于定义数据域或进行数据域的分组 参考hid-6.2.2.4 ,包含下面五种:
- Input: 设备向主机上报数据,bTag=0x8
- Output:主机向设备发送数据, bTag=0x9
- Feature:返回配置信息, bTag=0xB
- Collection:数据分组开始, bTag=0xA
- End Collection::数据分组结束,, bTag=0xC
在每一个 Input、Output、Feature 的前缀字之后是 32bit 描述数据 ( 这 32bit 就是可选数据) ,目前最多定义了 9 个 bit,其余为保留位。bit0~8 的定义中只有位 7 不能应用于 Input 项目,除此之外其他的位定义都适应于 Input、Output、Feature 项目。 hid-6.2.2.5 中有详细说明每个 bit 的含义,这里不展开说明。下面是一个 Input Item 的示例:
0x81,0x46, // Input ( Data,Var,Rel,Null)
0x81 对应 bSize=1 表示有 1 个字节可选数据, bType=0 表示 Main Item, bTag=8 表示是 Input Item。后面跟着的一个字节数据是 0x46,展开二进制 b01000110,也就是 Data, Variable, Relative, No Wrap, Linear, Preferred State, Null state。这个 Item 就表示了向主机上报的是变量 ( Variable) 数据值 ( Data) ,相对变化 ( Relative) ,到最大值不会循环 ( No Wrap) ,线性变化 ( Linear) ,有预置状态 ( Preferred State) ,有无效状态 ( Null state) 。 Input Item 的 bit 位的对应关系参考下图,Output 和 Feature 的也可以在 hid-6.2.2.4 中找到。
Collection 主要使用下面四种,属于可选数据占用 1 字节
- Physical:物理层次描述,定义了设备的物理结构和连接方式,关注的是设备的物理特性和交互方式。例如,鼠标的按钮和滚轮。
- Application:应用层次描述,定义了设备的输入和输出行为,以及设备与操作系统或应用程序之间的交互方式。例如,游戏手柄的按键和摇杆、音频设备的音量控制。
- Logical:逻辑层次作为 Physical 和 Application 之间的桥梁,定义了输入设备的逻辑结构和映射关系。例如,将鼠标的滚轮映射为音量控制功能。
- Vendoer Defined
例如下面就是一个 Application 的 Colloection
0xA1,0x01, /* Collection ( Application) */
0x81 对应 bSize=1 表示有 1 个字节可选数据, bType=0 表示 Main Item, bTag=A 表示是 Colloection Item。后面跟一个字节数据是 0x01,表示是 Application。
End Collection 是 Collection 条目的结束标志,值固定为 0xC0。
Global Item 链接到标题
Global Item 主要用来选择用途页 ( Usage Page) ,定义数据域的长度 ( Report Count) 、数量 ( Report Size) 、报告 ID ( ReportId) 等。Global Item 对后续的所有 Item 有效,当遇到新的 Global Item 时才会变为新的定义数据。Global Item 在 hid-6.2.2.7 中有详细描述,这里不做展开,常用的有:
- Usage Page:用途页,bTag=0x0
- Logical Minimum:逻辑最小值,bTag=0x1
- Logical Maxinum:逻辑最大值,bTag=0x2
- Physical Minimum:物理最小值, bTag=0x3
- Physical Maximum:物理最大值,bTag=0x4
- Report Size:数据域大小,表示每个数据域有多少位, bTag=0x7
- Report Count: 有多少个数据域,bTag=0x9
- ReportId:报告 ID, bTag=0x8
其中 Usage Page 的可选数据项为 Page ID,值和含义参考 hut-Table 3.1 ,下面摘抄了部分: 下面是一个 Usage Page Global Item 的示例
0x05,0x01, /* Usage Page ( Generic Desktop Ctrls) */
0x05 ( 0b00000101) 对应 bSize=1 表示有 1 个字节可选数据, bType=1 表示 Global Item, bTag=0 表示是 Usage Page Item。后面跟一个字节数据是 0x01,表示是 Generic Desktop Ctrls。
Local Item 链接到标题
Local Item 用于定义数据的控制特性,如该数据域的用途,用途的最大值,用途的最小值等。Local Item 目只在局部有效,遇到一个 Main Item 后就失效。Local Item 在 hid-6.2.2.8 中有详细描述,这里不做展开,常用的有: Usage :用途,bTag=0x0 Usage Minmum:用途的最小值,bTag=0x1 Usage Maxmum:用途的最大值,bTag=0x2
其中 Usage 描述用途的内容根据 Usage Page 的不同而不同,在确定 Usage Page 后可以从 hut 中查询对应的 Usage 的含义, 例如当 Usage Page 是 Generic Desktop Ctrls 时,就需要从 hut-Table 4.1: Generic Desktop Page 中查找 Usage 的含义。
0x09,0x30, /* Usage ( X) */
0x09 ( 0b00001001) 对应 bSize=1 表示有 1 个字节可选数据, bType=2 表示 Local Item, bTag=0 表示是 Usage。后面跟一个字节数据是 0x01,在 Generic Desktop Ctrls 的 Usage 下 0x30 表示的是 X 坐标。
报告描述符 链接到标题
HID 的报告描述符由前面提到的各种 Item 组合而成,从解析的角度来看报告描述符如下: 这是一个典型的树形结构,不同的 HID 设备其描述符结构不同,我们看如何用标准的方法来描述一个 Item
如何描述 链接到标题
USB 官网提供一个可以生成 HID 报告描述符的工具:https://usb.org/document-library/hid-descriptor-tool,我们采用该工具的方法来描述 Item,针对不同的 Item 都有对应的标准功能名称,然后用 ITEM_FUNC ( Value) 来进行描述,常见的 ITEM_FUNC 如下,更多的请参考 dt 工具。
- Main Item
- Input: INPUT
- Output: OUTPUT
- Feature: FEATURE
- Collection: COLLECTION
- End Collection: END_COLLECTION
- Global Item
- Usage Page: USAGE_PAGE
- Logical Minimum: LOGICAL_MINIMUM
- Logical Maxinum: LOGICAL_MAXIMUM
- Physical Minimum: PHYSICAL_MINIMUM
- Physical Maximum: PHYSICAL_MAXIMUM
- Report Size: REPORT_SIZE
- Report Count: REPORT_COUNT
- ReportId: REPORT_ID
- Local Item
- Usage : USAGE
- Usage Minmum: USAGE_MINIMUM
- Usage Maxmum: USAGE_MAXIMUM
对于 Value 该 Tool 也有标准的描述,具体可以通过 dt 工具查看。
写一个描述符 链接到标题
以制作一个多媒体控制键盘为例,多媒体控制键盘上每个按建都用一个 bit 表示,逻辑状态值就只有 0 和 1:
LOGICAL_MINIMUM ( 0)
LOGICAL_MAXIMUM ( 1)
每个按建对应一个 bit,按建功能是分开定义,因此定义数据域为 1bit,一个按建只有一个数据域
REPORT_SIZE ( 1)
REPORT_COUNT ( 1)
一共有 6 个按建,分别是播放/暂停,音量+,音量-,下一首,上一首,对应 5 个 USAGE,这 5 个 bit 数据都要上传到 Host
USAGE ( Play/Pause)
INPUT ( Data,Var,Abs)
USAGE ( Volume Up)
INPUT ( Data,Var,Abs)
USAGE ( Volume Down)
INPUT ( Data,Var,Abs)
USAGE ( Scan Next Track)
INPUT ( Data,Var,Abs)
USAGE ( Scan Previous Track)
INPUT ( Data,Var,Abs)
上报数据以字节对齐,前面用了 5bit 的按建,因此要加入 3bit 对齐
REPORT_COUNT ( 1)
REPORT_SIZE ( 3)
INPUT ( Cnst,Var,Abs)
要上报的就是上面内容,将其合并到一起并加入 report 的 id 就是上报内容
REPORT_ID ( 1)
LOGICAL_MINIMUM ( 0)
LOGICAL_MAXIMUM ( 1)
REPORT_SIZE ( 1)
REPORT_COUNT ( 1)
USAGE ( Play/Pause)
INPUT ( Data,Var,Abs)
USAGE ( Volume Up)
INPUT ( Data,Var,Abs)
USAGE ( Volume Down)
INPUT ( Data,Var,Abs)
USAGE ( Scan Next Track)
INPUT ( Data,Var,Abs)
USAGE ( Scan Previous Track)
INPUT ( Data,Var,Abs)
REPORT_COUNT ( 1)
REPORT_SIZE ( 3)
INPUT ( Cnst,Var,Abs)
上报上面数据时,还需要让 HOST 知道我是多媒体控制器,因此加上下面内容让 Host 知道是多媒体控制器
USAGE_PAGE ( Consumer Devices)
USAGE ( Consumer Control)
COLLECTION ( Application)
REPORT_ID ( 1)
LOGICAL_MINIMUM ( 0)
LOGICAL_MAXIMUM ( 1)
REPORT_SIZE ( 1)
REPORT_COUNT ( 1)
USAGE ( Play/Pause)
INPUT ( Data,Var,Abs)
USAGE ( Volume Up)
INPUT ( Data,Var,Abs)
USAGE ( Volume Down)
INPUT ( Data,Var,Abs)
USAGE ( Scan Next Track)
INPUT ( Data,Var,Abs)
USAGE ( Scan Previous Track)
INPUT ( Data,Var,Abs)
REPORT_COUNT ( 1)
REPORT_SIZE ( 3)
INPUT ( Cnst,Var,Abs)
END_COLLECTION
可以在 dt 工具内输入上面报告描述符,然后转换为 C 数组
char ReportDescriptor [43] = {
0x05,0x0c, // USAGE_PAGE ( Consumer Devices)
0x09,0x01, // USAGE ( Consumer Control)
0xa1,0x01, // COLLECTION ( Application)
0x85,0x01, // REPORT_ID ( 1)
0x15,0x00, // LOGICAL_MINIMUM ( 0)
0x25,0x01, // LOGICAL_MAXIMUM ( 1)
0x75,0x01, // REPORT_SIZE ( 1)
0x95,0x01, // REPORT_COUNT ( 1)
0x09,0xcd, // USAGE ( Play/Pause)
0x81,0x02, // INPUT ( Data,Var,Abs)
0x09,0xe9, // USAGE ( Volume Up)
0x81,0x06, // INPUT ( Data,Var,Rel)
0x09,0xea, // USAGE ( Volume Down)
0x81,0x06, // INPUT ( Data,Var,Rel)
0x09,0xb5, // USAGE ( Scan Next Track)
0x81,0x02, // INPUT ( Data,Var,Abs)
0x09,0xb6, // USAGE ( Scan Previous Track)
0x81,0x02, // INPUT ( Data,Var,Abs)
0x75,0x03, // REPORT_SIZE ( 3)
0x95,0x01, // REPORT_COUNT ( 1)
0x81,0x01, // INPUT ( Cnst,Ary,Abs)
0xc0 //END_COLLECTION
};
Host 处理 链接到标题
在 HID 设备枚举的过程中,设备会先向主机发送报告描述符,主机按照 Item 的定义解析出报告描述符,知道设备发送的 HID 数据格式,当后续收到设备报文时就按报告描述符的定义进行解析。例如前面的示例解析完后知道只有 8bit 数据,每个 bit 表示哪个按建,然后再按照按键值进行分发处理。
HID 报告描述符适用情况 链接到标题
除了在 USB HID 设备中会使用 HID 报告描述符外,蓝牙的 HID 设备也会使用 USB 定义的 HID 报告描述符。
参考 链接到标题
https://www.usb.org/sites/default/files/documents/hid1_11.pdf https://www.usb.org/sites/default/files/hut1_22.pdf https://www.usbzh.com/article/detail-830.html https://www.usbzh.com/article/detail-525.html