USB HID(USB Human Interface Device Class)是 USB 设备类规范中承载 HID 的方式,用标准 USB 描述符、HID 类描述符、HID Report Descriptor 和 interrupt/control 传输让主机免厂商驱动接入人机接口设备。
它常用于键盘、鼠标、触控板、手柄、扫描枪、遥控器和少量厂商自定义控制器。USB HID 的关键优势是主流操作系统都有通用 HID 类驱动。
核心问题
USB 只提供设备枚举、配置、接口、端点和传输机制。主机还需要知道一个接口属于哪类设备,以及接口传输的数据怎么解释。
USB HID 解决的是“在 USB 上如何标准化发现、描述和交换 HID report”的问题。它让设备在插入时通过标准描述符告诉主机:我是 HID 接口,我的 report descriptor 在哪里,我会通过哪些端点收发 report。
核心对象
| 对象 | 含义 | 工程关注点 |
|---|---|---|
| USB device | 物理 USB 外设 | VID/PID、电源、速度、复合设备结构 |
| Configuration descriptor | 描述设备当前配置 | 一个设备可有多个 interface |
| Interface descriptor | 声明某个接口的 class/subclass/protocol | HID class、Boot Keyboard、Boot Mouse |
| HID descriptor | HID 类专用描述符 | 指向 report descriptor,声明 HID 版本 |
| HID Report Descriptor | 描述 report 布局和语义 | 主机解析 input/output/feature report 的依据 |
| Interrupt IN endpoint | 设备向主机上报 input report | 轮询间隔、最大包长、延迟 |
| Interrupt OUT endpoint | 主机向设备发送 output report,可选 | LED、震动、控制命令 |
| Control endpoint 0 | 枚举和类请求通道 | GET_DESCRIPTOR、GET_REPORT、SET_REPORT |
USB HID 的“免驱”来自这些描述符和类请求共同形成的标准契约,而不是主机猜测设备行为。
核心机制
1. 枚举阶段发现 HID 接口
USB HID 插入后的典型枚举路径是:
host reads device descriptor
-> host reads configuration descriptor
-> host finds HID interface
-> host reads HID descriptor
-> host reads report descriptor
-> host binds HID class driverInterface descriptor 中的 class/subclass/protocol 决定主机是否按 HID 类处理该接口。键盘、鼠标可以使用 Boot Interface Subclass,让早期启动环境用简化协议识别它们。
2. 运行时通过 report 交换数据
USB HID 常用 interrupt IN 端点上报输入:
device firmware
-> builds input report
-> host polls interrupt IN endpoint
-> device returns report
-> OS HID driver parses report“interrupt endpoint”名字容易误导。USB 里它不是设备主动打断主机,而是主机按端点声明的轮询间隔定期发起事务。设备有数据时在轮询中返回 report。
主机给设备的 output report 可以走 interrupt OUT 端点,也可以走 control endpoint 的 SET_REPORT 类请求。Feature report 常用于配置或状态查询,可能通过 control transfer 读写。
3. report descriptor 决定字节布局
设备固件发出的每个 report 必须和 report descriptor 一致。可以用一个简化关系表示:
runtime_report_bytes must match report_descriptor_layout这里的 report_descriptor_layout 包括 Report ID、字段顺序、字段 bit 长度、usage、logical range 和 padding。如果 descriptor 声明 4 字节 input report,但固件发送 5 字节或字段顺序不同,主机就会错解数据。
工程用途
- 标准键鼠和输入设备:插上即可被操作系统识别。
- 扫描枪和按键板:常模拟键盘,把扫描结果或按钮事件变成按键输入。
- 工业控制面板:少量按键、旋钮、指示灯可以用 HID report 表达。
- 自定义免驱通信:使用 Vendor-defined Usage Page 收发低速配置、状态或测试命令。
- 嵌入式 USB device:MCU 或 SoC 通过 USB device controller 暴露 HID 接口给 PC。
调试 USB HID 时,常看 USB 枚举日志、lsusb -v、report descriptor 解析结果、端点最大包长、轮询间隔、hidraw 节点、系统输入事件和抓包工具输出。
边界与常见坑
- USB HID 不等于所有 USB 外设:摄像头通常是 UVC,网卡、串口、存储都有自己的设备类。
- USB HID 不适合高吞吐数据流:HID 偏低速输入/控制;大量图像、音频、日志或固件传输应考虑其他类或自定义协议。
- Boot Protocol 很窄:它只覆盖简化键盘和鼠标,不能代表完整 HID report descriptor 能力。
- 复合设备要分清接口:一个 USB 设备可以同时有 HID、CDC、UVC 等多个接口,驱动绑定按 interface 发生。
- 端点方向不要混淆:IN/OUT 方向以主机视角命名,IN 是设备到主机,OUT 是主机到设备。
- 自定义 HID 仍需要主机应用协议:通用 HID 驱动负责搬运 report,不负责理解厂商业务命令。
- 描述符长度和实际返回必须一致:HID descriptor 中报告的 report descriptor length 写错,会导致主机读不全或解析失败。