User-Space EC Interface (cdev)

The surface_aggregator_cdev module provides a misc-device for the SSAM controller to allow for a (more or less) direct connection from user-space to the SAM EC. It is intended to be used for development and debugging, and therefore should not be used or relied upon in any other way. Note that this module is not loaded automatically, but instead must be loaded manually.

The provided interface is accessible through the /dev/surface/aggregator device-file. All functionality of this interface is provided via IOCTLs. These IOCTLs and their respective input/output parameter structs are defined in include/uapi/linux/surface_aggregator/cdev.h.

A small python library and scripts for accessing this interface can be found at https://github.com/linux-surface/surface-aggregator-module/tree/master/scripts/ssam.

Receiving Events

Events can be received by reading from the device-file. The are represented by the struct ssam_cdev_event datatype.

Before events are available to be read, however, the desired notifiers must be registered via the SSAM_CDEV_NOTIF_REGISTER IOCTL. Notifiers are, in essence, callbacks, called when the EC sends an event. They are, in this interface, associated with a specific target category and device-file-instance. They forward any event of this category to the buffer of the corresponding instance, from which it can then be read.

Notifiers themselves do not enable events on the EC. Thus, it may additionally be necessary to enable events via the SSAM_CDEV_EVENT_ENABLE IOCTL. While notifiers work per-client (i.e. per-device-file-instance), events are enabled globally, for the EC and all of its clients (regardless of userspace or non-userspace). The SSAM_CDEV_EVENT_ENABLE and SSAM_CDEV_EVENT_DISABLE IOCTLs take care of reference counting the events, such that an event is enabled as long as there is a client that has requested it.

Note that enabled events are not automatically disabled once the client instance is closed. Therefore any client process (or group of processes) should balance their event enable calls with the corresponding event disable calls. It is, however, perfectly valid to enable and disable events on different client instances. For example, it is valid to set up notifiers and read events on client instance A, enable those events on instance B (note that these will also be received by A since events are enabled/disabled globally), and after no more events are desired, disable the previously enabled events via instance C.

Controller IOCTLs

The following IOCTLs are provided:

Controller IOCTLs

Type

Number

Direction

Name

Description

0xA5

1

WR

REQUEST

Perform synchronous SAM request.

0xA5

2

W

NOTIF_REGISTER

Register event notifier.

0xA5

3

W

NOTIF_UNREGISTER

Unregister event notifier.

0xA5

4

W

EVENT_ENABLE

Enable event source.

0xA5

5

W

EVENT_DISABLE

Disable event source.

SSAM_CDEV_REQUEST

Defined as _IOWR(0xA5, 1, struct ssam_cdev_request).

Executes a synchronous SAM request. The request specification is passed in as argument of type struct ssam_cdev_request, which is then written to/modified by the IOCTL to return status and result of the request.

Request payload data must be allocated separately and is passed in via the payload.data and payload.length members. If a response is required, the response buffer must be allocated by the caller and passed in via the response.data member. The response.length member must be set to the capacity of this buffer, or if no response is required, zero. Upon completion of the request, the call will write the response to the response buffer (if its capacity allows it) and overwrite the length field with the actual size of the response, in bytes.

Additionally, if the request has a response, this must be indicated via the request flags, as is done with in-kernel requests. Request flags can be set via the flags member and the values correspond to the values found in enum ssam_cdev_request_flags.

Finally, the status of the request itself is returned in the status member (a negative errno value indicating failure). Note that failure indication of the IOCTL is separated from failure indication of the request: The IOCTL returns a negative status code if anything failed during setup of the request (-EFAULT) or if the provided argument or any of its fields are invalid (-EINVAL). In this case, the status value of the request argument may be set, providing more detail on what went wrong (e.g. -ENOMEM for out-of-memory), but this value may also be zero. The IOCTL will return with a zero status code in case the request has been set up, submitted, and completed (i.e. handed back to user-space) successfully from inside the IOCTL, but the request status member may still be negative in case the actual execution of the request failed after it has been submitted.

A full definition of the argument struct is provided below.

SSAM_CDEV_NOTIF_REGISTER

Defined as _IOW(0xA5, 2, struct ssam_cdev_notifier_desc).

Register a notifier for the event target category specified in the given notifier description with the specified priority. Notifiers registration is required to receive events, but does not enable events themselves. After a notifier for a specific target category has been registered, all events of that category will be forwarded to the userspace client and can then be read from the device file instance. Note that events may have to be enabled, e.g. via the SSAM_CDEV_EVENT_ENABLE IOCTL, before the EC will send them.

Only one notifier can be registered per target category and client instance. If a notifier has already been registered, this IOCTL will fail with -EEXIST.

Notifiers will automatically be removed when the device file instance is closed.

SSAM_CDEV_NOTIF_UNREGISTER

Defined as _IOW(0xA5, 3, struct ssam_cdev_notifier_desc).

Unregisters the notifier associated with the specified target category. The priority field will be ignored by this IOCTL. If no notifier has been registered for this client instance and the given category, this IOCTL will fail with -ENOENT.

SSAM_CDEV_EVENT_ENABLE

Defined as _IOW(0xA5, 4, struct ssam_cdev_event_desc).

Enable the event associated with the given event descriptor.

Note that this call will not register a notifier itself, it will only enable events on the controller. If you want to receive events by reading from the device file, you will need to register the corresponding notifier(s) on that instance.

Events are not automatically disabled when the device file is closed. This must be done manually, via a call to the SSAM_CDEV_EVENT_DISABLE IOCTL.

SSAM_CDEV_EVENT_DISABLE

Defined as _IOW(0xA5, 5, struct ssam_cdev_event_desc).

Disable the event associated with the given event descriptor.

Note that this will not unregister any notifiers. Events may still be received and forwarded to user-space after this call. The only safe way of stopping events from being received is unregistering all previously registered notifiers.

Structures and Enums

Error

kernel-doc missing