用户空间 EC 接口 (cdev)¶
surface_aggregator_cdev
模块为 SSAM 控制器提供了一个 misc 设备,允许用户空间与 SAM EC 进行(或多或少)直接连接。它旨在用于开发和调试,因此不应以任何其他方式使用或依赖。请注意,此模块不会自动加载,而是必须手动加载。
提供的接口可通过 /dev/surface/aggregator
设备文件访问。此接口的所有功能都通过 IOCTL 提供。这些 IOCTL 及其各自的输入/输出参数结构在 include/uapi/linux/surface_aggregator/cdev.h
中定义。
访问此接口的小型 Python 库和脚本可以在 https://github.com/linux-surface/surface-aggregator-module/tree/master/scripts/ssam 中找到。
接收事件¶
可以通过读取设备文件来接收事件。它们由 struct ssam_cdev_event
数据类型表示。
但是,在可以读取事件之前,必须通过 SSAM_CDEV_NOTIF_REGISTER
IOCTL 注册所需的通知器。本质上,通知器是在 EC 发送事件时调用的回调。在此接口中,它们与特定的目标类别和设备文件实例关联。它们将此类别的任何事件转发到相应实例的缓冲区,然后可以从中读取。
通知器本身不会在 EC 上启用事件。因此,可能还需要通过 SSAM_CDEV_EVENT_ENABLE
IOCTL 启用事件。虽然通知器按客户端工作(即按设备文件实例工作),但事件是全局启用的,适用于 EC 及其所有客户端(无论用户空间还是非用户空间)。SSAM_CDEV_EVENT_ENABLE
和 SSAM_CDEV_EVENT_DISABLE
IOCTL 负责事件的引用计数,以便只要有客户端请求事件,该事件就会被启用。
请注意,一旦客户端实例关闭,已启用的事件不会自动禁用。因此,任何客户端进程(或进程组)都应平衡其事件启用调用与相应的事件禁用调用。但是,在不同的客户端实例上启用和禁用事件是完全有效的。例如,在客户端实例 A
上设置通知器并读取事件,在实例 B
上启用这些事件(请注意,由于事件是全局启用/禁用的,因此 A 也会收到这些事件),并且在不再需要事件后,通过实例 C
禁用先前启用的事件是有效的。
控制器 IOCTL¶
提供以下 IOCTL
类型 |
编号 |
方向 |
名称 |
描述 |
---|---|---|---|---|
|
|
|
|
执行同步 SAM 请求。 |
|
|
|
|
注册事件通知器。 |
|
|
|
|
取消注册事件通知器。 |
|
|
|
|
启用事件源。 |
|
|
|
|
禁用事件源。 |
SSAM_CDEV_REQUEST
¶
定义为 _IOWR(0xA5, 1, struct ssam_cdev_request)
。
执行同步 SAM 请求。请求规范作为 struct ssam_cdev_request
类型的参数传入,然后由 IOCTL 写入/修改以返回请求的状态和结果。
请求负载数据必须单独分配,并通过 payload.data
和 payload.length
成员传入。如果需要响应,则响应缓冲区必须由调用者分配,并通过 response.data
成员传入。response.length
成员必须设置为此缓冲区的容量,如果不需要响应,则设置为零。请求完成后,调用会将响应写入响应缓冲区(如果其容量允许),并使用响应的实际大小(以字节为单位)覆盖长度字段。
此外,如果请求有响应,则必须通过请求标志来指示,就像内核请求一样。可以通过 flags
成员设置请求标志,值对应于 enum ssam_cdev_request_flags
中的值。
最后,请求本身的状态在 status
成员中返回(负 errno 值表示失败)。请注意,IOCTL 的失败指示与请求的失败指示是分开的:如果请求设置期间出现任何失败 (-EFAULT
) 或者如果提供的参数或其任何字段无效 (-EINVAL
),则 IOCTL 返回负状态代码。在这种情况下,可以设置请求参数的状态值,提供有关出错原因的更多详细信息(例如,内存不足的 -ENOMEM
),但此值也可以为零。如果请求已在 IOCTL 内部成功设置、提交和完成(即返回到用户空间),则 IOCTL 将返回零状态代码,但如果请求的实际执行在提交后失败,则请求 status
成员可能仍为负值。
下面提供了参数结构的完整定义。
SSAM_CDEV_NOTIF_REGISTER
¶
定义为 _IOW(0xA5, 2, struct ssam_cdev_notifier_desc)
。
使用指定的优先级为给定通知器描述中指定的事件目标类别注册一个通知器。接收事件需要注册通知器,但这不会启用事件本身。在为特定目标类别注册通知器后,该类别的所有事件都将转发给用户空间客户端,然后可以从设备文件实例中读取。请注意,可能需要启用事件,例如通过 SSAM_CDEV_EVENT_ENABLE
IOCTL,然后EC才会发送它们。
每个目标类别和客户端实例只能注册一个通知器。如果已注册通知器,则此 IOCTL 将失败并返回 -EEXIST
。
当设备文件实例关闭时,通知器将自动被删除。
SSAM_CDEV_NOTIF_UNREGISTER
¶
定义为 _IOW(0xA5, 3, struct ssam_cdev_notifier_desc)
。
取消注册与指定目标类别关联的通知器。此 IOCTL 将忽略优先级字段。如果未为此客户端实例和给定类别注册任何通知器,则此 IOCTL 将失败并返回 -ENOENT
。
SSAM_CDEV_EVENT_ENABLE
¶
定义为 _IOW(0xA5, 4, struct ssam_cdev_event_desc)
。
启用与给定事件描述符关联的事件。
请注意,此调用本身不会注册通知器,它只会启用控制器上的事件。如果要通过读取设备文件来接收事件,则需要在该实例上注册相应的通知器。
当设备文件关闭时,事件不会自动禁用。必须通过调用 SSAM_CDEV_EVENT_DISABLE
IOCTL 手动完成此操作。
SSAM_CDEV_EVENT_DISABLE
¶
定义为 _IOW(0xA5, 5, struct ssam_cdev_event_desc)
。
禁用与给定事件描述符关联的事件。
请注意,这不会取消注册任何通知器。在此调用之后,仍可能接收到事件并将其转发到用户空间。停止接收事件的唯一安全方法是取消注册所有先前注册的通知器。
结构体和枚举¶
-
enum ssam_cdev_request_flags¶
SSAM cdev 请求 IOCTL 的请求标志。
常量
SSAM_CDEV_REQUEST_HAS_RESPONSE
指定请求期望收到响应。如果未设置,则在传输完底层数据包后将直接完成请求。如果设置,则请求传输系统会等待请求的响应。
SSAM_CDEV_REQUEST_UNSEQUENCED
指定应通过无序数据包传输请求。如果设置,则请求不得有响应,这意味着此标志和
SSAM_CDEV_REQUEST_HAS_RESPONSE
标志是互斥的。
-
struct ssam_cdev_request¶
控制器请求 IOCTL 参数。
定义:
struct ssam_cdev_request {
__u8 target_category;
__u8 target_id;
__u8 command_id;
__u8 instance_id;
__u16 flags;
__s16 status;
struct {
__u64 data;
__u16 length;
__u8 __pad[6];
} payload;
struct {
__u64 data;
__u16 length;
__u8 __pad[6];
} response;
};
成员
target_category
SAM 请求的目标类别。
target_id
SAM 请求的目标 ID。
command_id
SAM 请求的命令 ID。
instance_id
SAM 请求的实例 ID。
flags
请求标志(请参见
enum ssam_cdev_request_flags
)。status
请求状态(输出)。
payload
请求有效负载(输入数据)。
payload.data
指向请求有效负载数据的指针。
payload.length
请求有效负载数据的长度(以字节为单位)。
response
请求响应(输出数据)。
response.data
指向响应缓冲区的指针。
response.length
输入时:响应缓冲区的容量(以字节为单位)。输出时:请求响应的长度(缓冲区中实际使用的字节数)。
-
struct ssam_cdev_notifier_desc¶
通知器描述符。
定义:
struct ssam_cdev_notifier_desc {
__s32 priority;
__u8 target_category;
};
成员
priority
确定调用通知器回调顺序的优先级值。值越高表示优先级越高,即关联的回调将比其他(较低优先级)回调更早执行。
target_category
此通知器应接收事件的事件目标类别。
描述
指定应注册或取消注册的通知器,特别是其优先级和事件的目标类别。
-
struct ssam_cdev_event_desc¶
事件描述符。
定义:
struct ssam_cdev_event_desc {
struct {
__u8 target_category;
__u8 target_id;
__u8 cid_enable;
__u8 cid_disable;
} reg;
struct {
__u8 target_category;
__u8 instance;
} id;
__u8 flags;
};
成员
reg
将通过其启用/禁用事件的注册表。
reg.target_category
事件注册表请求的目标类别。
reg.target_id
事件注册表请求的目标 ID。
reg.cid_enable
事件启用请求的命令 ID。
reg.cid_disable
事件禁用请求的命令 ID。
id
指定事件的 ID。
id.target_category
事件源的目标类别。
id.instance
事件源的实例 ID。
flags
用于启用事件的标志。
描述
指定应启用/禁用哪个事件以及如何执行此操作。
-
struct ssam_cdev_event¶
EC 发送的 SSAM 事件。
定义:
struct ssam_cdev_event {
__u8 target_category;
__u8 target_id;
__u8 command_id;
__u8 instance_id;
__u16 length;
__u8 data[];
};
成员
target_category
事件源的目标类别。请参见
enum ssam_ssh_tc
。target_id
事件源的目标 ID。
command_id
事件的命令 ID。
instance_id
事件源的实例 ID。
length
事件有效负载的长度(以字节为单位)。
data
事件有效负载数据。