| 1 | /* SPDX-License-Identifier: GPL-2.0+ */ |
| 2 | /* |
| 3 | * Surface System Aggregator Module (SSAM) bus and client-device subsystem. |
| 4 | * |
| 5 | * Main interface for the surface-aggregator bus, surface-aggregator client |
| 6 | * devices, and respective drivers building on top of the SSAM controller. |
| 7 | * Provides support for non-platform/non-ACPI SSAM clients via dedicated |
| 8 | * subsystem. |
| 9 | * |
| 10 | * Copyright (C) 2019-2021 Maximilian Luz <luzmaximilian@gmail.com> |
| 11 | */ |
| 12 | |
| 13 | #ifndef _LINUX_SURFACE_AGGREGATOR_DEVICE_H |
| 14 | #define _LINUX_SURFACE_AGGREGATOR_DEVICE_H |
| 15 | |
| 16 | #include <linux/device.h> |
| 17 | #include <linux/mod_devicetable.h> |
| 18 | #include <linux/property.h> |
| 19 | #include <linux/types.h> |
| 20 | |
| 21 | #include <linux/surface_aggregator/controller.h> |
| 22 | |
| 23 | |
| 24 | /* -- Surface System Aggregator Module bus. --------------------------------- */ |
| 25 | |
| 26 | /** |
| 27 | * enum ssam_device_domain - SAM device domain. |
| 28 | * @SSAM_DOMAIN_VIRTUAL: Virtual device. |
| 29 | * @SSAM_DOMAIN_SERIALHUB: Physical device connected via Surface Serial Hub. |
| 30 | */ |
| 31 | enum ssam_device_domain { |
| 32 | SSAM_DOMAIN_VIRTUAL = 0x00, |
| 33 | SSAM_DOMAIN_SERIALHUB = 0x01, |
| 34 | }; |
| 35 | |
| 36 | /** |
| 37 | * enum ssam_virtual_tc - Target categories for the virtual SAM domain. |
| 38 | * @SSAM_VIRTUAL_TC_HUB: Device hub category. |
| 39 | */ |
| 40 | enum ssam_virtual_tc { |
| 41 | SSAM_VIRTUAL_TC_HUB = 0x00, |
| 42 | }; |
| 43 | |
| 44 | /** |
| 45 | * struct ssam_device_uid - Unique identifier for SSAM device. |
| 46 | * @domain: Domain of the device. |
| 47 | * @category: Target category of the device. |
| 48 | * @target: Target ID of the device. |
| 49 | * @instance: Instance ID of the device. |
| 50 | * @function: Sub-function of the device. This field can be used to split a |
| 51 | * single SAM device into multiple virtual subdevices to separate |
| 52 | * different functionality of that device and allow one driver per |
| 53 | * such functionality. |
| 54 | */ |
| 55 | struct ssam_device_uid { |
| 56 | u8 domain; |
| 57 | u8 category; |
| 58 | u8 target; |
| 59 | u8 instance; |
| 60 | u8 function; |
| 61 | }; |
| 62 | |
| 63 | /* |
| 64 | * Special values for device matching. |
| 65 | * |
| 66 | * These values are intended to be used with SSAM_DEVICE(), SSAM_VDEV(), and |
| 67 | * SSAM_SDEV() exclusively. Specifically, they are used to initialize the |
| 68 | * match_flags member of the device ID structure. Do not use them directly |
| 69 | * with struct ssam_device_id or struct ssam_device_uid. |
| 70 | */ |
| 71 | #define SSAM_SSH_TID_ANY 0xffff |
| 72 | #define SSAM_SSH_IID_ANY 0xffff |
| 73 | #define SSAM_SSH_FUN_ANY 0xffff |
| 74 | |
| 75 | /** |
| 76 | * SSAM_DEVICE() - Initialize a &struct ssam_device_id with the given |
| 77 | * parameters. |
| 78 | * @d: Domain of the device. |
| 79 | * @cat: Target category of the device. |
| 80 | * @tid: Target ID of the device. |
| 81 | * @iid: Instance ID of the device. |
| 82 | * @fun: Sub-function of the device. |
| 83 | * |
| 84 | * Initializes a &struct ssam_device_id with the given parameters. See &struct |
| 85 | * ssam_device_uid for details regarding the parameters. The special values |
| 86 | * %SSAM_SSH_TID_ANY, %SSAM_SSH_IID_ANY, and %SSAM_SSH_FUN_ANY can be used to specify that |
| 87 | * matching should ignore target ID, instance ID, and/or sub-function, |
| 88 | * respectively. This macro initializes the ``match_flags`` field based on the |
| 89 | * given parameters. |
| 90 | * |
| 91 | * Note: The parameters @d and @cat must be valid &u8 values, the parameters |
| 92 | * @tid, @iid, and @fun must be either valid &u8 values or %SSAM_SSH_TID_ANY, |
| 93 | * %SSAM_SSH_IID_ANY, or %SSAM_SSH_FUN_ANY, respectively. Other non-&u8 values are not |
| 94 | * allowed. |
| 95 | */ |
| 96 | #define SSAM_DEVICE(d, cat, tid, iid, fun) \ |
| 97 | .match_flags = (((tid) != SSAM_SSH_TID_ANY) ? SSAM_MATCH_TARGET : 0) \ |
| 98 | | (((iid) != SSAM_SSH_IID_ANY) ? SSAM_MATCH_INSTANCE : 0) \ |
| 99 | | (((fun) != SSAM_SSH_FUN_ANY) ? SSAM_MATCH_FUNCTION : 0), \ |
| 100 | .domain = d, \ |
| 101 | .category = cat, \ |
| 102 | .target = __builtin_choose_expr((tid) != SSAM_SSH_TID_ANY, (tid), 0), \ |
| 103 | .instance = __builtin_choose_expr((iid) != SSAM_SSH_IID_ANY, (iid), 0), \ |
| 104 | .function = __builtin_choose_expr((fun) != SSAM_SSH_FUN_ANY, (fun), 0) |
| 105 | |
| 106 | /** |
| 107 | * SSAM_VDEV() - Initialize a &struct ssam_device_id as virtual device with |
| 108 | * the given parameters. |
| 109 | * @cat: Target category of the device. |
| 110 | * @tid: Target ID of the device. |
| 111 | * @iid: Instance ID of the device. |
| 112 | * @fun: Sub-function of the device. |
| 113 | * |
| 114 | * Initializes a &struct ssam_device_id with the given parameters in the |
| 115 | * virtual domain. See &struct ssam_device_uid for details regarding the |
| 116 | * parameters. The special values %SSAM_SSH_TID_ANY, %SSAM_SSH_IID_ANY, and |
| 117 | * %SSAM_SSH_FUN_ANY can be used to specify that matching should ignore target ID, |
| 118 | * instance ID, and/or sub-function, respectively. This macro initializes the |
| 119 | * ``match_flags`` field based on the given parameters. |
| 120 | * |
| 121 | * Note: The parameter @cat must be a valid &u8 value, the parameters @tid, |
| 122 | * @iid, and @fun must be either valid &u8 values or %SSAM_SSH_TID_ANY, |
| 123 | * %SSAM_SSH_IID_ANY, or %SSAM_SSH_FUN_ANY, respectively. Other non-&u8 values are not |
| 124 | * allowed. |
| 125 | */ |
| 126 | #define SSAM_VDEV(cat, tid, iid, fun) \ |
| 127 | SSAM_DEVICE(SSAM_DOMAIN_VIRTUAL, SSAM_VIRTUAL_TC_##cat, SSAM_SSH_TID_##tid, iid, fun) |
| 128 | |
| 129 | /** |
| 130 | * SSAM_SDEV() - Initialize a &struct ssam_device_id as physical SSH device |
| 131 | * with the given parameters. |
| 132 | * @cat: Target category of the device. |
| 133 | * @tid: Target ID of the device. |
| 134 | * @iid: Instance ID of the device. |
| 135 | * @fun: Sub-function of the device. |
| 136 | * |
| 137 | * Initializes a &struct ssam_device_id with the given parameters in the SSH |
| 138 | * domain. See &struct ssam_device_uid for details regarding the parameters. |
| 139 | * The special values %SSAM_SSH_TID_ANY, %SSAM_SSH_IID_ANY, and |
| 140 | * %SSAM_SSH_FUN_ANY can be used to specify that matching should ignore target |
| 141 | * ID, instance ID, and/or sub-function, respectively. This macro initializes |
| 142 | * the ``match_flags`` field based on the given parameters. |
| 143 | * |
| 144 | * Note: The parameter @cat must be a valid &u8 value, the parameters @tid, |
| 145 | * @iid, and @fun must be either valid &u8 values or %SSAM_SSH_TID_ANY, |
| 146 | * %SSAM_SSH_IID_ANY, or %SSAM_SSH_FUN_ANY, respectively. Other non-&u8 values |
| 147 | * are not allowed. |
| 148 | */ |
| 149 | #define SSAM_SDEV(cat, tid, iid, fun) \ |
| 150 | SSAM_DEVICE(SSAM_DOMAIN_SERIALHUB, SSAM_SSH_TC_##cat, SSAM_SSH_TID_##tid, iid, fun) |
| 151 | |
| 152 | /* |
| 153 | * enum ssam_device_flags - Flags for SSAM client devices. |
| 154 | * @SSAM_DEVICE_HOT_REMOVED_BIT: |
| 155 | * The device has been hot-removed. Further communication with it may time |
| 156 | * out and should be avoided. |
| 157 | */ |
| 158 | enum ssam_device_flags { |
| 159 | SSAM_DEVICE_HOT_REMOVED_BIT = 0, |
| 160 | }; |
| 161 | |
| 162 | /** |
| 163 | * struct ssam_device - SSAM client device. |
| 164 | * @dev: Driver model representation of the device. |
| 165 | * @ctrl: SSAM controller managing this device. |
| 166 | * @uid: UID identifying the device. |
| 167 | * @flags: Device state flags, see &enum ssam_device_flags. |
| 168 | */ |
| 169 | struct ssam_device { |
| 170 | struct device dev; |
| 171 | struct ssam_controller *ctrl; |
| 172 | |
| 173 | struct ssam_device_uid uid; |
| 174 | |
| 175 | unsigned long flags; |
| 176 | }; |
| 177 | |
| 178 | /** |
| 179 | * struct ssam_device_driver - SSAM client device driver. |
| 180 | * @driver: Base driver model structure. |
| 181 | * @match_table: Match table specifying which devices the driver should bind to. |
| 182 | * @probe: Called when the driver is being bound to a device. |
| 183 | * @remove: Called when the driver is being unbound from the device. |
| 184 | */ |
| 185 | struct ssam_device_driver { |
| 186 | struct device_driver driver; |
| 187 | |
| 188 | const struct ssam_device_id *match_table; |
| 189 | |
| 190 | int (*probe)(struct ssam_device *sdev); |
| 191 | void (*remove)(struct ssam_device *sdev); |
| 192 | }; |
| 193 | |
| 194 | #ifdef CONFIG_SURFACE_AGGREGATOR_BUS |
| 195 | |
| 196 | extern const struct device_type ssam_device_type; |
| 197 | |
| 198 | /** |
| 199 | * is_ssam_device() - Check if the given device is a SSAM client device. |
| 200 | * @d: The device to test the type of. |
| 201 | * |
| 202 | * Return: Returns %true if the specified device is of type &struct |
| 203 | * ssam_device, i.e. the device type points to %ssam_device_type, and %false |
| 204 | * otherwise. |
| 205 | */ |
| 206 | static inline bool is_ssam_device(struct device *d) |
| 207 | { |
| 208 | return d->type == &ssam_device_type; |
| 209 | } |
| 210 | |
| 211 | #else /* CONFIG_SURFACE_AGGREGATOR_BUS */ |
| 212 | |
| 213 | static inline bool is_ssam_device(struct device *d) |
| 214 | { |
| 215 | return false; |
| 216 | } |
| 217 | |
| 218 | #endif /* CONFIG_SURFACE_AGGREGATOR_BUS */ |
| 219 | |
| 220 | /** |
| 221 | * to_ssam_device() - Casts the given device to a SSAM client device. |
| 222 | * @d: The device to cast. |
| 223 | * |
| 224 | * Casts the given &struct device to a &struct ssam_device. The caller has to |
| 225 | * ensure that the given device is actually enclosed in a &struct ssam_device, |
| 226 | * e.g. by calling is_ssam_device(). |
| 227 | * |
| 228 | * Return: Returns a pointer to the &struct ssam_device wrapping the given |
| 229 | * device @d. |
| 230 | */ |
| 231 | #define to_ssam_device(d) container_of_const(d, struct ssam_device, dev) |
| 232 | |
| 233 | /** |
| 234 | * to_ssam_device_driver() - Casts the given device driver to a SSAM client |
| 235 | * device driver. |
| 236 | * @d: The driver to cast. |
| 237 | * |
| 238 | * Casts the given &struct device_driver to a &struct ssam_device_driver. The |
| 239 | * caller has to ensure that the given driver is actually enclosed in a |
| 240 | * &struct ssam_device_driver. |
| 241 | * |
| 242 | * Return: Returns the pointer to the &struct ssam_device_driver wrapping the |
| 243 | * given device driver @d. |
| 244 | */ |
| 245 | #define to_ssam_device_driver(d) container_of_const(d, struct ssam_device_driver, driver) |
| 246 | |
| 247 | const struct ssam_device_id *ssam_device_id_match(const struct ssam_device_id *table, |
| 248 | const struct ssam_device_uid uid); |
| 249 | |
| 250 | const struct ssam_device_id *ssam_device_get_match(const struct ssam_device *dev); |
| 251 | |
| 252 | const void *ssam_device_get_match_data(const struct ssam_device *dev); |
| 253 | |
| 254 | struct ssam_device *ssam_device_alloc(struct ssam_controller *ctrl, |
| 255 | struct ssam_device_uid uid); |
| 256 | |
| 257 | int ssam_device_add(struct ssam_device *sdev); |
| 258 | void ssam_device_remove(struct ssam_device *sdev); |
| 259 | |
| 260 | /** |
| 261 | * ssam_device_mark_hot_removed() - Mark the given device as hot-removed. |
| 262 | * @sdev: The device to mark as hot-removed. |
| 263 | * |
| 264 | * Mark the device as having been hot-removed. This signals drivers using the |
| 265 | * device that communication with the device should be avoided and may lead to |
| 266 | * timeouts. |
| 267 | */ |
| 268 | static inline void ssam_device_mark_hot_removed(struct ssam_device *sdev) |
| 269 | { |
| 270 | dev_dbg(&sdev->dev, "marking device as hot-removed\n" ); |
| 271 | set_bit(nr: SSAM_DEVICE_HOT_REMOVED_BIT, addr: &sdev->flags); |
| 272 | } |
| 273 | |
| 274 | /** |
| 275 | * ssam_device_is_hot_removed() - Check if the given device has been |
| 276 | * hot-removed. |
| 277 | * @sdev: The device to check. |
| 278 | * |
| 279 | * Checks if the given device has been marked as hot-removed. See |
| 280 | * ssam_device_mark_hot_removed() for more details. |
| 281 | * |
| 282 | * Return: Returns ``true`` if the device has been marked as hot-removed. |
| 283 | */ |
| 284 | static inline bool ssam_device_is_hot_removed(struct ssam_device *sdev) |
| 285 | { |
| 286 | return test_bit(SSAM_DEVICE_HOT_REMOVED_BIT, &sdev->flags); |
| 287 | } |
| 288 | |
| 289 | /** |
| 290 | * ssam_device_get() - Increment reference count of SSAM client device. |
| 291 | * @sdev: The device to increment the reference count of. |
| 292 | * |
| 293 | * Increments the reference count of the given SSAM client device by |
| 294 | * incrementing the reference count of the enclosed &struct device via |
| 295 | * get_device(). |
| 296 | * |
| 297 | * See ssam_device_put() for the counter-part of this function. |
| 298 | * |
| 299 | * Return: Returns the device provided as input. |
| 300 | */ |
| 301 | static inline struct ssam_device *ssam_device_get(struct ssam_device *sdev) |
| 302 | { |
| 303 | return sdev ? to_ssam_device(get_device(&sdev->dev)) : NULL; |
| 304 | } |
| 305 | |
| 306 | /** |
| 307 | * ssam_device_put() - Decrement reference count of SSAM client device. |
| 308 | * @sdev: The device to decrement the reference count of. |
| 309 | * |
| 310 | * Decrements the reference count of the given SSAM client device by |
| 311 | * decrementing the reference count of the enclosed &struct device via |
| 312 | * put_device(). |
| 313 | * |
| 314 | * See ssam_device_get() for the counter-part of this function. |
| 315 | */ |
| 316 | static inline void ssam_device_put(struct ssam_device *sdev) |
| 317 | { |
| 318 | if (sdev) |
| 319 | put_device(dev: &sdev->dev); |
| 320 | } |
| 321 | |
| 322 | /** |
| 323 | * ssam_device_get_drvdata() - Get driver-data of SSAM client device. |
| 324 | * @sdev: The device to get the driver-data from. |
| 325 | * |
| 326 | * Return: Returns the driver-data of the given device, previously set via |
| 327 | * ssam_device_set_drvdata(). |
| 328 | */ |
| 329 | static inline void *ssam_device_get_drvdata(struct ssam_device *sdev) |
| 330 | { |
| 331 | return dev_get_drvdata(dev: &sdev->dev); |
| 332 | } |
| 333 | |
| 334 | /** |
| 335 | * ssam_device_set_drvdata() - Set driver-data of SSAM client device. |
| 336 | * @sdev: The device to set the driver-data of. |
| 337 | * @data: The data to set the device's driver-data pointer to. |
| 338 | */ |
| 339 | static inline void ssam_device_set_drvdata(struct ssam_device *sdev, void *data) |
| 340 | { |
| 341 | dev_set_drvdata(dev: &sdev->dev, data); |
| 342 | } |
| 343 | |
| 344 | int __ssam_device_driver_register(struct ssam_device_driver *d, struct module *o); |
| 345 | void ssam_device_driver_unregister(struct ssam_device_driver *d); |
| 346 | |
| 347 | /** |
| 348 | * ssam_device_driver_register() - Register a SSAM client device driver. |
| 349 | * @drv: The driver to register. |
| 350 | */ |
| 351 | #define ssam_device_driver_register(drv) \ |
| 352 | __ssam_device_driver_register(drv, THIS_MODULE) |
| 353 | |
| 354 | /** |
| 355 | * module_ssam_device_driver() - Helper macro for SSAM device driver |
| 356 | * registration. |
| 357 | * @drv: The driver managed by this module. |
| 358 | * |
| 359 | * Helper macro to register a SSAM device driver via module_init() and |
| 360 | * module_exit(). This macro may only be used once per module and replaces the |
| 361 | * aforementioned definitions. |
| 362 | */ |
| 363 | #define module_ssam_device_driver(drv) \ |
| 364 | module_driver(drv, ssam_device_driver_register, \ |
| 365 | ssam_device_driver_unregister) |
| 366 | |
| 367 | |
| 368 | /* -- Helpers for controller and hub devices. ------------------------------- */ |
| 369 | |
| 370 | #ifdef CONFIG_SURFACE_AGGREGATOR_BUS |
| 371 | |
| 372 | int __ssam_register_clients(struct device *parent, struct ssam_controller *ctrl, |
| 373 | struct fwnode_handle *node); |
| 374 | void ssam_remove_clients(struct device *dev); |
| 375 | |
| 376 | #else /* CONFIG_SURFACE_AGGREGATOR_BUS */ |
| 377 | |
| 378 | static inline int __ssam_register_clients(struct device *parent, struct ssam_controller *ctrl, |
| 379 | struct fwnode_handle *node) |
| 380 | { |
| 381 | return 0; |
| 382 | } |
| 383 | |
| 384 | static inline void ssam_remove_clients(struct device *dev) {} |
| 385 | |
| 386 | #endif /* CONFIG_SURFACE_AGGREGATOR_BUS */ |
| 387 | |
| 388 | /** |
| 389 | * ssam_register_clients() - Register all client devices defined under the |
| 390 | * given parent device. |
| 391 | * @dev: The parent device under which clients should be registered. |
| 392 | * @ctrl: The controller with which client should be registered. |
| 393 | * |
| 394 | * Register all clients that have via firmware nodes been defined as children |
| 395 | * of the given (parent) device. The respective child firmware nodes will be |
| 396 | * associated with the correspondingly created child devices. |
| 397 | * |
| 398 | * The given controller will be used to instantiate the new devices. See |
| 399 | * ssam_device_add() for details. |
| 400 | * |
| 401 | * Return: Returns zero on success, nonzero on failure. |
| 402 | */ |
| 403 | static inline int ssam_register_clients(struct device *dev, struct ssam_controller *ctrl) |
| 404 | { |
| 405 | return __ssam_register_clients(parent: dev, ctrl, dev_fwnode(dev)); |
| 406 | } |
| 407 | |
| 408 | /** |
| 409 | * ssam_device_register_clients() - Register all client devices defined under |
| 410 | * the given SSAM parent device. |
| 411 | * @sdev: The parent device under which clients should be registered. |
| 412 | * |
| 413 | * Register all clients that have via firmware nodes been defined as children |
| 414 | * of the given (parent) device. The respective child firmware nodes will be |
| 415 | * associated with the correspondingly created child devices. |
| 416 | * |
| 417 | * The controller used by the parent device will be used to instantiate the new |
| 418 | * devices. See ssam_device_add() for details. |
| 419 | * |
| 420 | * Return: Returns zero on success, nonzero on failure. |
| 421 | */ |
| 422 | static inline int ssam_device_register_clients(struct ssam_device *sdev) |
| 423 | { |
| 424 | return ssam_register_clients(dev: &sdev->dev, ctrl: sdev->ctrl); |
| 425 | } |
| 426 | |
| 427 | |
| 428 | /* -- Helpers for client-device requests. ----------------------------------- */ |
| 429 | |
| 430 | /** |
| 431 | * SSAM_DEFINE_SYNC_REQUEST_CL_N() - Define synchronous client-device SAM |
| 432 | * request function with neither argument nor return value. |
| 433 | * @name: Name of the generated function. |
| 434 | * @spec: Specification (&struct ssam_request_spec_md) defining the request. |
| 435 | * |
| 436 | * Defines a function executing the synchronous SAM request specified by |
| 437 | * @spec, with the request having neither argument nor return value. Device |
| 438 | * specifying parameters are not hard-coded, but instead are provided via the |
| 439 | * client device, specifically its UID, supplied when calling this function. |
| 440 | * The generated function takes care of setting up the request struct, buffer |
| 441 | * allocation, as well as execution of the request itself, returning once the |
| 442 | * request has been fully completed. The required transport buffer will be |
| 443 | * allocated on the stack. |
| 444 | * |
| 445 | * The generated function is defined as ``static int name(struct ssam_device |
| 446 | * *sdev)``, returning the status of the request, which is zero on success and |
| 447 | * negative on failure. The ``sdev`` parameter specifies both the target |
| 448 | * device of the request and by association the controller via which the |
| 449 | * request is sent. |
| 450 | * |
| 451 | * Refer to ssam_request_do_sync_onstack() for more details on the behavior of |
| 452 | * the generated function. |
| 453 | */ |
| 454 | #define SSAM_DEFINE_SYNC_REQUEST_CL_N(name, spec...) \ |
| 455 | SSAM_DEFINE_SYNC_REQUEST_MD_N(__raw_##name, spec) \ |
| 456 | static int name(struct ssam_device *sdev) \ |
| 457 | { \ |
| 458 | return __raw_##name(sdev->ctrl, sdev->uid.target, \ |
| 459 | sdev->uid.instance); \ |
| 460 | } |
| 461 | |
| 462 | /** |
| 463 | * SSAM_DEFINE_SYNC_REQUEST_CL_W() - Define synchronous client-device SAM |
| 464 | * request function with argument. |
| 465 | * @name: Name of the generated function. |
| 466 | * @atype: Type of the request's argument. |
| 467 | * @spec: Specification (&struct ssam_request_spec_md) defining the request. |
| 468 | * |
| 469 | * Defines a function executing the synchronous SAM request specified by |
| 470 | * @spec, with the request taking an argument of type @atype and having no |
| 471 | * return value. Device specifying parameters are not hard-coded, but instead |
| 472 | * are provided via the client device, specifically its UID, supplied when |
| 473 | * calling this function. The generated function takes care of setting up the |
| 474 | * request struct, buffer allocation, as well as execution of the request |
| 475 | * itself, returning once the request has been fully completed. The required |
| 476 | * transport buffer will be allocated on the stack. |
| 477 | * |
| 478 | * The generated function is defined as ``static int name(struct ssam_device |
| 479 | * *sdev, const atype *arg)``, returning the status of the request, which is |
| 480 | * zero on success and negative on failure. The ``sdev`` parameter specifies |
| 481 | * both the target device of the request and by association the controller via |
| 482 | * which the request is sent. The request's argument is specified via the |
| 483 | * ``arg`` pointer. |
| 484 | * |
| 485 | * Refer to ssam_request_do_sync_onstack() for more details on the behavior of |
| 486 | * the generated function. |
| 487 | */ |
| 488 | #define SSAM_DEFINE_SYNC_REQUEST_CL_W(name, atype, spec...) \ |
| 489 | SSAM_DEFINE_SYNC_REQUEST_MD_W(__raw_##name, atype, spec) \ |
| 490 | static int name(struct ssam_device *sdev, const atype *arg) \ |
| 491 | { \ |
| 492 | return __raw_##name(sdev->ctrl, sdev->uid.target, \ |
| 493 | sdev->uid.instance, arg); \ |
| 494 | } |
| 495 | |
| 496 | /** |
| 497 | * SSAM_DEFINE_SYNC_REQUEST_CL_R() - Define synchronous client-device SAM |
| 498 | * request function with return value. |
| 499 | * @name: Name of the generated function. |
| 500 | * @rtype: Type of the request's return value. |
| 501 | * @spec: Specification (&struct ssam_request_spec_md) defining the request. |
| 502 | * |
| 503 | * Defines a function executing the synchronous SAM request specified by |
| 504 | * @spec, with the request taking no argument but having a return value of |
| 505 | * type @rtype. Device specifying parameters are not hard-coded, but instead |
| 506 | * are provided via the client device, specifically its UID, supplied when |
| 507 | * calling this function. The generated function takes care of setting up the |
| 508 | * request struct, buffer allocation, as well as execution of the request |
| 509 | * itself, returning once the request has been fully completed. The required |
| 510 | * transport buffer will be allocated on the stack. |
| 511 | * |
| 512 | * The generated function is defined as ``static int name(struct ssam_device |
| 513 | * *sdev, rtype *ret)``, returning the status of the request, which is zero on |
| 514 | * success and negative on failure. The ``sdev`` parameter specifies both the |
| 515 | * target device of the request and by association the controller via which |
| 516 | * the request is sent. The request's return value is written to the memory |
| 517 | * pointed to by the ``ret`` parameter. |
| 518 | * |
| 519 | * Refer to ssam_request_do_sync_onstack() for more details on the behavior of |
| 520 | * the generated function. |
| 521 | */ |
| 522 | #define SSAM_DEFINE_SYNC_REQUEST_CL_R(name, rtype, spec...) \ |
| 523 | SSAM_DEFINE_SYNC_REQUEST_MD_R(__raw_##name, rtype, spec) \ |
| 524 | static int name(struct ssam_device *sdev, rtype *ret) \ |
| 525 | { \ |
| 526 | return __raw_##name(sdev->ctrl, sdev->uid.target, \ |
| 527 | sdev->uid.instance, ret); \ |
| 528 | } |
| 529 | |
| 530 | /** |
| 531 | * SSAM_DEFINE_SYNC_REQUEST_CL_WR() - Define synchronous client-device SAM |
| 532 | * request function with argument and return value. |
| 533 | * @name: Name of the generated function. |
| 534 | * @atype: Type of the request's argument. |
| 535 | * @rtype: Type of the request's return value. |
| 536 | * @spec: Specification (&struct ssam_request_spec_md) defining the request. |
| 537 | * |
| 538 | * Defines a function executing the synchronous SAM request specified by @spec, |
| 539 | * with the request taking an argument of type @atype and having a return value |
| 540 | * of type @rtype. Device specifying parameters are not hard-coded, but instead |
| 541 | * are provided via the client device, specifically its UID, supplied when |
| 542 | * calling this function. The generated function takes care of setting up the |
| 543 | * request struct, buffer allocation, as well as execution of the request |
| 544 | * itself, returning once the request has been fully completed. The required |
| 545 | * transport buffer will be allocated on the stack. |
| 546 | * |
| 547 | * The generated function is defined as ``static int name(struct ssam_device |
| 548 | * *sdev, const atype *arg, rtype *ret)``, returning the status of the request, |
| 549 | * which is zero on success and negative on failure. The ``sdev`` parameter |
| 550 | * specifies both the target device of the request and by association the |
| 551 | * controller via which the request is sent. The request's argument is |
| 552 | * specified via the ``arg`` pointer. The request's return value is written to |
| 553 | * the memory pointed to by the ``ret`` parameter. |
| 554 | * |
| 555 | * Refer to ssam_request_do_sync_onstack() for more details on the behavior of |
| 556 | * the generated function. |
| 557 | */ |
| 558 | #define SSAM_DEFINE_SYNC_REQUEST_CL_WR(name, atype, rtype, spec...) \ |
| 559 | SSAM_DEFINE_SYNC_REQUEST_MD_WR(__raw_##name, atype, rtype, spec) \ |
| 560 | static int name(struct ssam_device *sdev, const atype *arg, rtype *ret) \ |
| 561 | { \ |
| 562 | return __raw_##name(sdev->ctrl, sdev->uid.target, \ |
| 563 | sdev->uid.instance, arg, ret); \ |
| 564 | } |
| 565 | |
| 566 | |
| 567 | /* -- Helpers for client-device notifiers. ---------------------------------- */ |
| 568 | |
| 569 | /** |
| 570 | * ssam_device_notifier_register() - Register an event notifier for the |
| 571 | * specified client device. |
| 572 | * @sdev: The device the notifier should be registered on. |
| 573 | * @n: The event notifier to register. |
| 574 | * |
| 575 | * Register an event notifier. Increment the usage counter of the associated |
| 576 | * SAM event if the notifier is not marked as an observer. If the event is not |
| 577 | * marked as an observer and is currently not enabled, it will be enabled |
| 578 | * during this call. If the notifier is marked as an observer, no attempt will |
| 579 | * be made at enabling any event and no reference count will be modified. |
| 580 | * |
| 581 | * Notifiers marked as observers do not need to be associated with one specific |
| 582 | * event, i.e. as long as no event matching is performed, only the event target |
| 583 | * category needs to be set. |
| 584 | * |
| 585 | * Return: Returns zero on success, %-ENOSPC if there have already been |
| 586 | * %INT_MAX notifiers for the event ID/type associated with the notifier block |
| 587 | * registered, %-ENOMEM if the corresponding event entry could not be |
| 588 | * allocated, %-ENODEV if the device is marked as hot-removed. If this is the |
| 589 | * first time that a notifier block is registered for the specific associated |
| 590 | * event, returns the status of the event-enable EC-command. |
| 591 | */ |
| 592 | static inline int ssam_device_notifier_register(struct ssam_device *sdev, |
| 593 | struct ssam_event_notifier *n) |
| 594 | { |
| 595 | /* |
| 596 | * Note that this check does not provide any guarantees whatsoever as |
| 597 | * hot-removal could happen at any point and we can't protect against |
| 598 | * it. Nevertheless, if we can detect hot-removal, bail early to avoid |
| 599 | * communication timeouts. |
| 600 | */ |
| 601 | if (ssam_device_is_hot_removed(sdev)) |
| 602 | return -ENODEV; |
| 603 | |
| 604 | return ssam_notifier_register(ctrl: sdev->ctrl, n); |
| 605 | } |
| 606 | |
| 607 | /** |
| 608 | * ssam_device_notifier_unregister() - Unregister an event notifier for the |
| 609 | * specified client device. |
| 610 | * @sdev: The device the notifier has been registered on. |
| 611 | * @n: The event notifier to unregister. |
| 612 | * |
| 613 | * Unregister an event notifier. Decrement the usage counter of the associated |
| 614 | * SAM event if the notifier is not marked as an observer. If the usage counter |
| 615 | * reaches zero, the event will be disabled. |
| 616 | * |
| 617 | * In case the device has been marked as hot-removed, the event will not be |
| 618 | * disabled on the EC, as in those cases any attempt at doing so may time out. |
| 619 | * |
| 620 | * Return: Returns zero on success, %-ENOENT if the given notifier block has |
| 621 | * not been registered on the controller. If the given notifier block was the |
| 622 | * last one associated with its specific event, returns the status of the |
| 623 | * event-disable EC-command. |
| 624 | */ |
| 625 | static inline int ssam_device_notifier_unregister(struct ssam_device *sdev, |
| 626 | struct ssam_event_notifier *n) |
| 627 | { |
| 628 | return __ssam_notifier_unregister(ctrl: sdev->ctrl, n, |
| 629 | disable: !ssam_device_is_hot_removed(sdev)); |
| 630 | } |
| 631 | |
| 632 | #endif /* _LINUX_SURFACE_AGGREGATOR_DEVICE_H */ |
| 633 | |