~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/Documentation/driver-api/surface_aggregator/client.rst

Version: ~ [ linux-6.12-rc7 ] ~ [ linux-6.11.7 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.60 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.116 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.171 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.229 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.285 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.323 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.12 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 .. SPDX-License-Identifier: GPL-2.0+
  2 
  3 .. |ssam_controller| replace:: :c:type:`struct ssam_controller <ssam_controller>`
  4 .. |ssam_device| replace:: :c:type:`struct ssam_device <ssam_device>`
  5 .. |ssam_device_driver| replace:: :c:type:`struct ssam_device_driver <ssam_device_driver>`
  6 .. |ssam_client_bind| replace:: :c:func:`ssam_client_bind`
  7 .. |ssam_client_link| replace:: :c:func:`ssam_client_link`
  8 .. |ssam_get_controller| replace:: :c:func:`ssam_get_controller`
  9 .. |ssam_controller_get| replace:: :c:func:`ssam_controller_get`
 10 .. |ssam_controller_put| replace:: :c:func:`ssam_controller_put`
 11 .. |ssam_device_alloc| replace:: :c:func:`ssam_device_alloc`
 12 .. |ssam_device_add| replace:: :c:func:`ssam_device_add`
 13 .. |ssam_device_remove| replace:: :c:func:`ssam_device_remove`
 14 .. |ssam_device_driver_register| replace:: :c:func:`ssam_device_driver_register`
 15 .. |ssam_device_driver_unregister| replace:: :c:func:`ssam_device_driver_unregister`
 16 .. |module_ssam_device_driver| replace:: :c:func:`module_ssam_device_driver`
 17 .. |SSAM_DEVICE| replace:: :c:func:`SSAM_DEVICE`
 18 .. |ssam_notifier_register| replace:: :c:func:`ssam_notifier_register`
 19 .. |ssam_notifier_unregister| replace:: :c:func:`ssam_notifier_unregister`
 20 .. |ssam_device_notifier_register| replace:: :c:func:`ssam_device_notifier_register`
 21 .. |ssam_device_notifier_unregister| replace:: :c:func:`ssam_device_notifier_unregister`
 22 .. |ssam_request_do_sync| replace:: :c:func:`ssam_request_do_sync`
 23 .. |ssam_event_mask| replace:: :c:type:`enum ssam_event_mask <ssam_event_mask>`
 24 
 25 
 26 ======================
 27 Writing Client Drivers
 28 ======================
 29 
 30 For the API documentation, refer to:
 31 
 32 .. toctree::
 33    :maxdepth: 2
 34 
 35    client-api
 36 
 37 
 38 Overview
 39 ========
 40 
 41 Client drivers can be set up in two main ways, depending on how the
 42 corresponding device is made available to the system. We specifically
 43 differentiate between devices that are presented to the system via one of
 44 the conventional ways, e.g. as platform devices via ACPI, and devices that
 45 are non-discoverable and instead need to be explicitly provided by some
 46 other mechanism, as discussed further below.
 47 
 48 
 49 Non-SSAM Client Drivers
 50 =======================
 51 
 52 All communication with the SAM EC is handled via the |ssam_controller|
 53 representing that EC to the kernel. Drivers targeting a non-SSAM device (and
 54 thus not being a |ssam_device_driver|) need to explicitly establish a
 55 connection/relation to that controller. This can be done via the
 56 |ssam_client_bind| function. Said function returns a reference to the SSAM
 57 controller, but, more importantly, also establishes a device link between
 58 client device and controller (this can also be done separate via
 59 |ssam_client_link|). It is important to do this, as it, first, guarantees
 60 that the returned controller is valid for use in the client driver for as
 61 long as this driver is bound to its device, i.e. that the driver gets
 62 unbound before the controller ever becomes invalid, and, second, as it
 63 ensures correct suspend/resume ordering. This setup should be done in the
 64 driver's probe function, and may be used to defer probing in case the SSAM
 65 subsystem is not ready yet, for example:
 66 
 67 .. code-block:: c
 68 
 69    static int client_driver_probe(struct platform_device *pdev)
 70    {
 71            struct ssam_controller *ctrl;
 72 
 73            ctrl = ssam_client_bind(&pdev->dev);
 74            if (IS_ERR(ctrl))
 75                    return PTR_ERR(ctrl) == -ENODEV ? -EPROBE_DEFER : PTR_ERR(ctrl);
 76 
 77            // ...
 78 
 79            return 0;
 80    }
 81 
 82 The controller may be separately obtained via |ssam_get_controller| and its
 83 lifetime be guaranteed via |ssam_controller_get| and |ssam_controller_put|.
 84 Note that none of these functions, however, guarantee that the controller
 85 will not be shut down or suspended. These functions essentially only operate
 86 on the reference, i.e. only guarantee a bare minimum of accessibility
 87 without any guarantees at all on practical operability.
 88 
 89 
 90 Adding SSAM Devices
 91 ===================
 92 
 93 If a device does not already exist/is not already provided via conventional
 94 means, it should be provided as |ssam_device| via the SSAM client device
 95 hub. New devices can be added to this hub by entering their UID into the
 96 corresponding registry. SSAM devices can also be manually allocated via
 97 |ssam_device_alloc|, subsequently to which they have to be added via
 98 |ssam_device_add| and eventually removed via |ssam_device_remove|. By
 99 default, the parent of the device is set to the controller device provided
100 for allocation, however this may be changed before the device is added. Note
101 that, when changing the parent device, care must be taken to ensure that the
102 controller lifetime and suspend/resume ordering guarantees, in the default
103 setup provided through the parent-child relation, are preserved. If
104 necessary, by use of |ssam_client_link| as is done for non-SSAM client
105 drivers and described in more detail above.
106 
107 A client device must always be removed by the party which added the
108 respective device before the controller shuts down. Such removal can be
109 guaranteed by linking the driver providing the SSAM device to the controller
110 via |ssam_client_link|, causing it to unbind before the controller driver
111 unbinds. Client devices registered with the controller as parent are
112 automatically removed when the controller shuts down, but this should not be
113 relied upon, especially as this does not extend to client devices with a
114 different parent.
115 
116 
117 SSAM Client Drivers
118 ===================
119 
120 SSAM client device drivers are, in essence, no different than other device
121 driver types. They are represented via |ssam_device_driver| and bind to a
122 |ssam_device| via its UID (:c:type:`struct ssam_device.uid <ssam_device>`)
123 member and the match table
124 (:c:type:`struct ssam_device_driver.match_table <ssam_device_driver>`),
125 which should be set when declaring the driver struct instance. Refer to the
126 |SSAM_DEVICE| macro documentation for more details on how to define members
127 of the driver's match table.
128 
129 The UID for SSAM client devices consists of a ``domain``, a ``category``,
130 a ``target``, an ``instance``, and a ``function``. The ``domain`` is used
131 differentiate between physical SAM devices
132 (:c:type:`SSAM_DOMAIN_SERIALHUB <ssam_device_domain>`), i.e. devices that can
133 be accessed via the Surface Serial Hub, and virtual ones
134 (:c:type:`SSAM_DOMAIN_VIRTUAL <ssam_device_domain>`), such as client-device
135 hubs, that have no real representation on the SAM EC and are solely used on
136 the kernel/driver-side. For physical devices, ``category`` represents the
137 target category, ``target`` the target ID, and ``instance`` the instance ID
138 used to access the physical SAM device. In addition, ``function`` references
139 a specific device functionality, but has no meaning to the SAM EC. The
140 (default) name of a client device is generated based on its UID.
141 
142 A driver instance can be registered via |ssam_device_driver_register| and
143 unregistered via |ssam_device_driver_unregister|. For convenience, the
144 |module_ssam_device_driver| macro may be used to define module init- and
145 exit-functions registering the driver.
146 
147 The controller associated with a SSAM client device can be found in its
148 :c:type:`struct ssam_device.ctrl <ssam_device>` member. This reference is
149 guaranteed to be valid for at least as long as the client driver is bound,
150 but should also be valid for as long as the client device exists. Note,
151 however, that access outside of the bound client driver must ensure that the
152 controller device is not suspended while making any requests or
153 (un-)registering event notifiers (and thus should generally be avoided). This
154 is guaranteed when the controller is accessed from inside the bound client
155 driver.
156 
157 
158 Making Synchronous Requests
159 ===========================
160 
161 Synchronous requests are (currently) the main form of host-initiated
162 communication with the EC. There are a couple of ways to define and execute
163 such requests, however, most of them boil down to something similar as shown
164 in the example below. This example defines a write-read request, meaning
165 that the caller provides an argument to the SAM EC and receives a response.
166 The caller needs to know the (maximum) length of the response payload and
167 provide a buffer for it.
168 
169 Care must be taken to ensure that any command payload data passed to the SAM
170 EC is provided in little-endian format and, similarly, any response payload
171 data received from it is converted from little-endian to host endianness.
172 
173 .. code-block:: c
174 
175    int perform_request(struct ssam_controller *ctrl, u32 arg, u32 *ret)
176    {
177            struct ssam_request rqst;
178            struct ssam_response resp;
179            int status;
180 
181            /* Convert request argument to little-endian. */
182            __le32 arg_le = cpu_to_le32(arg);
183            __le32 ret_le = cpu_to_le32(0);
184 
185            /*
186             * Initialize request specification. Replace this with your values.
187             * The rqst.payload field may be NULL if rqst.length is zero,
188             * indicating that the request does not have any argument.
189             *
190             * Note: The request parameters used here are not valid, i.e.
191             *       they do not correspond to an actual SAM/EC request.
192             */
193            rqst.target_category = SSAM_SSH_TC_SAM;
194            rqst.target_id = SSAM_SSH_TID_SAM;
195            rqst.command_id = 0x02;
196            rqst.instance_id = 0x03;
197            rqst.flags = SSAM_REQUEST_HAS_RESPONSE;
198            rqst.length = sizeof(arg_le);
199            rqst.payload = (u8 *)&arg_le;
200 
201            /* Initialize request response. */
202            resp.capacity = sizeof(ret_le);
203            resp.length = 0;
204            resp.pointer = (u8 *)&ret_le;
205 
206            /*
207             * Perform actual request. The response pointer may be null in case
208             * the request does not have any response. This must be consistent
209             * with the SSAM_REQUEST_HAS_RESPONSE flag set in the specification
210             * above.
211             */
212            status = ssam_request_do_sync(ctrl, &rqst, &resp);
213 
214            /*
215             * Alternatively use
216             *
217             *   ssam_request_do_sync_onstack(ctrl, &rqst, &resp, sizeof(arg_le));
218             *
219             * to perform the request, allocating the message buffer directly
220             * on the stack as opposed to allocation via kzalloc().
221             */
222 
223            /*
224             * Convert request response back to native format. Note that in the
225             * error case, this value is not touched by the SSAM core, i.e.
226             * 'ret_le' will be zero as specified in its initialization.
227             */
228            *ret = le32_to_cpu(ret_le);
229 
230            return status;
231    }
232 
233 Note that |ssam_request_do_sync| in its essence is a wrapper over lower-level
234 request primitives, which may also be used to perform requests. Refer to its
235 implementation and documentation for more details.
236 
237 An arguably more user-friendly way of defining such functions is by using
238 one of the generator macros, for example via:
239 
240 .. code-block:: c
241 
242    SSAM_DEFINE_SYNC_REQUEST_W(__ssam_tmp_perf_mode_set, __le32, {
243            .target_category = SSAM_SSH_TC_TMP,
244            .target_id       = SSAM_SSH_TID_SAM,
245            .command_id      = 0x03,
246            .instance_id     = 0x00,
247    });
248 
249 This example defines a function
250 
251 .. code-block:: c
252 
253    static int __ssam_tmp_perf_mode_set(struct ssam_controller *ctrl, const __le32 *arg);
254 
255 executing the specified request, with the controller passed in when calling
256 said function. In this example, the argument is provided via the ``arg``
257 pointer. Note that the generated function allocates the message buffer on
258 the stack. Thus, if the argument provided via the request is large, these
259 kinds of macros should be avoided. Also note that, in contrast to the
260 previous non-macro example, this function does not do any endianness
261 conversion, which has to be handled by the caller. Apart from those
262 differences the function generated by the macro is similar to the one
263 provided in the non-macro example above.
264 
265 The full list of such function-generating macros is
266 
267 - :c:func:`SSAM_DEFINE_SYNC_REQUEST_N` for requests without return value and
268   without argument.
269 - :c:func:`SSAM_DEFINE_SYNC_REQUEST_R` for requests with return value but no
270   argument.
271 - :c:func:`SSAM_DEFINE_SYNC_REQUEST_W` for requests without return value but
272   with argument.
273 
274 Refer to their respective documentation for more details. For each one of
275 these macros, a special variant is provided, which targets request types
276 applicable to multiple instances of the same device type:
277 
278 - :c:func:`SSAM_DEFINE_SYNC_REQUEST_MD_N`
279 - :c:func:`SSAM_DEFINE_SYNC_REQUEST_MD_R`
280 - :c:func:`SSAM_DEFINE_SYNC_REQUEST_MD_W`
281 
282 The difference of those macros to the previously mentioned versions is, that
283 the device target and instance IDs are not fixed for the generated function,
284 but instead have to be provided by the caller of said function.
285 
286 Additionally, variants for direct use with client devices, i.e.
287 |ssam_device|, are also provided. These can, for example, be used as
288 follows:
289 
290 .. code-block:: c
291 
292    SSAM_DEFINE_SYNC_REQUEST_CL_R(ssam_bat_get_sta, __le32, {
293            .target_category = SSAM_SSH_TC_BAT,
294            .command_id      = 0x01,
295    });
296 
297 This invocation of the macro defines a function
298 
299 .. code-block:: c
300 
301    static int ssam_bat_get_sta(struct ssam_device *sdev, __le32 *ret);
302 
303 executing the specified request, using the device IDs and controller given
304 in the client device. The full list of such macros for client devices is:
305 
306 - :c:func:`SSAM_DEFINE_SYNC_REQUEST_CL_N`
307 - :c:func:`SSAM_DEFINE_SYNC_REQUEST_CL_R`
308 - :c:func:`SSAM_DEFINE_SYNC_REQUEST_CL_W`
309 
310 
311 Handling Events
312 ===============
313 
314 To receive events from the SAM EC, an event notifier must be registered for
315 the desired event via |ssam_notifier_register|. The notifier must be
316 unregistered via |ssam_notifier_unregister| once it is not required any
317 more. For |ssam_device| type clients, the |ssam_device_notifier_register| and
318 |ssam_device_notifier_unregister| wrappers should be preferred as they properly
319 handle hot-removal of client devices.
320 
321 Event notifiers are registered by providing (at minimum) a callback to call
322 in case an event has been received, the registry specifying how the event
323 should be enabled, an event ID specifying for which target category and,
324 optionally and depending on the registry used, for which instance ID events
325 should be enabled, and finally, flags describing how the EC will send these
326 events. If the specific registry does not enable events by instance ID, the
327 instance ID must be set to zero. Additionally, a priority for the respective
328 notifier may be specified, which determines its order in relation to any
329 other notifier registered for the same target category.
330 
331 By default, event notifiers will receive all events for the specific target
332 category, regardless of the instance ID specified when registering the
333 notifier. The core may be instructed to only call a notifier if the target
334 ID or instance ID (or both) of the event match the ones implied by the
335 notifier IDs (in case of target ID, the target ID of the registry), by
336 providing an event mask (see |ssam_event_mask|).
337 
338 In general, the target ID of the registry is also the target ID of the
339 enabled event (with the notable exception being keyboard input events on the
340 Surface Laptop 1 and 2, which are enabled via a registry with target ID 1,
341 but provide events with target ID 2).
342 
343 A full example for registering an event notifier and handling received
344 events is provided below:
345 
346 .. code-block:: c
347 
348    u32 notifier_callback(struct ssam_event_notifier *nf,
349                          const struct ssam_event *event)
350    {
351            int status = ...
352 
353            /* Handle the event here ... */
354 
355            /* Convert return value and indicate that we handled the event. */
356            return ssam_notifier_from_errno(status) | SSAM_NOTIF_HANDLED;
357    }
358 
359    int setup_notifier(struct ssam_device *sdev,
360                       struct ssam_event_notifier *nf)
361    {
362            /* Set priority wrt. other handlers of same target category. */
363            nf->base.priority = 1;
364 
365            /* Set event/notifier callback. */
366            nf->base.fn = notifier_callback;
367 
368            /* Specify event registry, i.e. how events get enabled/disabled. */
369            nf->event.reg = SSAM_EVENT_REGISTRY_KIP;
370 
371            /* Specify which event to enable/disable */
372            nf->event.id.target_category = sdev->uid.category;
373            nf->event.id.instance = sdev->uid.instance;
374 
375            /*
376             * Specify for which events the notifier callback gets executed.
377             * This essentially tells the core if it can skip notifiers that
378             * don't have target or instance IDs matching those of the event.
379             */
380            nf->event.mask = SSAM_EVENT_MASK_STRICT;
381 
382            /* Specify event flags. */
383            nf->event.flags = SSAM_EVENT_SEQUENCED;
384 
385            return ssam_notifier_register(sdev->ctrl, nf);
386    }
387 
388 Multiple event notifiers can be registered for the same event. The event
389 handler core takes care of enabling and disabling events when notifiers are
390 registered and unregistered, by keeping track of how many notifiers for a
391 specific event (combination of registry, event target category, and event
392 instance ID) are currently registered. This means that a specific event will
393 be enabled when the first notifier for it is being registered and disabled
394 when the last notifier for it is being unregistered. Note that the event
395 flags are therefore only used on the first registered notifier, however, one
396 should take care that notifiers for a specific event are always registered
397 with the same flag and it is considered a bug to do otherwise.

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php