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 :

alt

各字段的含义:

  • 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 中找到。 alt

Collection 主要使用下面四种,属于可选数据占用 1 字节

  • Physical:物理层次描述,定义了设备的物理结构和连接方式,关注的是设备的物理特性和交互方式。例如,鼠标的按钮和滚轮。
  • Application:应用层次描述,定义了设备的输入和输出行为,以及设备与操作系统或应用程序之间的交互方式。例如,游戏手柄的按键和摇杆、音频设备的音量控制。
  • Logical:逻辑层次作为 Physical 和 Application 之间的桥梁,定义了输入设备的逻辑结构和映射关系。例如,将鼠标的滚轮映射为音量控制功能。
  • Vendoer Defined

alt 例如下面就是一个 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 ,下面摘抄了部分: alt 下面是一个 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 的含义。 alt

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 组合而成,从解析的角度来看报告描述符如下: rp.png 这是一个典型的树形结构,不同的 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