HID 传感器框架

HID 传感器框架提供了必要的接口来实现连接到传感器集线器的传感器驱动程序。 传感器集线器是一个 HID 设备,它提供符合 HID 1.12 传感器使用表的报告描述符。

HID 1.12 “HID 传感器使用”规范中的描述:“传感器 HID 使用的标准化将允许(但不要求)传感器硬件供应商在 USB 边界提供一致的即插即用接口,从而使一些操作系统能够合并可以在供应商之间重用的通用设备驱动程序,从而减轻供应商自己提供驱动程序的任何需要。”

该规范描述了许多使用 ID,这些 ID 描述了传感器类型以及各个数据字段。 每个传感器可以有可变数量的数据字段。 长度和顺序在报告描述符中指定。 例如,报告描述符的一部分可能如下所示

   INPUT(1)[INPUT]
 ..
    Field(2)
      Physical(0020.0073)
      Usage(1)
        0020.045f
      Logical Minimum(-32767)
      Logical Maximum(32767)
      Report Size(8)
      Report Count(1)
      Report Offset(16)
      Flags(Variable Absolute)
..
..

该报告指示“传感器页面(0x20)”包含一个 3D 加速计(0x73)。 这个 3D 加速计有一些字段。 例如,这里字段 2 是运动强度 (0x045f),逻辑最小值为 -32767,逻辑最大值为 32767。 字段的顺序和每个字段的长度非常重要,因为输入事件原始数据将使用这种格式。

实现

该规范定义了许多不同类型的传感器,具有不同的数据集。 对于不同的传感器,很难为用户空间应用程序提供通用的输入事件。 例如,加速度计可以发送 X、Y 和 Z 数据,而环境光传感器可以发送照度数据。 因此,该实现包含两个部分

  • 核心 HID 驱动程序

  • 单个传感器处理部分(传感器驱动程序)

核心驱动程序

核心驱动程序 (hid-sensor-hub) 注册为 HID 驱动程序。 它解析报告描述符并识别所有存在的传感器。 它添加了一个名称为 HID-SENSOR-xxxx 的 MFD 设备(其中 xxxx 是规范中的使用 ID)。

例如

HID-SENSOR-200073 已注册到 3D 加速度计驱动程序。

因此,如果插入任何具有此名称的驱动程序,则将调用该函数的探测例程。 因此,加速度计处理驱动程序可以使用此名称注册,并且如果检测到 3D 加速度计,将被探测。

核心驱动程序提供了一组 API,处理驱动程序可以使用这些 API 来注册并获取该使用 ID 的事件。 它还提供了解析函数,可以获取和设置每个输入/功能/输出报告。

单个传感器处理部分(传感器驱动程序)

处理驱动程序将使用核心驱动程序提供的接口来解析报告并获取字段索引,还可以获取事件。 该驱动程序可以使用 IIO 接口来使用为传感器类型定义的标准 ABI。

核心驱动程序接口

回调结构

Each processing driver can use this structure to set some callbacks.
      int (*suspend)(..): Callback when HID suspend is received
      int (*resume)(..): Callback when HID resume is received
      int (*capture_sample)(..): Capture a sample for one of its data fields
      int (*send_event)(..): One complete event is received which can have
                             multiple data fields.

注册函数

int sensor_hub_register_callback(struct hid_sensor_hub_device *hsdev,
                      u32 usage_id,
                      struct hid_sensor_hub_callbacks *usage_callback):

为使用 ID 注册回调。 不允许回调函数休眠

int sensor_hub_remove_callback(struct hid_sensor_hub_device *hsdev,
                      u32 usage_id):

删除使用 ID 的回调。

解析函数

int sensor_hub_input_get_attribute_info(struct hid_sensor_hub_device *hsdev,
                      u8 type,
                      u32 usage_id, u32 attr_usage_id,
                      struct hid_sensor_hub_attribute_info *info);

处理驱动程序可以查找一些感兴趣的字段,并检查它是否存在于报告描述符中。 如果存在,它将存储必要的信息,以便可以单独设置或获取字段。 这些索引避免了每次搜索和获取字段索引来获取或设置。

设置功能报告

int sensor_hub_set_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
                      u32 field_index, s32 value);

此接口用于设置功能报告中字段的值。 例如,如果有一个 report_interval 字段,之前通过调用 sensor_hub_input_get_attribute_info 进行了解析,那么它可以直接设置该单个字段

int sensor_hub_get_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
                      u32 field_index, s32 *value);

