| .. SPDX-License-Identifier: GPL-2.0+ | |
| .. |ssam_cdev_request| replace:: :c:type:`struct ssam_cdev_request <ssam_cdev_request>` | |
| .. |ssam_cdev_request_flags| replace:: :c:type:`enum ssam_cdev_request_flags <ssam_cdev_request_flags>` | |
| .. |ssam_cdev_event| replace:: :c:type:`struct ssam_cdev_event <ssam_cdev_event>` | |
| ============================== | |
| 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. | |
| .. contents:: | |
| Receiving Events | |
| ================ | |
| Events can be received by reading from the device-file. The are represented by | |
| the |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: | |
| .. flat-table:: Controller IOCTLs | |
| :widths: 1 1 1 1 4 | |
| :header-rows: 1 | |
| * - 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 |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 | |
| |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 | |
| ==================== | |
| .. kernel-doc:: include/uapi/linux/surface_aggregator/cdev.h |