xref: /openbmc/linux/Documentation/driver-api/surface_aggregator/client.rst (revision 9a87ffc99ec8eb8d35eed7c4f816d75f5cc9662e)
18d779282SMaximilian Luz.. SPDX-License-Identifier: GPL-2.0+
28d779282SMaximilian Luz
38d779282SMaximilian Luz.. |ssam_controller| replace:: :c:type:`struct ssam_controller <ssam_controller>`
48d779282SMaximilian Luz.. |ssam_device| replace:: :c:type:`struct ssam_device <ssam_device>`
58d779282SMaximilian Luz.. |ssam_device_driver| replace:: :c:type:`struct ssam_device_driver <ssam_device_driver>`
68d779282SMaximilian Luz.. |ssam_client_bind| replace:: :c:func:`ssam_client_bind`
78d779282SMaximilian Luz.. |ssam_client_link| replace:: :c:func:`ssam_client_link`
88d779282SMaximilian Luz.. |ssam_get_controller| replace:: :c:func:`ssam_get_controller`
98d779282SMaximilian Luz.. |ssam_controller_get| replace:: :c:func:`ssam_controller_get`
108d779282SMaximilian Luz.. |ssam_controller_put| replace:: :c:func:`ssam_controller_put`
118d779282SMaximilian Luz.. |ssam_device_alloc| replace:: :c:func:`ssam_device_alloc`
128d779282SMaximilian Luz.. |ssam_device_add| replace:: :c:func:`ssam_device_add`
138d779282SMaximilian Luz.. |ssam_device_remove| replace:: :c:func:`ssam_device_remove`
148d779282SMaximilian Luz.. |ssam_device_driver_register| replace:: :c:func:`ssam_device_driver_register`
158d779282SMaximilian Luz.. |ssam_device_driver_unregister| replace:: :c:func:`ssam_device_driver_unregister`
168d779282SMaximilian Luz.. |module_ssam_device_driver| replace:: :c:func:`module_ssam_device_driver`
178d779282SMaximilian Luz.. |SSAM_DEVICE| replace:: :c:func:`SSAM_DEVICE`
188d779282SMaximilian Luz.. |ssam_notifier_register| replace:: :c:func:`ssam_notifier_register`
198d779282SMaximilian Luz.. |ssam_notifier_unregister| replace:: :c:func:`ssam_notifier_unregister`
205c1e88b9SMaximilian Luz.. |ssam_device_notifier_register| replace:: :c:func:`ssam_device_notifier_register`
215c1e88b9SMaximilian Luz.. |ssam_device_notifier_unregister| replace:: :c:func:`ssam_device_notifier_unregister`
22*b09ee1cdSMaximilian Luz.. |ssam_request_do_sync| replace:: :c:func:`ssam_request_do_sync`
238d779282SMaximilian Luz.. |ssam_event_mask| replace:: :c:type:`enum ssam_event_mask <ssam_event_mask>`
248d779282SMaximilian Luz
258d779282SMaximilian Luz
268d779282SMaximilian Luz======================
278d779282SMaximilian LuzWriting Client Drivers
288d779282SMaximilian Luz======================
298d779282SMaximilian Luz
308d779282SMaximilian LuzFor the API documentation, refer to:
318d779282SMaximilian Luz
328d779282SMaximilian Luz.. toctree::
338d779282SMaximilian Luz   :maxdepth: 2
348d779282SMaximilian Luz
358d779282SMaximilian Luz   client-api
368d779282SMaximilian Luz
378d779282SMaximilian Luz
388d779282SMaximilian LuzOverview
398d779282SMaximilian Luz========
408d779282SMaximilian Luz
418d779282SMaximilian LuzClient drivers can be set up in two main ways, depending on how the
428d779282SMaximilian Luzcorresponding device is made available to the system. We specifically
438d779282SMaximilian Luzdifferentiate between devices that are presented to the system via one of
448d779282SMaximilian Luzthe conventional ways, e.g. as platform devices via ACPI, and devices that
458d779282SMaximilian Luzare non-discoverable and instead need to be explicitly provided by some
468d779282SMaximilian Luzother mechanism, as discussed further below.
478d779282SMaximilian Luz
488d779282SMaximilian Luz
498d779282SMaximilian LuzNon-SSAM Client Drivers
508d779282SMaximilian Luz=======================
518d779282SMaximilian Luz
528d779282SMaximilian LuzAll communication with the SAM EC is handled via the |ssam_controller|
538d779282SMaximilian Luzrepresenting that EC to the kernel. Drivers targeting a non-SSAM device (and
548d779282SMaximilian Luzthus not being a |ssam_device_driver|) need to explicitly establish a
558d779282SMaximilian Luzconnection/relation to that controller. This can be done via the
568d779282SMaximilian Luz|ssam_client_bind| function. Said function returns a reference to the SSAM
578d779282SMaximilian Luzcontroller, but, more importantly, also establishes a device link between
588d779282SMaximilian Luzclient device and controller (this can also be done separate via
598d779282SMaximilian Luz|ssam_client_link|). It is important to do this, as it, first, guarantees
608d779282SMaximilian Luzthat the returned controller is valid for use in the client driver for as
618d779282SMaximilian Luzlong as this driver is bound to its device, i.e. that the driver gets
628d779282SMaximilian Luzunbound before the controller ever becomes invalid, and, second, as it
638d779282SMaximilian Luzensures correct suspend/resume ordering. This setup should be done in the
648d779282SMaximilian Luzdriver's probe function, and may be used to defer probing in case the SSAM
658d779282SMaximilian Luzsubsystem is not ready yet, for example:
668d779282SMaximilian Luz
678d779282SMaximilian Luz.. code-block:: c
688d779282SMaximilian Luz
698d779282SMaximilian Luz   static int client_driver_probe(struct platform_device *pdev)
708d779282SMaximilian Luz   {
718d779282SMaximilian Luz           struct ssam_controller *ctrl;
728d779282SMaximilian Luz
738d779282SMaximilian Luz           ctrl = ssam_client_bind(&pdev->dev);
748d779282SMaximilian Luz           if (IS_ERR(ctrl))
758d779282SMaximilian Luz                   return PTR_ERR(ctrl) == -ENODEV ? -EPROBE_DEFER : PTR_ERR(ctrl);
768d779282SMaximilian Luz
778d779282SMaximilian Luz           // ...
788d779282SMaximilian Luz
798d779282SMaximilian Luz           return 0;
808d779282SMaximilian Luz   }
818d779282SMaximilian Luz
828d779282SMaximilian LuzThe controller may be separately obtained via |ssam_get_controller| and its
838d779282SMaximilian Luzlifetime be guaranteed via |ssam_controller_get| and |ssam_controller_put|.
848d779282SMaximilian LuzNote that none of these functions, however, guarantee that the controller
858d779282SMaximilian Luzwill not be shut down or suspended. These functions essentially only operate
868d779282SMaximilian Luzon the reference, i.e. only guarantee a bare minimum of accessibility
878d779282SMaximilian Luzwithout any guarantees at all on practical operability.
888d779282SMaximilian Luz
898d779282SMaximilian Luz
908d779282SMaximilian LuzAdding SSAM Devices
918d779282SMaximilian Luz===================
928d779282SMaximilian Luz
938d779282SMaximilian LuzIf a device does not already exist/is not already provided via conventional
948d779282SMaximilian Luzmeans, it should be provided as |ssam_device| via the SSAM client device
958d779282SMaximilian Luzhub. New devices can be added to this hub by entering their UID into the
968d779282SMaximilian Luzcorresponding registry. SSAM devices can also be manually allocated via
978d779282SMaximilian Luz|ssam_device_alloc|, subsequently to which they have to be added via
988d779282SMaximilian Luz|ssam_device_add| and eventually removed via |ssam_device_remove|. By
998d779282SMaximilian Luzdefault, the parent of the device is set to the controller device provided
1008d779282SMaximilian Luzfor allocation, however this may be changed before the device is added. Note
1018d779282SMaximilian Luzthat, when changing the parent device, care must be taken to ensure that the
1028d779282SMaximilian Luzcontroller lifetime and suspend/resume ordering guarantees, in the default
1038d779282SMaximilian Luzsetup provided through the parent-child relation, are preserved. If
1048d779282SMaximilian Luznecessary, by use of |ssam_client_link| as is done for non-SSAM client
1058d779282SMaximilian Luzdrivers and described in more detail above.
1068d779282SMaximilian Luz
1078d779282SMaximilian LuzA client device must always be removed by the party which added the
1088d779282SMaximilian Luzrespective device before the controller shuts down. Such removal can be
1098d779282SMaximilian Luzguaranteed by linking the driver providing the SSAM device to the controller
1108d779282SMaximilian Luzvia |ssam_client_link|, causing it to unbind before the controller driver
1118d779282SMaximilian Luzunbinds. Client devices registered with the controller as parent are
1128d779282SMaximilian Luzautomatically removed when the controller shuts down, but this should not be
1138d779282SMaximilian Luzrelied upon, especially as this does not extend to client devices with a
1148d779282SMaximilian Luzdifferent parent.
1158d779282SMaximilian Luz
1168d779282SMaximilian Luz
1178d779282SMaximilian LuzSSAM Client Drivers
1188d779282SMaximilian Luz===================
1198d779282SMaximilian Luz
1208d779282SMaximilian LuzSSAM client device drivers are, in essence, no different than other device
1218d779282SMaximilian Luzdriver types. They are represented via |ssam_device_driver| and bind to a
1228d779282SMaximilian Luz|ssam_device| via its UID (:c:type:`struct ssam_device.uid <ssam_device>`)
1238d779282SMaximilian Luzmember and the match table
1248d779282SMaximilian Luz(:c:type:`struct ssam_device_driver.match_table <ssam_device_driver>`),
1258d779282SMaximilian Luzwhich should be set when declaring the driver struct instance. Refer to the
1268d779282SMaximilian Luz|SSAM_DEVICE| macro documentation for more details on how to define members
1278d779282SMaximilian Luzof the driver's match table.
1288d779282SMaximilian Luz
1298d779282SMaximilian LuzThe UID for SSAM client devices consists of a ``domain``, a ``category``,
1308d779282SMaximilian Luza ``target``, an ``instance``, and a ``function``. The ``domain`` is used
1318d779282SMaximilian Luzdifferentiate between physical SAM devices
1328d779282SMaximilian Luz(:c:type:`SSAM_DOMAIN_SERIALHUB <ssam_device_domain>`), i.e. devices that can
1338d779282SMaximilian Luzbe accessed via the Surface Serial Hub, and virtual ones
1348d779282SMaximilian Luz(:c:type:`SSAM_DOMAIN_VIRTUAL <ssam_device_domain>`), such as client-device
1358d779282SMaximilian Luzhubs, that have no real representation on the SAM EC and are solely used on
1368d779282SMaximilian Luzthe kernel/driver-side. For physical devices, ``category`` represents the
1378d779282SMaximilian Luztarget category, ``target`` the target ID, and ``instance`` the instance ID
1388d779282SMaximilian Luzused to access the physical SAM device. In addition, ``function`` references
1398d779282SMaximilian Luza specific device functionality, but has no meaning to the SAM EC. The
1408d779282SMaximilian Luz(default) name of a client device is generated based on its UID.
1418d779282SMaximilian Luz
1428d779282SMaximilian LuzA driver instance can be registered via |ssam_device_driver_register| and
1438d779282SMaximilian Luzunregistered via |ssam_device_driver_unregister|. For convenience, the
1448d779282SMaximilian Luz|module_ssam_device_driver| macro may be used to define module init- and
1458d779282SMaximilian Luzexit-functions registering the driver.
1468d779282SMaximilian Luz
1478d779282SMaximilian LuzThe controller associated with a SSAM client device can be found in its
1488d779282SMaximilian Luz:c:type:`struct ssam_device.ctrl <ssam_device>` member. This reference is
1498d779282SMaximilian Luzguaranteed to be valid for at least as long as the client driver is bound,
1508d779282SMaximilian Luzbut should also be valid for as long as the client device exists. Note,
1518d779282SMaximilian Luzhowever, that access outside of the bound client driver must ensure that the
1528d779282SMaximilian Luzcontroller device is not suspended while making any requests or
1538d779282SMaximilian Luz(un-)registering event notifiers (and thus should generally be avoided). This
1548d779282SMaximilian Luzis guaranteed when the controller is accessed from inside the bound client
1558d779282SMaximilian Luzdriver.
1568d779282SMaximilian Luz
1578d779282SMaximilian Luz
1588d779282SMaximilian LuzMaking Synchronous Requests
1598d779282SMaximilian Luz===========================
1608d779282SMaximilian Luz
1618d779282SMaximilian LuzSynchronous requests are (currently) the main form of host-initiated
1628d779282SMaximilian Luzcommunication with the EC. There are a couple of ways to define and execute
1638d779282SMaximilian Luzsuch requests, however, most of them boil down to something similar as shown
1648d779282SMaximilian Luzin the example below. This example defines a write-read request, meaning
1658d779282SMaximilian Luzthat the caller provides an argument to the SAM EC and receives a response.
1668d779282SMaximilian LuzThe caller needs to know the (maximum) length of the response payload and
1678d779282SMaximilian Luzprovide a buffer for it.
1688d779282SMaximilian Luz
1698d779282SMaximilian LuzCare must be taken to ensure that any command payload data passed to the SAM
1708d779282SMaximilian LuzEC is provided in little-endian format and, similarly, any response payload
1718d779282SMaximilian Luzdata received from it is converted from little-endian to host endianness.
1728d779282SMaximilian Luz
1738d779282SMaximilian Luz.. code-block:: c
1748d779282SMaximilian Luz
1758d779282SMaximilian Luz   int perform_request(struct ssam_controller *ctrl, u32 arg, u32 *ret)
1768d779282SMaximilian Luz   {
1778d779282SMaximilian Luz           struct ssam_request rqst;
1788d779282SMaximilian Luz           struct ssam_response resp;
1798d779282SMaximilian Luz           int status;
1808d779282SMaximilian Luz
1818d779282SMaximilian Luz           /* Convert request argument to little-endian. */
1828d779282SMaximilian Luz           __le32 arg_le = cpu_to_le32(arg);
1838d779282SMaximilian Luz           __le32 ret_le = cpu_to_le32(0);
1848d779282SMaximilian Luz
1858d779282SMaximilian Luz           /*
1868d779282SMaximilian Luz            * Initialize request specification. Replace this with your values.
1878d779282SMaximilian Luz            * The rqst.payload field may be NULL if rqst.length is zero,
1888d779282SMaximilian Luz            * indicating that the request does not have any argument.
1898d779282SMaximilian Luz            *
1908d779282SMaximilian Luz            * Note: The request parameters used here are not valid, i.e.
1918d779282SMaximilian Luz            *       they do not correspond to an actual SAM/EC request.
1928d779282SMaximilian Luz            */
1938d779282SMaximilian Luz           rqst.target_category = SSAM_SSH_TC_SAM;
1943f88b459SMaximilian Luz           rqst.target_id = SSAM_SSH_TID_SAM;
1958d779282SMaximilian Luz           rqst.command_id = 0x02;
1968d779282SMaximilian Luz           rqst.instance_id = 0x03;
1978d779282SMaximilian Luz           rqst.flags = SSAM_REQUEST_HAS_RESPONSE;
1988d779282SMaximilian Luz           rqst.length = sizeof(arg_le);
1998d779282SMaximilian Luz           rqst.payload = (u8 *)&arg_le;
2008d779282SMaximilian Luz
2018d779282SMaximilian Luz           /* Initialize request response. */
2028d779282SMaximilian Luz           resp.capacity = sizeof(ret_le);
2038d779282SMaximilian Luz           resp.length = 0;
2048d779282SMaximilian Luz           resp.pointer = (u8 *)&ret_le;
2058d779282SMaximilian Luz
2068d779282SMaximilian Luz           /*
2078d779282SMaximilian Luz            * Perform actual request. The response pointer may be null in case
2088d779282SMaximilian Luz            * the request does not have any response. This must be consistent
2098d779282SMaximilian Luz            * with the SSAM_REQUEST_HAS_RESPONSE flag set in the specification
2108d779282SMaximilian Luz            * above.
2118d779282SMaximilian Luz            */
212*b09ee1cdSMaximilian Luz           status = ssam_request_do_sync(ctrl, &rqst, &resp);
2138d779282SMaximilian Luz
2148d779282SMaximilian Luz           /*
2158d779282SMaximilian Luz            * Alternatively use
2168d779282SMaximilian Luz            *
217*b09ee1cdSMaximilian Luz            *   ssam_request_do_sync_onstack(ctrl, &rqst, &resp, sizeof(arg_le));
2188d779282SMaximilian Luz            *
2198d779282SMaximilian Luz            * to perform the request, allocating the message buffer directly
2208d779282SMaximilian Luz            * on the stack as opposed to allocation via kzalloc().
2218d779282SMaximilian Luz            */
2228d779282SMaximilian Luz
2238d779282SMaximilian Luz           /*
2248d779282SMaximilian Luz            * Convert request response back to native format. Note that in the
2258d779282SMaximilian Luz            * error case, this value is not touched by the SSAM core, i.e.
2268d779282SMaximilian Luz            * 'ret_le' will be zero as specified in its initialization.
2278d779282SMaximilian Luz            */
2288d779282SMaximilian Luz           *ret = le32_to_cpu(ret_le);
2298d779282SMaximilian Luz
2308d779282SMaximilian Luz           return status;
2318d779282SMaximilian Luz   }
2328d779282SMaximilian Luz
233*b09ee1cdSMaximilian LuzNote that |ssam_request_do_sync| in its essence is a wrapper over lower-level
2348d779282SMaximilian Luzrequest primitives, which may also be used to perform requests. Refer to its
2358d779282SMaximilian Luzimplementation and documentation for more details.
2368d779282SMaximilian Luz
2378d779282SMaximilian LuzAn arguably more user-friendly way of defining such functions is by using
2388d779282SMaximilian Luzone of the generator macros, for example via:
2398d779282SMaximilian Luz
2408d779282SMaximilian Luz.. code-block:: c
2418d779282SMaximilian Luz
2428d779282SMaximilian Luz   SSAM_DEFINE_SYNC_REQUEST_W(__ssam_tmp_perf_mode_set, __le32, {
2438d779282SMaximilian Luz           .target_category = SSAM_SSH_TC_TMP,
2443f88b459SMaximilian Luz           .target_id       = SSAM_SSH_TID_SAM,
2458d779282SMaximilian Luz           .command_id      = 0x03,
2468d779282SMaximilian Luz           .instance_id     = 0x00,
2478d779282SMaximilian Luz   });
2488d779282SMaximilian Luz
2498d779282SMaximilian LuzThis example defines a function
2508d779282SMaximilian Luz
2518d779282SMaximilian Luz.. code-block:: c
2528d779282SMaximilian Luz
25303ee3183SMaximilian Luz   static int __ssam_tmp_perf_mode_set(struct ssam_controller *ctrl, const __le32 *arg);
2548d779282SMaximilian Luz
2558d779282SMaximilian Luzexecuting the specified request, with the controller passed in when calling
2568d779282SMaximilian Luzsaid function. In this example, the argument is provided via the ``arg``
2578d779282SMaximilian Luzpointer. Note that the generated function allocates the message buffer on
2588d779282SMaximilian Luzthe stack. Thus, if the argument provided via the request is large, these
2598d779282SMaximilian Luzkinds of macros should be avoided. Also note that, in contrast to the
2608d779282SMaximilian Luzprevious non-macro example, this function does not do any endianness
2618d779282SMaximilian Luzconversion, which has to be handled by the caller. Apart from those
2628d779282SMaximilian Luzdifferences the function generated by the macro is similar to the one
2638d779282SMaximilian Luzprovided in the non-macro example above.
2648d779282SMaximilian Luz
2658d779282SMaximilian LuzThe full list of such function-generating macros is
2668d779282SMaximilian Luz
2678d779282SMaximilian Luz- :c:func:`SSAM_DEFINE_SYNC_REQUEST_N` for requests without return value and
2688d779282SMaximilian Luz  without argument.
2698d779282SMaximilian Luz- :c:func:`SSAM_DEFINE_SYNC_REQUEST_R` for requests with return value but no
2708d779282SMaximilian Luz  argument.
2718d779282SMaximilian Luz- :c:func:`SSAM_DEFINE_SYNC_REQUEST_W` for requests without return value but
2728d779282SMaximilian Luz  with argument.
2738d779282SMaximilian Luz
2748d779282SMaximilian LuzRefer to their respective documentation for more details. For each one of
2758d779282SMaximilian Luzthese macros, a special variant is provided, which targets request types
2768d779282SMaximilian Luzapplicable to multiple instances of the same device type:
2778d779282SMaximilian Luz
2788d779282SMaximilian Luz- :c:func:`SSAM_DEFINE_SYNC_REQUEST_MD_N`
2798d779282SMaximilian Luz- :c:func:`SSAM_DEFINE_SYNC_REQUEST_MD_R`
2808d779282SMaximilian Luz- :c:func:`SSAM_DEFINE_SYNC_REQUEST_MD_W`
2818d779282SMaximilian Luz
2828d779282SMaximilian LuzThe difference of those macros to the previously mentioned versions is, that
2838d779282SMaximilian Luzthe device target and instance IDs are not fixed for the generated function,
2848d779282SMaximilian Luzbut instead have to be provided by the caller of said function.
2858d779282SMaximilian Luz
2868d779282SMaximilian LuzAdditionally, variants for direct use with client devices, i.e.
2878d779282SMaximilian Luz|ssam_device|, are also provided. These can, for example, be used as
2888d779282SMaximilian Luzfollows:
2898d779282SMaximilian Luz
2908d779282SMaximilian Luz.. code-block:: c
2918d779282SMaximilian Luz
2928d779282SMaximilian Luz   SSAM_DEFINE_SYNC_REQUEST_CL_R(ssam_bat_get_sta, __le32, {
2938d779282SMaximilian Luz           .target_category = SSAM_SSH_TC_BAT,
2948d779282SMaximilian Luz           .command_id      = 0x01,
2958d779282SMaximilian Luz   });
2968d779282SMaximilian Luz
2978d779282SMaximilian LuzThis invocation of the macro defines a function
2988d779282SMaximilian Luz
2998d779282SMaximilian Luz.. code-block:: c
3008d779282SMaximilian Luz
30103ee3183SMaximilian Luz   static int ssam_bat_get_sta(struct ssam_device *sdev, __le32 *ret);
3028d779282SMaximilian Luz
3038d779282SMaximilian Luzexecuting the specified request, using the device IDs and controller given
3048d779282SMaximilian Luzin the client device. The full list of such macros for client devices is:
3058d779282SMaximilian Luz
3068d779282SMaximilian Luz- :c:func:`SSAM_DEFINE_SYNC_REQUEST_CL_N`
3078d779282SMaximilian Luz- :c:func:`SSAM_DEFINE_SYNC_REQUEST_CL_R`
3088d779282SMaximilian Luz- :c:func:`SSAM_DEFINE_SYNC_REQUEST_CL_W`
3098d779282SMaximilian Luz
3108d779282SMaximilian Luz
3118d779282SMaximilian LuzHandling Events
3128d779282SMaximilian Luz===============
3138d779282SMaximilian Luz
3148d779282SMaximilian LuzTo receive events from the SAM EC, an event notifier must be registered for
3158d779282SMaximilian Luzthe desired event via |ssam_notifier_register|. The notifier must be
3168d779282SMaximilian Luzunregistered via |ssam_notifier_unregister| once it is not required any
3175c1e88b9SMaximilian Luzmore. For |ssam_device| type clients, the |ssam_device_notifier_register| and
3185c1e88b9SMaximilian Luz|ssam_device_notifier_unregister| wrappers should be preferred as they properly
3195c1e88b9SMaximilian Luzhandle hot-removal of client devices.
3208d779282SMaximilian Luz
3218d779282SMaximilian LuzEvent notifiers are registered by providing (at minimum) a callback to call
3228d779282SMaximilian Luzin case an event has been received, the registry specifying how the event
3238d779282SMaximilian Luzshould be enabled, an event ID specifying for which target category and,
3248d779282SMaximilian Luzoptionally and depending on the registry used, for which instance ID events
3258d779282SMaximilian Luzshould be enabled, and finally, flags describing how the EC will send these
3268d779282SMaximilian Luzevents. If the specific registry does not enable events by instance ID, the
3278d779282SMaximilian Luzinstance ID must be set to zero. Additionally, a priority for the respective
3288d779282SMaximilian Luznotifier may be specified, which determines its order in relation to any
3298d779282SMaximilian Luzother notifier registered for the same target category.
3308d779282SMaximilian Luz
3318d779282SMaximilian LuzBy default, event notifiers will receive all events for the specific target
3328d779282SMaximilian Luzcategory, regardless of the instance ID specified when registering the
3338d779282SMaximilian Luznotifier. The core may be instructed to only call a notifier if the target
3348d779282SMaximilian LuzID or instance ID (or both) of the event match the ones implied by the
3358d779282SMaximilian Luznotifier IDs (in case of target ID, the target ID of the registry), by
3368d779282SMaximilian Luzproviding an event mask (see |ssam_event_mask|).
3378d779282SMaximilian Luz
3388d779282SMaximilian LuzIn general, the target ID of the registry is also the target ID of the
3398d779282SMaximilian Luzenabled event (with the notable exception being keyboard input events on the
3408d779282SMaximilian LuzSurface Laptop 1 and 2, which are enabled via a registry with target ID 1,
3418d779282SMaximilian Luzbut provide events with target ID 2).
3428d779282SMaximilian Luz
3438d779282SMaximilian LuzA full example for registering an event notifier and handling received
3448d779282SMaximilian Luzevents is provided below:
3458d779282SMaximilian Luz
3468d779282SMaximilian Luz.. code-block:: c
3478d779282SMaximilian Luz
3488d779282SMaximilian Luz   u32 notifier_callback(struct ssam_event_notifier *nf,
3498d779282SMaximilian Luz                         const struct ssam_event *event)
3508d779282SMaximilian Luz   {
3518d779282SMaximilian Luz           int status = ...
3528d779282SMaximilian Luz
3538d779282SMaximilian Luz           /* Handle the event here ... */
3548d779282SMaximilian Luz
3558d779282SMaximilian Luz           /* Convert return value and indicate that we handled the event. */
3568d779282SMaximilian Luz           return ssam_notifier_from_errno(status) | SSAM_NOTIF_HANDLED;
3578d779282SMaximilian Luz   }
3588d779282SMaximilian Luz
3598d779282SMaximilian Luz   int setup_notifier(struct ssam_device *sdev,
3608d779282SMaximilian Luz                      struct ssam_event_notifier *nf)
3618d779282SMaximilian Luz   {
3628d779282SMaximilian Luz           /* Set priority wrt. other handlers of same target category. */
3638d779282SMaximilian Luz           nf->base.priority = 1;
3648d779282SMaximilian Luz
3658d779282SMaximilian Luz           /* Set event/notifier callback. */
3668d779282SMaximilian Luz           nf->base.fn = notifier_callback;
3678d779282SMaximilian Luz
3688d779282SMaximilian Luz           /* Specify event registry, i.e. how events get enabled/disabled. */
3698d779282SMaximilian Luz           nf->event.reg = SSAM_EVENT_REGISTRY_KIP;
3708d779282SMaximilian Luz
3718d779282SMaximilian Luz           /* Specify which event to enable/disable */
3728d779282SMaximilian Luz           nf->event.id.target_category = sdev->uid.category;
3738d779282SMaximilian Luz           nf->event.id.instance = sdev->uid.instance;
3748d779282SMaximilian Luz
3758d779282SMaximilian Luz           /*
3768d779282SMaximilian Luz            * Specify for which events the notifier callback gets executed.
3778d779282SMaximilian Luz            * This essentially tells the core if it can skip notifiers that
3788d779282SMaximilian Luz            * don't have target or instance IDs matching those of the event.
3798d779282SMaximilian Luz            */
3808d779282SMaximilian Luz           nf->event.mask = SSAM_EVENT_MASK_STRICT;
3818d779282SMaximilian Luz
3828d779282SMaximilian Luz           /* Specify event flags. */
3838d779282SMaximilian Luz           nf->event.flags = SSAM_EVENT_SEQUENCED;
3848d779282SMaximilian Luz
3858d779282SMaximilian Luz           return ssam_notifier_register(sdev->ctrl, nf);
3868d779282SMaximilian Luz   }
3878d779282SMaximilian Luz
3888d779282SMaximilian LuzMultiple event notifiers can be registered for the same event. The event
3898d779282SMaximilian Luzhandler core takes care of enabling and disabling events when notifiers are
3908d779282SMaximilian Luzregistered and unregistered, by keeping track of how many notifiers for a
3918d779282SMaximilian Luzspecific event (combination of registry, event target category, and event
3928d779282SMaximilian Luzinstance ID) are currently registered. This means that a specific event will
3938d779282SMaximilian Luzbe enabled when the first notifier for it is being registered and disabled
3948d779282SMaximilian Luzwhen the last notifier for it is being unregistered. Note that the event
3958d779282SMaximilian Luzflags are therefore only used on the first registered notifier, however, one
3968d779282SMaximilian Luzshould take care that notifiers for a specific event are always registered
3978d779282SMaximilian Luzwith the same flag and it is considered a bug to do otherwise.
398