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