Back to home page

OSCL-LXR

 
 

    


0001 .. SPDX-License-Identifier: GPL-2.0+
0002 
0003 .. |ssam_controller| replace:: :c:type:`struct ssam_controller <ssam_controller>`
0004 .. |ssam_device| replace:: :c:type:`struct ssam_device <ssam_device>`
0005 .. |ssam_device_driver| replace:: :c:type:`struct ssam_device_driver <ssam_device_driver>`
0006 .. |ssam_client_bind| replace:: :c:func:`ssam_client_bind`
0007 .. |ssam_client_link| replace:: :c:func:`ssam_client_link`
0008 .. |ssam_get_controller| replace:: :c:func:`ssam_get_controller`
0009 .. |ssam_controller_get| replace:: :c:func:`ssam_controller_get`
0010 .. |ssam_controller_put| replace:: :c:func:`ssam_controller_put`
0011 .. |ssam_device_alloc| replace:: :c:func:`ssam_device_alloc`
0012 .. |ssam_device_add| replace:: :c:func:`ssam_device_add`
0013 .. |ssam_device_remove| replace:: :c:func:`ssam_device_remove`
0014 .. |ssam_device_driver_register| replace:: :c:func:`ssam_device_driver_register`
0015 .. |ssam_device_driver_unregister| replace:: :c:func:`ssam_device_driver_unregister`
0016 .. |module_ssam_device_driver| replace:: :c:func:`module_ssam_device_driver`
0017 .. |SSAM_DEVICE| replace:: :c:func:`SSAM_DEVICE`
0018 .. |ssam_notifier_register| replace:: :c:func:`ssam_notifier_register`
0019 .. |ssam_notifier_unregister| replace:: :c:func:`ssam_notifier_unregister`
0020 .. |ssam_device_notifier_register| replace:: :c:func:`ssam_device_notifier_register`
0021 .. |ssam_device_notifier_unregister| replace:: :c:func:`ssam_device_notifier_unregister`
0022 .. |ssam_request_sync| replace:: :c:func:`ssam_request_sync`
0023 .. |ssam_event_mask| replace:: :c:type:`enum ssam_event_mask <ssam_event_mask>`
0024 
0025 
0026 ======================
0027 Writing Client Drivers
0028 ======================
0029 
0030 For the API documentation, refer to:
0031 
0032 .. toctree::
0033    :maxdepth: 2
0034 
0035    client-api
0036 
0037 
0038 Overview
0039 ========
0040 
0041 Client drivers can be set up in two main ways, depending on how the
0042 corresponding device is made available to the system. We specifically
0043 differentiate between devices that are presented to the system via one of
0044 the conventional ways, e.g. as platform devices via ACPI, and devices that
0045 are non-discoverable and instead need to be explicitly provided by some
0046 other mechanism, as discussed further below.
0047 
0048 
0049 Non-SSAM Client Drivers
0050 =======================
0051 
0052 All communication with the SAM EC is handled via the |ssam_controller|
0053 representing that EC to the kernel. Drivers targeting a non-SSAM device (and
0054 thus not being a |ssam_device_driver|) need to explicitly establish a
0055 connection/relation to that controller. This can be done via the
0056 |ssam_client_bind| function. Said function returns a reference to the SSAM
0057 controller, but, more importantly, also establishes a device link between
0058 client device and controller (this can also be done separate via
0059 |ssam_client_link|). It is important to do this, as it, first, guarantees
0060 that the returned controller is valid for use in the client driver for as
0061 long as this driver is bound to its device, i.e. that the driver gets
0062 unbound before the controller ever becomes invalid, and, second, as it
0063 ensures correct suspend/resume ordering. This setup should be done in the
0064 driver's probe function, and may be used to defer probing in case the SSAM
0065 subsystem is not ready yet, for example:
0066 
0067 .. code-block:: c
0068 
0069    static int client_driver_probe(struct platform_device *pdev)
0070    {
0071            struct ssam_controller *ctrl;
0072 
0073            ctrl = ssam_client_bind(&pdev->dev);
0074            if (IS_ERR(ctrl))
0075                    return PTR_ERR(ctrl) == -ENODEV ? -EPROBE_DEFER : PTR_ERR(ctrl);
0076 
0077            // ...
0078 
0079            return 0;
0080    }
0081 
0082 The controller may be separately obtained via |ssam_get_controller| and its
0083 lifetime be guaranteed via |ssam_controller_get| and |ssam_controller_put|.
0084 Note that none of these functions, however, guarantee that the controller
0085 will not be shut down or suspended. These functions essentially only operate
0086 on the reference, i.e. only guarantee a bare minimum of accessibility
0087 without any guarantees at all on practical operability.
0088 
0089 
0090 Adding SSAM Devices
0091 ===================
0092 
0093 If a device does not already exist/is not already provided via conventional
0094 means, it should be provided as |ssam_device| via the SSAM client device
0095 hub. New devices can be added to this hub by entering their UID into the
0096 corresponding registry. SSAM devices can also be manually allocated via
0097 |ssam_device_alloc|, subsequently to which they have to be added via
0098 |ssam_device_add| and eventually removed via |ssam_device_remove|. By
0099 default, the parent of the device is set to the controller device provided
0100 for allocation, however this may be changed before the device is added. Note
0101 that, when changing the parent device, care must be taken to ensure that the
0102 controller lifetime and suspend/resume ordering guarantees, in the default
0103 setup provided through the parent-child relation, are preserved. If
0104 necessary, by use of |ssam_client_link| as is done for non-SSAM client
0105 drivers and described in more detail above.
0106 
0107 A client device must always be removed by the party which added the
0108 respective device before the controller shuts down. Such removal can be
0109 guaranteed by linking the driver providing the SSAM device to the controller
0110 via |ssam_client_link|, causing it to unbind before the controller driver
0111 unbinds. Client devices registered with the controller as parent are
0112 automatically removed when the controller shuts down, but this should not be
0113 relied upon, especially as this does not extend to client devices with a
0114 different parent.
0115 
0116 
0117 SSAM Client Drivers
0118 ===================
0119 
0120 SSAM client device drivers are, in essence, no different than other device
0121 driver types. They are represented via |ssam_device_driver| and bind to a
0122 |ssam_device| via its UID (:c:type:`struct ssam_device.uid <ssam_device>`)
0123 member and the match table
0124 (:c:type:`struct ssam_device_driver.match_table <ssam_device_driver>`),
0125 which should be set when declaring the driver struct instance. Refer to the
0126 |SSAM_DEVICE| macro documentation for more details on how to define members
0127 of the driver's match table.
0128 
0129 The UID for SSAM client devices consists of a ``domain``, a ``category``,
0130 a ``target``, an ``instance``, and a ``function``. The ``domain`` is used
0131 differentiate between physical SAM devices
0132 (:c:type:`SSAM_DOMAIN_SERIALHUB <ssam_device_domain>`), i.e. devices that can
0133 be accessed via the Surface Serial Hub, and virtual ones
0134 (:c:type:`SSAM_DOMAIN_VIRTUAL <ssam_device_domain>`), such as client-device
0135 hubs, that have no real representation on the SAM EC and are solely used on
0136 the kernel/driver-side. For physical devices, ``category`` represents the
0137 target category, ``target`` the target ID, and ``instance`` the instance ID
0138 used to access the physical SAM device. In addition, ``function`` references
0139 a specific device functionality, but has no meaning to the SAM EC. The
0140 (default) name of a client device is generated based on its UID.
0141 
0142 A driver instance can be registered via |ssam_device_driver_register| and
0143 unregistered via |ssam_device_driver_unregister|. For convenience, the
0144 |module_ssam_device_driver| macro may be used to define module init- and
0145 exit-functions registering the driver.
0146 
0147 The controller associated with a SSAM client device can be found in its
0148 :c:type:`struct ssam_device.ctrl <ssam_device>` member. This reference is
0149 guaranteed to be valid for at least as long as the client driver is bound,
0150 but should also be valid for as long as the client device exists. Note,
0151 however, that access outside of the bound client driver must ensure that the
0152 controller device is not suspended while making any requests or
0153 (un-)registering event notifiers (and thus should generally be avoided). This
0154 is guaranteed when the controller is accessed from inside the bound client
0155 driver.
0156 
0157 
0158 Making Synchronous Requests
0159 ===========================
0160 
0161 Synchronous requests are (currently) the main form of host-initiated
0162 communication with the EC. There are a couple of ways to define and execute
0163 such requests, however, most of them boil down to something similar as shown
0164 in the example below. This example defines a write-read request, meaning
0165 that the caller provides an argument to the SAM EC and receives a response.
0166 The caller needs to know the (maximum) length of the response payload and
0167 provide a buffer for it.
0168 
0169 Care must be taken to ensure that any command payload data passed to the SAM
0170 EC is provided in little-endian format and, similarly, any response payload
0171 data received from it is converted from little-endian to host endianness.
0172 
0173 .. code-block:: c
0174 
0175    int perform_request(struct ssam_controller *ctrl, u32 arg, u32 *ret)
0176    {
0177            struct ssam_request rqst;
0178            struct ssam_response resp;
0179            int status;
0180 
0181            /* Convert request argument to little-endian. */
0182            __le32 arg_le = cpu_to_le32(arg);
0183            __le32 ret_le = cpu_to_le32(0);
0184 
0185            /*
0186             * Initialize request specification. Replace this with your values.
0187             * The rqst.payload field may be NULL if rqst.length is zero,
0188             * indicating that the request does not have any argument.
0189             *
0190             * Note: The request parameters used here are not valid, i.e.
0191             *       they do not correspond to an actual SAM/EC request.
0192             */
0193            rqst.target_category = SSAM_SSH_TC_SAM;
0194            rqst.target_id = 0x01;
0195            rqst.command_id = 0x02;
0196            rqst.instance_id = 0x03;
0197            rqst.flags = SSAM_REQUEST_HAS_RESPONSE;
0198            rqst.length = sizeof(arg_le);
0199            rqst.payload = (u8 *)&arg_le;
0200 
0201            /* Initialize request response. */
0202            resp.capacity = sizeof(ret_le);
0203            resp.length = 0;
0204            resp.pointer = (u8 *)&ret_le;
0205 
0206            /*
0207             * Perform actual request. The response pointer may be null in case
0208             * the request does not have any response. This must be consistent
0209             * with the SSAM_REQUEST_HAS_RESPONSE flag set in the specification
0210             * above.
0211             */
0212            status = ssam_request_sync(ctrl, &rqst, &resp);
0213 
0214            /*
0215             * Alternatively use
0216             *
0217             *   ssam_request_sync_onstack(ctrl, &rqst, &resp, sizeof(arg_le));
0218             *
0219             * to perform the request, allocating the message buffer directly
0220             * on the stack as opposed to allocation via kzalloc().
0221             */
0222 
0223            /*
0224             * Convert request response back to native format. Note that in the
0225             * error case, this value is not touched by the SSAM core, i.e.
0226             * 'ret_le' will be zero as specified in its initialization.
0227             */
0228            *ret = le32_to_cpu(ret_le);
0229 
0230            return status;
0231    }
0232 
0233 Note that |ssam_request_sync| in its essence is a wrapper over lower-level
0234 request primitives, which may also be used to perform requests. Refer to its
0235 implementation and documentation for more details.
0236 
0237 An arguably more user-friendly way of defining such functions is by using
0238 one of the generator macros, for example via:
0239 
0240 .. code-block:: c
0241 
0242    SSAM_DEFINE_SYNC_REQUEST_W(__ssam_tmp_perf_mode_set, __le32, {
0243            .target_category = SSAM_SSH_TC_TMP,
0244            .target_id       = 0x01,
0245            .command_id      = 0x03,
0246            .instance_id     = 0x00,
0247    });
0248 
0249 This example defines a function
0250 
0251 .. code-block:: c
0252 
0253    static int __ssam_tmp_perf_mode_set(struct ssam_controller *ctrl, const __le32 *arg);
0254 
0255 executing the specified request, with the controller passed in when calling
0256 said function. In this example, the argument is provided via the ``arg``
0257 pointer. Note that the generated function allocates the message buffer on
0258 the stack. Thus, if the argument provided via the request is large, these
0259 kinds of macros should be avoided. Also note that, in contrast to the
0260 previous non-macro example, this function does not do any endianness
0261 conversion, which has to be handled by the caller. Apart from those
0262 differences the function generated by the macro is similar to the one
0263 provided in the non-macro example above.
0264 
0265 The full list of such function-generating macros is
0266 
0267 - :c:func:`SSAM_DEFINE_SYNC_REQUEST_N` for requests without return value and
0268   without argument.
0269 - :c:func:`SSAM_DEFINE_SYNC_REQUEST_R` for requests with return value but no
0270   argument.
0271 - :c:func:`SSAM_DEFINE_SYNC_REQUEST_W` for requests without return value but
0272   with argument.
0273 
0274 Refer to their respective documentation for more details. For each one of
0275 these macros, a special variant is provided, which targets request types
0276 applicable to multiple instances of the same device type:
0277 
0278 - :c:func:`SSAM_DEFINE_SYNC_REQUEST_MD_N`
0279 - :c:func:`SSAM_DEFINE_SYNC_REQUEST_MD_R`
0280 - :c:func:`SSAM_DEFINE_SYNC_REQUEST_MD_W`
0281 
0282 The difference of those macros to the previously mentioned versions is, that
0283 the device target and instance IDs are not fixed for the generated function,
0284 but instead have to be provided by the caller of said function.
0285 
0286 Additionally, variants for direct use with client devices, i.e.
0287 |ssam_device|, are also provided. These can, for example, be used as
0288 follows:
0289 
0290 .. code-block:: c
0291 
0292    SSAM_DEFINE_SYNC_REQUEST_CL_R(ssam_bat_get_sta, __le32, {
0293            .target_category = SSAM_SSH_TC_BAT,
0294            .command_id      = 0x01,
0295    });
0296 
0297 This invocation of the macro defines a function
0298 
0299 .. code-block:: c
0300 
0301    static int ssam_bat_get_sta(struct ssam_device *sdev, __le32 *ret);
0302 
0303 executing the specified request, using the device IDs and controller given
0304 in the client device. The full list of such macros for client devices is:
0305 
0306 - :c:func:`SSAM_DEFINE_SYNC_REQUEST_CL_N`
0307 - :c:func:`SSAM_DEFINE_SYNC_REQUEST_CL_R`
0308 - :c:func:`SSAM_DEFINE_SYNC_REQUEST_CL_W`
0309 
0310 
0311 Handling Events
0312 ===============
0313 
0314 To receive events from the SAM EC, an event notifier must be registered for
0315 the desired event via |ssam_notifier_register|. The notifier must be
0316 unregistered via |ssam_notifier_unregister| once it is not required any
0317 more. For |ssam_device| type clients, the |ssam_device_notifier_register| and
0318 |ssam_device_notifier_unregister| wrappers should be preferred as they properly
0319 handle hot-removal of client devices.
0320 
0321 Event notifiers are registered by providing (at minimum) a callback to call
0322 in case an event has been received, the registry specifying how the event
0323 should be enabled, an event ID specifying for which target category and,
0324 optionally and depending on the registry used, for which instance ID events
0325 should be enabled, and finally, flags describing how the EC will send these
0326 events. If the specific registry does not enable events by instance ID, the
0327 instance ID must be set to zero. Additionally, a priority for the respective
0328 notifier may be specified, which determines its order in relation to any
0329 other notifier registered for the same target category.
0330 
0331 By default, event notifiers will receive all events for the specific target
0332 category, regardless of the instance ID specified when registering the
0333 notifier. The core may be instructed to only call a notifier if the target
0334 ID or instance ID (or both) of the event match the ones implied by the
0335 notifier IDs (in case of target ID, the target ID of the registry), by
0336 providing an event mask (see |ssam_event_mask|).
0337 
0338 In general, the target ID of the registry is also the target ID of the
0339 enabled event (with the notable exception being keyboard input events on the
0340 Surface Laptop 1 and 2, which are enabled via a registry with target ID 1,
0341 but provide events with target ID 2).
0342 
0343 A full example for registering an event notifier and handling received
0344 events is provided below:
0345 
0346 .. code-block:: c
0347 
0348    u32 notifier_callback(struct ssam_event_notifier *nf,
0349                          const struct ssam_event *event)
0350    {
0351            int status = ...
0352 
0353            /* Handle the event here ... */
0354 
0355            /* Convert return value and indicate that we handled the event. */
0356            return ssam_notifier_from_errno(status) | SSAM_NOTIF_HANDLED;
0357    }
0358 
0359    int setup_notifier(struct ssam_device *sdev,
0360                       struct ssam_event_notifier *nf)
0361    {
0362            /* Set priority wrt. other handlers of same target category. */
0363            nf->base.priority = 1;
0364 
0365            /* Set event/notifier callback. */
0366            nf->base.fn = notifier_callback;
0367 
0368            /* Specify event registry, i.e. how events get enabled/disabled. */
0369            nf->event.reg = SSAM_EVENT_REGISTRY_KIP;
0370 
0371            /* Specify which event to enable/disable */
0372            nf->event.id.target_category = sdev->uid.category;
0373            nf->event.id.instance = sdev->uid.instance;
0374 
0375            /*
0376             * Specify for which events the notifier callback gets executed.
0377             * This essentially tells the core if it can skip notifiers that
0378             * don't have target or instance IDs matching those of the event.
0379             */
0380            nf->event.mask = SSAM_EVENT_MASK_STRICT;
0381 
0382            /* Specify event flags. */
0383            nf->event.flags = SSAM_EVENT_SEQUENCED;
0384 
0385            return ssam_notifier_register(sdev->ctrl, nf);
0386    }
0387 
0388 Multiple event notifiers can be registered for the same event. The event
0389 handler core takes care of enabling and disabling events when notifiers are
0390 registered and unregistered, by keeping track of how many notifiers for a
0391 specific event (combination of registry, event target category, and event
0392 instance ID) are currently registered. This means that a specific event will
0393 be enabled when the first notifier for it is being registered and disabled
0394 when the last notifier for it is being unregistered. Note that the event
0395 flags are therefore only used on the first registered notifier, however, one
0396 should take care that notifiers for a specific event are always registered
0397 with the same flag and it is considered a bug to do otherwise.