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