此接口用于获取输入报告中字段的值。 例如,如果有一个 report_interval 字段,之前通过调用 sensor_hub_input_get_attribute_info 进行了解析,那么它可以直接获取该单个字段值

int sensor_hub_input_attr_get_raw_value(struct hid_sensor_hub_device *hsdev,
                      u32 usage_id,
                      u32 attr_usage_id, u32 report_id);

这用于通过输入报告获取特定字段值。 例如,加速度计想要轮询 X 轴值,那么它可以调用此函数并使用 X 轴的使用 ID。 HID 传感器可以提供事件,因此无需轮询任何字段。 如果有任何新样本,核心驱动程序将调用注册的回调函数来处理该样本。


HID 自定义和通用传感器

HID 传感器规范定义了两种特殊的传感器使用类型。 由于它们不代表标准传感器,因此无法使用 Linux IIO 类型接口进行定义。 这些传感器的目的是扩展功能或提供一种混淆传感器正在通信的数据的方法。 在不知道数据与其封装形式之间的映射的情况下,应用程序/驱动程序很难确定传感器正在通信的数据。 这允许一些差异化的用例,其中供应商可以提供应用程序。 一些常见的用例是调试其他传感器或提供一些事件,例如键盘连接/断开或盖子打开/关闭。

为了允许应用程序利用这些传感器,这里它们使用 sysfs 属性组、属性和 misc 设备接口导出。

sysfs 上这种表示形式的示例

/sys/devices/pci0000:00/INT33C2:00/i2c-0/i2c-INT33D1:00/0018:8086:09FA.0001/HID-SENSOR-2000e1.6.auto$ tree -R
.
│   ├──  enable_sensor
│   │   ├── feature-0-200316
│   │   │   ├── feature-0-200316-maximum
│   │   │   ├── feature-0-200316-minimum
│   │   │   ├── feature-0-200316-name
│   │   │   ├── feature-0-200316-size
│   │   │   ├── feature-0-200316-unit-expo
│   │   │   ├── feature-0-200316-units
│   │   │   ├── feature-0-200316-value
│   │   ├── feature-1-200201
│   │   │   ├── feature-1-200201-maximum
│   │   │   ├── feature-1-200201-minimum
│   │   │   ├── feature-1-200201-name
│   │   │   ├── feature-1-200201-size
│   │   │   ├── feature-1-200201-unit-expo
│   │   │   ├── feature-1-200201-units
│   │   │   ├── feature-1-200201-value
│   │   ├── input-0-200201
│   │   │   ├── input-0-200201-maximum
│   │   │   ├── input-0-200201-minimum
│   │   │   ├── input-0-200201-name
│   │   │   ├── input-0-200201-size
│   │   │   ├── input-0-200201-unit-expo
│   │   │   ├── input-0-200201-units
│   │   │   ├── input-0-200201-value
│   │   ├── input-1-200202
│   │   │   ├── input-1-200202-maximum
│   │   │   ├── input-1-200202-minimum
│   │   │   ├── input-1-200202-name
│   │   │   ├── input-1-200202-size
│   │   │   ├── input-1-200202-unit-expo
│   │   │   ├── input-1-200202-units
│   │   │   ├── input-1-200202-value

这里有一个自定义传感器,有四个字段:两个功能和两个输入。 每个字段由一组属性表示。 除了“value”之外的所有字段都是只读的。 value 字段是一个读写字段。

示例

/sys/bus/platform/devices/HID-SENSOR-2000e1.6.auto/feature-0-200316$ grep -r . *
feature-0-200316-maximum:6
feature-0-200316-minimum:0
feature-0-200316-name:property-reporting-state
feature-0-200316-size:1
feature-0-200316-unit-expo:0
feature-0-200316-units:25
feature-0-200316-value:1

如何启用此类传感器?

默认情况下,传感器可以断电。 要启用,可以使用 sysfs 属性“enable”

$ echo 1 > enable_sensor

一旦启用并通电,传感器可以使用 HID 报告报告值。 这些报告使用 FIFO 顺序通过 misc 设备接口推送。

/dev$ tree | grep HID-SENSOR-2000e1.6.auto
│   │   │   ├── 10:53 -> ../HID-SENSOR-2000e1.6.auto
│   ├──  HID-SENSOR-2000e1.6.auto

每个报告的长度可以是可变的,前面是报头。 该报头包含一个 32 位的使用 ID、一个 64 位的时间戳和一个 32 位的原始数据长度字段。