人机接口设备的维护和使用¶
简介¶
除了通常的输入类型 HID 设备外,USB 还将人机接口协议用于那些实际上不是人机接口,但具有类似通信需求的事物。 这方面的两个主要例子是电源设备(尤其是 不间断电源)和高端显示器上的显示器控制。
为了支持这些不同的需求,Linux USB 系统向两个单独的接口提供 HID 事件:* 输入子系统,它将 HID 事件转换为普通的输入设备接口(例如键盘、鼠标和操纵杆)以及一个规范化的事件接口 - 请参阅 简介 * hiddev 接口,它提供相当原始的 HID 事件
设备生成的 HID 事件的数据流如下所示
usb.c ---> hid-core.c ----> hid-input.c ----> [keyboard/mouse/joystick/event]
|
|
--> hiddev.c ----> POWER / MONITOR CONTROL
此外,其他子系统(除了 USB)也可以将事件馈送到输入子系统,但这些对 HID 设备接口没有影响。
使用 HID 设备接口¶
hiddev 接口是一个字符接口,使用普通的 USB 主设备号,次设备号从 96 开始,到 111 结束。因此,您需要以下命令
mknod /dev/usb/hiddev0 c 180 96
mknod /dev/usb/hiddev1 c 180 97
mknod /dev/usb/hiddev2 c 180 98
mknod /dev/usb/hiddev3 c 180 99
mknod /dev/usb/hiddev4 c 180 100
mknod /dev/usb/hiddev5 c 180 101
mknod /dev/usb/hiddev6 c 180 102
mknod /dev/usb/hiddev7 c 180 103
mknod /dev/usb/hiddev8 c 180 104
mknod /dev/usb/hiddev9 c 180 105
mknod /dev/usb/hiddev10 c 180 106
mknod /dev/usb/hiddev11 c 180 107
mknod /dev/usb/hiddev12 c 180 108
mknod /dev/usb/hiddev13 c 180 109
mknod /dev/usb/hiddev14 c 180 110
mknod /dev/usb/hiddev15 c 180 111
因此,您将 hiddev 兼容的用户空间程序指向您设备的正确接口,一切正常。
当然,前提是您有一个 hiddev 兼容的用户空间程序。 如果您需要编写一个,请继续阅读。
HIDDEV API¶
该描述应与 HID 规范结合阅读,该规范可从 https://www.usb.org 免费获取,并方便地链接到 http://www.linux-usb.org。
hiddev API 使用 read() 接口和一组 ioctl() 调用。
HID 设备使用称为“报告”的数据包与主机计算机交换数据。 每个报告都分为“字段”,每个字段可以有一个或多个“用途”。 在 hid-core 中,每个用途都有一个带符号的 32 位值。
read():¶
这是事件接口。当 HID 设备的状态发生变化时,它会执行一个中断传输,其中包含一个包含更改值的报告。 hid-core.c 模块解析该报告,并将报告中已更改的单个用途返回给 hiddev.c。 在其基本模式下,hiddev 将使用 struct hiddev_event 将这些单个用途更改提供给读取器
struct hiddev_event {
unsigned hid;
signed int value;
};
其中包含已更改状态的 HID 用途标识符以及更改后的值。 请注意,该结构在 <linux/hiddev.h> 中定义,以及其他一些有用的 #defines 和结构。 HID 用途标识符是将 HID 用途页面移至高 16 位,或与用途代码进行或运算的组合。 read() 函数的行为可以使用下面描述的 HIDIOCSFLAG ioctl() 进行修改。
ioctl():¶
这是控制接口。 有一些控制
- HIDIOCGVERSION
int (read)
从 hiddev 驱动程序中获取版本代码。
- HIDIOCAPPLICATION
(none)
此 ioctl 调用返回与 HID 设备关联的 HID 应用程序用途。 ioctl() 的第三个参数指定要获取哪个应用程序索引。 当设备有多个应用程序集合时,这很有用。 如果索引无效(大于或等于此设备拥有的应用程序集合的数量),则 ioctl 返回 -1。 您可以事先从 hiddev_devinfo 结构中的 num_applications 字段中找出设备有多少个应用程序集合。
- HIDIOCGCOLLECTIONINFO
struct hiddev_collection_info (read/write)
这返回了上述信息的超集,不仅提供应用程序集合,还提供设备拥有的所有集合。 它还返回集合在层次结构中所处的级别。 用户传入一个 hiddev_collection_info 结构,其索引字段设置为应返回的索引。 ioctl 填写其他字段。 如果索引大于最后一个集合索引,则 ioctl 返回 -1 并将 errno 设置为 -EINVAL。
- HIDIOCGDEVINFO
struct hiddev_devinfo (read)
获取描述设备的 hiddev_devinfo 结构。
- HIDIOCGSTRING
struct hiddev_string_descriptor (read/write)
从设备获取字符串描述符。 调用者必须填写“index”字段以指示应返回哪个描述符。
- HIDIOCINITREPORT
(none)
指示内核从设备检索所有输入和功能报告值。 此时,所有用途结构都将包含设备的当前值,并在设备发生更改时保持这些值。 请注意,通常不需要使用此 ioctl,因为后来的内核会在附加时自动初始化设备中的报告。
- HIDIOCGNAME
string (可变长度)
获取设备名称
- HIDIOCGREPORT
struct hiddev_report_info (write)
指示内核从设备获取功能或输入报告,以便有选择地更新用途结构(与 INITREPORT 相反)。
- HIDIOCSREPORT
struct hiddev_report_info (write)
指示内核将报告发送到设备。 用户可以通过 HIDIOCSUSAGE 调用(如下所述)来填充此报告,以在将报告完整发送到设备之前填充报告中的各个用途值。
- HIDIOCGREPORTINFO
struct hiddev_report_info (read/write)
为用户填写 hiddev_report_info 结构。 该报告按类型(输入、输出或功能)和 ID 查找,因此用户必须填写这些字段。 ID 可以是绝对的——设备报告的实际报告 ID——也可以是相对的——第一个报告的 HID_REPORT_ID_FIRST 和 report_id 之后的下一个报告的 (HID_REPORT_ID_NEXT | report_id)。 如果没有关于报告 ID 的先验信息,使用此 ioctl 的正确方法是使用上面的相对 ID 来枚举有效的 ID。 当没有下一个 ID 时,ioctl 返回非零值。 实际的报告 ID 会填充到返回的 hiddev_report_info 结构中。
- HIDIOCGFIELDINFO
struct hiddev_field_info (read/write)
以 hiddev_field_info 结构返回与报告关联的字段信息。 用户必须如上所述在此结构中填写 report_id 和 report_type。 还应填写 field_index,它应该是一个从 0 到 maxfield-1 的数字,如之前的 HIDIOCGREPORTINFO 调用返回的那样。
- HIDIOCGUCODE
struct hiddev_usage_ref (read/write)
返回 hiddev_usage_ref 结构中的 usage_code,前提是其报告类型、报告 ID、字段索引和字段内的索引已填写到结构中。
- HIDIOCGUSAGE
struct hiddev_usage_ref (read/write)
返回 hiddev_usage_ref 结构中用途的值。 要检索的用途可以如上所述指定,或者用户可以选择填写 report_type 字段并将 report_id 指定为 HID_REPORT_ID_UNKNOWN。 在这种情况下,如果找到该用途,则 hiddev_usage_ref 将填充与此用途关联的报告和字段信息。
- HIDIOCSUSAGE
struct hiddev_usage_ref (write)
设置输出报告中用途的值。 用户如上所述填写 hiddev_usage_ref 结构,但另外填写 value 字段。
- HIDIOGCOLLECTIONINDEX
struct hiddev_usage_ref (write)
返回与此用途关联的集合索引。 这表示该用途在集合层次结构中的位置。
- HIDIOCGFLAG
int (read)
- HIDIOCSFLAG
int (write)
这些操作分别检查和替换影响上述 read() 调用的模式标志。 这些标志如下
- HIDDEV_FLAG_UREF
read() 调用现在将返回 struct hiddev_usage_ref 而不是 struct hiddev_event。 这是一个更大的结构,但在设备在报告中具有多个具有相同用途代码的用途的情况下,此模式用于消除此类歧义。
- HIDDEV_FLAG_REPORT
此标志只能与 HIDDEV_FLAG_UREF 结合使用。 设置此标志后,当设备发送报告时,将向 read() 返回一个 struct hiddev_usage_ref,其中填充了 report_type 和 report_id,但 field_index 设置为 FIELD_INDEX_NONE。 当设备发送报告时,这可以作为额外的通知。