text: /*
   * Copyright (c) 2015 Intel Corporation.
   *
   * SPDX-License-Identifier: Apache-2.0
   */
  
  #ifndef ZEPHYR_INCLUDE_DEVICE_H_
  #define ZEPHYR_INCLUDE_DEVICE_H_
  
  /**
   * @brief Device Driver APIs
   * @defgroup io_interfaces Device Driver APIs
   * @{
   * @}
   */
  /**
   * @brief Miscellaneous Drivers APIs
   * @defgroup misc_interfaces Miscellaneous Drivers APIs
   * @ingroup io_interfaces
   * @{
   * @}
   */
  /**
   * @brief Device Model APIs
   * @defgroup device_model Device Model APIs
   * @{
   */
  
  #include <zephyr/init.h>
  #include <zephyr/linker/sections.h>
  #include <zephyr/sys/device_mmio.h>
  #include <zephyr/sys/util.h>
  
  #ifdef __cplusplus
  extern "C" {
  #endif
  
  /**
   * @brief Type used to represent a "handle" for a device.
   *
   * Every struct device has an associated handle. You can get a pointer
   * to a device structure from its handle and vice versa, but the
   * handle uses less space than a pointer. The device.h API mainly uses
   * handles to store lists of multiple devices in a compact way.
   *
   * The extreme values and zero have special significance. Negative
   * values identify functionality that does not correspond to a Zephyr
   * device, such as the system clock or a SYS_INIT() function.
   *
   * @see device_handle_get()
   * @see device_from_handle()
   */
  typedef int16_t device_handle_t;
  
  /** @brief Flag value used in lists of device handles to separate
   * distinct groups.
   *
   * This is the minimum value for the device_handle_t type.
   */
  #define DEVICE_HANDLE_SEP INT16_MIN
  
  /** @brief Flag value used in lists of device handles to indicate the
   * end of the list.
   *
   * This is the maximum value for the device_handle_t type.
   */
  #define DEVICE_HANDLE_ENDS INT16_MAX
  
  /** @brief Flag value used to identify an unknown device. */
  #define DEVICE_HANDLE_NULL 0
  
  #define Z_DEVICE_MAX_NAME_LEN	48
  
  /**
   * @def DEVICE_NAME_GET
   *
   * @brief Expands to the name of a global device object.
   *
   * @details Return the full name of a device object symbol created by
   * DEVICE_DEFINE(), using the dev_name provided to DEVICE_DEFINE().
   * This is the name of the global variable storing the device
   * structure, not a pointer to the string in the device's @p name
   * field.
   *
   * It is meant to be used for declaring extern symbols pointing to device
   * objects before using the DEVICE_GET macro to get the device object.
   *
   * This macro is normally only useful within device driver source
   * code. In other situations, you are probably looking for
   * device_get_binding().
   *
   * @param name The same @p dev_name token given to DEVICE_DEFINE()
   *
   * @return The full name of the device object defined by DEVICE_DEFINE()
   */
  #define DEVICE_NAME_GET(name) _CONCAT(__device_, name)
  
  /**
   * @def SYS_DEVICE_DEFINE
   *
   * @brief Run an initialization function at boot at specified priority.
   *
   * @deprecated Use SYS_INIT() instead.
   *
   * @param drv_name A string name for the pseudo-device (unused).
   * @param init_fn Pointer to the function which should run at boot time.
   * @param level Initialization level to run the function in.
   * @param prio Function's priority within its initialization level.
   */
  #define SYS_DEVICE_DEFINE(drv_name, init_fn, level, prio)		\
  	__DEPRECATED_MACRO SYS_INIT(init_fn, level, prio)
  
  /* Node paths can exceed the maximum size supported by device_get_binding() in user mode,
   * so synthesize a unique dev_name from the devicetree node.
   *
   * The ordinal used in this name can be mapped to the path by
   * examining zephyr/include/generated/device_extern.h header. If the
   * format of this conversion changes, gen_defines should be updated to
   * match it.
   */
  #define Z_DEVICE_DT_DEV_NAME(node_id) _CONCAT(dts_ord_, DT_DEP_ORD(node_id))
  
  /* Synthesize a unique name for the device state associated with
   * dev_name.
   */
  #define Z_DEVICE_STATE_NAME(dev_name) _CONCAT(__devstate_, dev_name)
  
  /**
   * @brief Utility macro to define and initialize the device state.
   *
   * @param node_id Devicetree node id of the device.
   * @param dev_name Device name.
   */
  #define Z_DEVICE_STATE_DEFINE(node_id, dev_name)			\
  	static struct device_state Z_DEVICE_STATE_NAME(dev_name)	\
  	__attribute__((__section__(".z_devstate")));
  
  /**
   * @def DEVICE_DEFINE
   *
   * @brief Create a device object and set it up for boot time initialization.
   *
   * @details This macro defines a <tt>struct device</tt> that is
   * automatically configured by the kernel during system
   * initialization. This macro should only be used when the device is
   * not being allocated from a devicetree node. If you are allocating a
   * device from a devicetree node, use DEVICE_DT_DEFINE() or
   * DEVICE_DT_INST_DEFINE() instead.
   *
   * @param dev_name A unique token which is used in the name of the
   * global device structure as a C identifier.
   *
   * @param drv_name A string name for the device, which will be stored
   * in the device structure's @p name field. This name can be used to
   * look up the device with device_get_binding(). This must be less
   * than Z_DEVICE_MAX_NAME_LEN characters (including terminating NUL)
   * in order to be looked up from user mode.
   *
   * @param init_fn Pointer to the device's initialization function,
   * which will be run by the kernel during system initialization.
   *
   * @param pm_device Pointer to the device's power management
   * resources, a <tt>struct pm_device</tt>, which will be stored in the
   * device structure's @p pm field. Use NULL if the device does not use
   * PM.
   *
   * @param data_ptr Pointer to the device's private mutable data, which
   * will be stored in the device structure's @p data field.
   *
   * @param cfg_ptr Pointer to the device's private constant data, which
   * will be stored in the device structure's @p config field.
   *
   * @param level The device's initialization level. See SYS_INIT() for
   * details.
   *
   * @param prio The device's priority within its initialization level.
   * See SYS_INIT() for details.
   *
   * @param api_ptr Pointer to the device's API structure. Can be NULL.
   */
  #define DEVICE_DEFINE(dev_name, drv_name, init_fn, pm_device,		\
  		      data_ptr, cfg_ptr, level, prio, api_ptr)		\
  	Z_DEVICE_STATE_DEFINE(DT_INVALID_NODE, dev_name) \
  	Z_DEVICE_DEFINE(DT_INVALID_NODE, dev_name, drv_name, init_fn,	\
  			pm_device,					\
  			data_ptr, cfg_ptr, level, prio, api_ptr,	\
  			&Z_DEVICE_STATE_NAME(dev_name))
  
  /**
   * @def DEVICE_DT_NAME
   *
   * @brief Return a string name for a devicetree node.
   *
   * @details This macro returns a string literal usable as a device's
   * @p name field from a devicetree node identifier.
   *
   * @param node_id The devicetree node identifier.
   *
   * @return The value of the node's "label" property, if it has one.
   * Otherwise, the node's full name in "node-name@@unit-address" form.
   */
  #define DEVICE_DT_NAME(node_id) \
  	DT_PROP_OR(node_id, label, DT_NODE_FULL_NAME(node_id))
  
  /**
   * @def DEVICE_DT_DEFINE
   *
   * @brief Create a device object from a devicetree node identifier and
   * set it up for boot time initialization.
   *
   * @details This macro defines a <tt>struct device</tt> that is
   * automatically configured by the kernel during system
   * initialization. The global device object's name as a C identifier
   * is derived from the node's dependency ordinal. The device
   * structure's @p name field is set to
   * <tt>DEVICE_DT_NAME(node_id)</tt>.
   *
   * The device is declared with extern visibility, so a pointer to a
   * global device object can be obtained with
   * <tt>DEVICE_DT_GET(node_id)</tt> from any source file that includes
   * device.h. Before using the pointer, the referenced object should be
   * checked using device_is_ready().
   *
   * @param node_id The devicetree node identifier.
   *
   * @param init_fn Pointer to the device's initialization function,
   * which will be run by the kernel during system initialization.
   *
   * @param pm_device Pointer to the device's power management
   * resources, a <tt>struct pm_device</tt>, which will be stored in the
   * device structure's @p pm field. Use NULL if the device does not use
   * PM.
   *
   * @param data_ptr Pointer to the device's private mutable data, which
   * will be stored in the device structure's @p data field.
   *
   * @param cfg_ptr Pointer to the device's private constant data, which
   * will be stored in the device structure's @p config field.
   *
   * @param level The device's initialization level. See SYS_INIT() for
   * details.
   *
   * @param prio The device's priority within its initialization level.
   * See SYS_INIT() for details.
   *
   * @param api_ptr Pointer to the device's API structure. Can be NULL.
   */
  #define DEVICE_DT_DEFINE(node_id, init_fn, pm_device,			\
  			 data_ptr, cfg_ptr, level, prio,		\
  			 api_ptr, ...)					\
  	Z_DEVICE_STATE_DEFINE(node_id, Z_DEVICE_DT_DEV_NAME(node_id)) \
  	Z_DEVICE_DEFINE(node_id, Z_DEVICE_DT_DEV_NAME(node_id),		\
  			DEVICE_DT_NAME(node_id), init_fn,		\
  			pm_device,					\
  			data_ptr, cfg_ptr, level, prio,			\
  			api_ptr,					\
  			&Z_DEVICE_STATE_NAME(Z_DEVICE_DT_DEV_NAME(node_id)),	\
  			__VA_ARGS__)
  
  /**
   * @def DEVICE_DT_INST_DEFINE
   *
   * @brief Like DEVICE_DT_DEFINE(), but uses an instance of a
   * DT_DRV_COMPAT compatible instead of a node identifier.
   *
   * @param inst instance number. The @p node_id argument to
   * DEVICE_DT_DEFINE is set to <tt>DT_DRV_INST(inst)</tt>.
   *
   * @param ... other parameters as expected by DEVICE_DT_DEFINE.
   */
  #define DEVICE_DT_INST_DEFINE(inst, ...) \
  	DEVICE_DT_DEFINE(DT_DRV_INST(inst), __VA_ARGS__)
  
  /**
   * @def DEVICE_DT_NAME_GET
   *
   * @brief The name of the global device object for @p node_id
   *
   * @details Returns the name of the global device structure as a C
   * identifier. The device must be allocated using DEVICE_DT_DEFINE()
   * or DEVICE_DT_INST_DEFINE() for this to work.
   *
   * This macro is normally only useful within device driver source
   * code. In other situations, you are probably looking for
   * DEVICE_DT_GET().
   *
   * @param node_id Devicetree node identifier
   *
   * @return The name of the device object as a C identifier
   */
  #define DEVICE_DT_NAME_GET(node_id) DEVICE_NAME_GET(Z_DEVICE_DT_DEV_NAME(node_id))
  
  /**
   * @def DEVICE_DT_GET
   *
   * @brief Get a <tt>const struct device*</tt> from a devicetree node
   * identifier
   *
   * @details Returns a pointer to a device object created from a
   * devicetree node, if any device was allocated by a driver.
   *
   * If no such device was allocated, this will fail at linker time. If
   * you get an error that looks like <tt>undefined reference to
   * __device_dts_ord_<N></tt>, that is what happened. Check to make
   * sure your device driver is being compiled, usually by enabling the
   * Kconfig options it requires.
   *
   * @param node_id A devicetree node identifier
   * @return A pointer to the device object created for that node
   */
  #define DEVICE_DT_GET(node_id) (&DEVICE_DT_NAME_GET(node_id))
  
  /** @def DEVICE_DT_INST_GET
   *
   * @brief Get a <tt>const struct device*</tt> for an instance of a
   *        DT_DRV_COMPAT compatible
   *
   * @details This is equivalent to <tt>DEVICE_DT_GET(DT_DRV_INST(inst))</tt>.
   *
   * @param inst DT_DRV_COMPAT instance number
   * @return A pointer to the device object created for that instance
   */
  #define DEVICE_DT_INST_GET(inst) DEVICE_DT_GET(DT_DRV_INST(inst))
  
  /**
   * @def DEVICE_DT_GET_ANY
   *
   * @brief Get a <tt>const struct device*</tt> from a devicetree compatible
   *
   * If an enabled devicetree node has the given compatible and a device
   * object was created from it, this returns a pointer to that device.
   *
   * If there no such devices, this returns NULL.
   *
   * If there are multiple, this returns an arbitrary one.
   *
   * If this returns non-NULL, the device must be checked for readiness
   * before use, e.g. with device_is_ready().
   *
   * @param compat lowercase-and-underscores devicetree compatible
   * @return a pointer to a device, or NULL
   */
  #define DEVICE_DT_GET_ANY(compat)					    \
  	COND_CODE_1(DT_HAS_COMPAT_STATUS_OKAY(compat),			    \
  		    (DEVICE_DT_GET(DT_COMPAT_GET_ANY_STATUS_OKAY(compat))), \
  		    (NULL))
  
  /**
   * @def DEVICE_DT_GET_ONE
   *
   * @brief Get a <tt>const struct device*</tt> from a devicetree compatible
   *
   * @details If an enabled devicetree node has the given compatible and
   * a device object was created from it, this returns a pointer to that
   * device.
   *
   * If there no such devices, this will fail at compile time.
   *
   * If there are multiple, this returns an arbitrary one.
   *
   * If this returns non-NULL, the device must be checked for readiness
   * before use, e.g. with device_is_ready().
   *
   * @param compat lowercase-and-underscores devicetree compatible
   * @return a pointer to a device
   */
  #define DEVICE_DT_GET_ONE(compat)					    \
  	COND_CODE_1(DT_HAS_COMPAT_STATUS_OKAY(compat),			    \
  		    (DEVICE_DT_GET(DT_COMPAT_GET_ANY_STATUS_OKAY(compat))), \
  		    (ZERO_OR_COMPILE_ERROR(0)))
  
  /**
   * @def DEVICE_DT_GET_OR_NULL
   *
   * @brief Utility macro to obtain an optional reference to a device.
   *
   * @details If the node identifier refers to a node with status
   * "okay", this returns <tt>DEVICE_DT_GET(node_id)</tt>. Otherwise, it
   * returns NULL.
   *
   * @param node_id devicetree node identifier
   *
   * @return a <tt>const struct device*</tt> for the node identifier,
   * which may be NULL.
   */
  #define DEVICE_DT_GET_OR_NULL(node_id)					\
  	COND_CODE_1(DT_NODE_HAS_STATUS(node_id, okay),			\
  		    (DEVICE_DT_GET(node_id)), (NULL))
  
  /**
   * @def DEVICE_GET
   *
   * @brief Obtain a pointer to a device object by name
   *
   * @details Return the address of a device object created by
   * DEVICE_DEFINE(), using the dev_name provided to DEVICE_DEFINE().
   *
   * @param name The same as dev_name provided to DEVICE_DEFINE()
   *
   * @return A pointer to the device object created by DEVICE_DEFINE()
   */
  #define DEVICE_GET(name) (&DEVICE_NAME_GET(name))
  
  /** @def DEVICE_DECLARE
   *
   * @brief Declare a static device object
   *
   * This macro can be used at the top-level to declare a device, such
   * that DEVICE_GET() may be used before the full declaration in
   * DEVICE_DEFINE().
   *
   * This is often useful when configuring interrupts statically in a
   * device's init or per-instance config function, as the init function
   * itself is required by DEVICE_DEFINE() and use of DEVICE_GET()
   * inside it creates a circular dependency.
   *
   * @param name Device name
   */
  #define DEVICE_DECLARE(name) static const struct device DEVICE_NAME_GET(name)
  
  /**
   * @brief Runtime device dynamic structure (in RAM) per driver instance
   *
   * Fields in this are expected to be default-initialized to zero. The
   * kernel driver infrastructure and driver access functions are
   * responsible for ensuring that any non-zero initialization is done
   * before they are accessed.
   */
  struct device_state {
  	/** Non-negative result of initializing the device.
  	 *
  	 * The absolute value returned when the device initialization
  	 * function was invoked, or `UINT8_MAX` if the value exceeds
  	 * an 8-bit integer. If initialized is also set, a zero value
  	 * indicates initialization succeeded.
  	 */
  	unsigned int init_res : 8;
  
  	/** Indicates the device initialization function has been
  	 * invoked.
  	 */
  	bool initialized : 1;
  };
  
  struct pm_device;
  
  #ifdef CONFIG_HAS_DYNAMIC_DEVICE_HANDLES
  #define Z_DEVICE_HANDLES_CONST
  #else
  #define Z_DEVICE_HANDLES_CONST const
  #endif
  
  /**
   * @brief Runtime device structure (in ROM) per driver instance
   */
  struct device {
  	/** Name of the device instance */
  	const char *name;
  	/** Address of device instance config information */
  	const void *config;
  	/** Address of the API structure exposed by the device instance */
  	const void *api;
  	/** Address of the common device state */
  	struct device_state * const state;
  	/** Address of the device instance private data */
  	void * const data;
  	/** optional pointer to handles associated with the device.
  	 *
  	 * This encodes a sequence of sets of device handles that have
  	 * some relationship to this node. The individual sets are
  	 * extracted with dedicated API, such as
  	 * device_required_handles_get().
  	 */
  	Z_DEVICE_HANDLES_CONST device_handle_t * const handles;
  
  #ifdef CONFIG_PM_DEVICE
  	/** Reference to the device PM resources. */
  	struct pm_device * const pm;
  #endif
  };
  
  /**
   * @brief Get the handle for a given device
   *
   * @param dev the device for which a handle is desired.
   *
   * @return the handle for the device, or DEVICE_HANDLE_NULL if the
   * device does not have an associated handle.
   */
  static inline device_handle_t
  device_handle_get(const struct device *dev)
  {
  	device_handle_t ret = DEVICE_HANDLE_NULL;
  	extern const struct device __device_start[];
  
  	/* TODO: If/when devices can be constructed that are not part of the
  	 * fixed sequence we'll need another solution.
  	 */
  	if (dev != NULL) {
  		ret = 1 + (device_handle_t)(dev - __device_start);
  	}
  
  	return ret;
  }
  
  /**
   * @brief Get the device corresponding to a handle.
   *
   * @param dev_handle the device handle
   *
   * @return the device that has that handle, or a null pointer if @p
   * dev_handle does not identify a device.
   */
  static inline const struct device *
  device_from_handle(device_handle_t dev_handle)
  {
  	extern const struct device __device_start[];
  	extern const struct device __device_end[];
  	const struct device *dev = NULL;
  	size_t numdev = __device_end - __device_start;
  
  	if ((dev_handle > 0) && ((size_t)dev_handle <= numdev)) {
  		dev = &__device_start[dev_handle - 1];
  	}
  
  	return dev;
  }
  
  /**
   * @brief Prototype for functions used when iterating over a set of devices.
   *
   * Such a function may be used in API that identifies a set of devices and
   * provides a visitor API supporting caller-specific interaction with each
   * device in the set.
   *
   * The visit is said to succeed if the visitor returns a non-negative value.
   *
   * @param dev a device in the set being iterated
   *
   * @param context state used to support the visitor function
   *
   * @return A non-negative number to allow walking to continue, and a negative
   * error code to case the iteration to stop.
   *
   * @see device_required_foreach()
   * @see device_supported_foreach()
   */
  typedef int (*device_visitor_callback_t)(const struct device *dev, void *context);
  
  /**
   * @brief Get the device handles for devicetree dependencies of this device.
   *
   * This function returns a pointer to an array of device handles. The
   * length of the array is stored in the @p count parameter.
   *
   * The array contains a handle for each device that @p dev requires
   * directly, as determined from the devicetree. This does not include
   * transitive dependencies; you must recursively determine those.
   *
   * @param dev the device for which dependencies are desired.
   *
   * @param count pointer to where this function should store the length
   * of the returned array. No value is stored if the call returns a
   * null pointer. The value may be set to zero if the device has no
   * devicetree dependencies.
   *
   * @return a pointer to a sequence of @p *count device handles, or a null
   * pointer if @p dev does not have any dependency data.
   */
  static inline const device_handle_t *
  device_required_handles_get(const struct device *dev,
  			    size_t *count)
  {
  	const device_handle_t *rv = dev->handles;
  
  	if (rv != NULL) {
  		size_t i = 0;
  
  		while ((rv[i] != DEVICE_HANDLE_ENDS)
  		       && (rv[i] != DEVICE_HANDLE_SEP)) {
  			++i;
  		}
  		*count = i;
  	}
  
  	return rv;
  }
  
  /**
   * @brief Get the set of handles that this device supports.
   *
   * This function returns a pointer to an array of device handles. The
   * length of the array is stored in the @p count parameter.
   *
   * The array contains a handle for each device that @p dev "supports"
   * -- that is, devices that require @p dev directly -- as determined
   * from the devicetree. This does not include transitive dependencies;
   * you must recursively determine those.
   *
   * @param dev the device for which supports are desired.
   *
   * @param count pointer to where this function should store the length
   * of the returned array. No value is stored if the call returns a
   * null pointer. The value may be set to zero if nothing in the
   * devicetree depends on @p dev.
   *
   * @return a pointer to a sequence of @p *count device handles, or a null
   * pointer if @p dev does not have any dependency data.
   */
  static inline const device_handle_t *
  device_supported_handles_get(const struct device *dev,
  			     size_t *count)
  {
  	const device_handle_t *rv = dev->handles;
  	size_t region = 0;
  	size_t i = 0;
  
  	if (rv != NULL) {
  		/* Fast forward to supporting devices */
  		while (region != 2) {
  			if (*rv == DEVICE_HANDLE_SEP) {
  				region++;
  			}
  			rv++;
  		}
  		/* Count supporting devices */
  		while (rv[i] != DEVICE_HANDLE_ENDS) {
  			++i;
  		}
  		*count = i;
  	}
  
  	return rv;
  }
  
  /**
   * @brief Visit every device that @p dev directly requires.
   *
   * Zephyr maintains information about which devices are directly required by
   * another device; for example an I2C-based sensor driver will require an I2C
   * controller for communication. Required devices can derive from
   * statically-defined devicetree relationships or dependencies registered
   * at runtime.
   *
   * This API supports operating on the set of required devices. Example uses
   * include making sure required devices are ready before the requiring device
   * is used, and releasing them when the requiring device is no longer needed.
   *
   * There is no guarantee on the order in which required devices are visited.
   *
   * If the @p visitor function returns a negative value iteration is halted,
   * and the returned value from the visitor is returned from this function.
   *
   * @note This API is not available to unprivileged threads.
   *
   * @param dev a device of interest. The devices that this device depends on
   * will be used as the set of devices to visit. This parameter must not be
   * null.
   *
   * @param visitor_cb the function that should be invoked on each device in the
   * dependency set. This parameter must not be null.
   *
   * @param context state that is passed through to the visitor function. This
   * parameter may be null if @p visitor tolerates a null @p context.
   *
   * @return The number of devices that were visited if all visits succeed, or
   * the negative value returned from the first visit that did not succeed.
   */
  int device_required_foreach(const struct device *dev,
  			  device_visitor_callback_t visitor_cb,
  			  void *context);
  
  /**
   * @brief Visit every device that @p dev directly supports.
   *
   * Zephyr maintains information about which devices are directly supported by
   * another device; for example an I2C controller will support an I2C-based
   * sensor driver. Supported devices can derive from statically-defined
   * devicetree relationships.
   *
   * This API supports operating on the set of supported devices. Example uses
   * include iterating over the devices connected to a regulator when it is
   * powered on.
   *
   * There is no guarantee on the order in which required devices are visited.
   *
   * If the @p visitor function returns a negative value iteration is halted,
   * and the returned value from the visitor is returned from this function.
   *
   * @note This API is not available to unprivileged threads.
   *
   * @param dev a device of interest. The devices that this device supports
   * will be used as the set of devices to visit. This parameter must not be
   * null.
   *
   * @param visitor_cb the function that should be invoked on each device in the
   * support set. This parameter must not be null.
   *
   * @param context state that is passed through to the visitor function. This
   * parameter may be null if @p visitor tolerates a null @p context.
   *
   * @return The number of devices that were visited if all visits succeed, or
   * the negative value returned from the first visit that did not succeed.
   */
  int device_supported_foreach(const struct device *dev,
  			     device_visitor_callback_t visitor_cb,
  			     void *context);
  
  /**
   * @brief Get a <tt>const struct device*</tt> from its @p name field
   *
   * @details This function iterates through the devices on the system.
   * If a device with the given @p name field is found, and that device
   * initialized successfully at boot time, this function returns a
   * pointer to the device.
   *
   * If no device has the given name, this function returns NULL.
   *
   * This function also returns NULL when a device is found, but it
   * failed to initialize successfully at boot time. (To troubleshoot
   * this case, set a breakpoint on your device driver's initialization
   * function.)
   *
   * @param name device name to search for. A null pointer, or a pointer
   * to an empty string, will cause NULL to be returned.
   *
   * @return pointer to device structure with the given name; NULL if
   * the device is not found or if the device with that name's
   * initialization function failed.
   */
  __syscall const struct device *device_get_binding(const char *name);
  
  /** @brief Get access to the static array of static devices.
   *
   * @param devices where to store the pointer to the array of
   * statically allocated devices. The array must not be mutated
   * through this pointer.
   *
   * @return the number of statically allocated devices.
   */
  size_t z_device_get_all_static(const struct device * *devices);
  
  /**
   * @brief Verify that a device is ready for use.
   *
   * This is the implementation underlying device_is_ready(), without the overhead
   * of a syscall wrapper.
   *
   * @param dev pointer to the device in question.
   *
   * @retval true If the device is ready for use.
   * @retval false If the device is not ready for use or if a NULL device pointer
   * is passed as argument.
   *
   * @see device_is_ready()
   */
  bool z_device_is_ready(const struct device *dev);
  
  /** @brief Verify that a device is ready for use.
   *
   * Indicates whether the provided device pointer is for a device known to be
   * in a state where it can be used with its standard API.
   *
   * This can be used with device pointers captured from DEVICE_DT_GET(), which
   * does not include the readiness checks of device_get_binding(). At minimum
   * this means that the device has been successfully initialized.
   *
   * @param dev pointer to the device in question.
   *
   * @retval true If the device is ready for use.
   * @retval false If the device is not ready for use or if a NULL device pointer
   * is passed as argument.
   */
  __syscall bool device_is_ready(const struct device *dev);
  
  static inline bool z_impl_device_is_ready(const struct device *dev)
  {
  	return z_device_is_ready(dev);
  }
  
  /**
   * @brief Determine whether a device is ready for use
   *
   * This is equivalent to device_usable_check(), without the overhead of a
   * syscall wrapper.
   *
   * @deprecated Use z_device_is_ready() instead.
   *
   * @param dev Device instance.
   *
   * @retval 0 If device is usable.
   * @retval -ENODEV If device is not usable.
   */
  __deprecated static inline int z_device_usable_check(const struct device *dev)
  {
  	return z_device_is_ready(dev) ? 0 : -ENODEV;
  }
  
  /**
   * @brief Determine whether a device is ready for use
   *
   * @deprecated Use device_is_ready() instead.
   *
   * @param dev Device instance.
   *
   * @retval 0 If device is usable.
   * @retval -ENODEV If device is not usable.
   */
  __deprecated static inline int device_usable_check(const struct device *dev)
  {
  	return device_is_ready(dev) ? 0 : -ENODEV;
  }
  
  /**
   * @}
   */
  
  /* Synthesize the name of the object that holds device ordinal and
   * dependency data. If the object doesn't come from a devicetree
   * node, use dev_name.
   */
  #define Z_DEVICE_HANDLE_NAME(node_id, dev_name)				\
  	_CONCAT(__devicehdl_,						\
  		COND_CODE_1(DT_NODE_EXISTS(node_id),			\
  			    (node_id),					\
  			    (dev_name)))
  
  #define Z_DEVICE_EXTRA_HANDLES(...)				\
  	FOR_EACH_NONEMPTY_TERM(IDENTITY, (,), __VA_ARGS__)
  
  /*
   * Utility macro to define and initialize the device state.
   *
   * @param node_id Devicetree node id of the device.
   * @param dev_name Device name.
   */
  #define Z_DEVICE_STATE_DEFINE(node_id, dev_name)			\
  	static struct device_state Z_DEVICE_STATE_NAME(dev_name)	\
  	__attribute__((__section__(".z_devstate")));
  
  /* Construct objects that are referenced from struct device. These
   * include power management and dependency handles.
   */
  #define Z_DEVICE_DEFINE_PRE(node_id, dev_name, ...)			\
  	Z_DEVICE_DEFINE_HANDLES(node_id, dev_name, __VA_ARGS__)
  
  /* Initial build provides a record that associates the device object
   * with its devicetree ordinal, and provides the dependency ordinals.
   * These are provided as weak definitions (to prevent the reference
   * from being captured when the original object file is compiled), and
   * in a distinct pass1 section (which will be replaced by
   * postprocessing).
   *
   * Before processing in gen_handles.py, the array format is:
   * {
   *     DEVICE_ORDINAL (or DEVICE_HANDLE_NULL if not a devicetree node),
   *     List of devicetree dependency ordinals (if any),
   *     DEVICE_HANDLE_SEP,
   *     List of injected dependency ordinals (if any),
   *     DEVICE_HANDLE_SEP,
   *     List of devicetree supporting ordinals (if any),
   * }
   *
   * After processing in gen_handles.py, the format is updated to:
   * {
   *     List of existing devicetree dependency handles (if any),
   *     DEVICE_HANDLE_SEP,
   *     List of injected dependency ordinals (if any),
   *     DEVICE_HANDLE_SEP,
   *     List of existing devicetree support handles (if any),
   *     DEVICE_HANDLE_NULL
   * }
   *
   * It is also (experimentally) necessary to provide explicit alignment
   * on each object. Otherwise x86-64 builds will introduce padding
   * between objects in the same input section in individual object
   * files, which will be retained in subsequent links both wasting
   * space and resulting in aggregate size changes relative to pass2
   * when all objects will be in the same input section.
   *
   * The build assert will fail if device_handle_t changes size, which
   * means the alignment directives in the linker scripts and in
   * `gen_handles.py` must be updated.
   */
  BUILD_ASSERT(sizeof(device_handle_t) == 2, "fix the linker scripts");
  #define Z_DEVICE_DEFINE_HANDLES(node_id, dev_name, ...)			\
  	extern Z_DEVICE_HANDLES_CONST device_handle_t			\
  		Z_DEVICE_HANDLE_NAME(node_id, dev_name)[];		\
  	Z_DEVICE_HANDLES_CONST device_handle_t				\
  	__aligned(sizeof(device_handle_t))				\
  	__attribute__((__weak__,					\
  		       __section__(".__device_handles_pass1")))		\
  	Z_DEVICE_HANDLE_NAME(node_id, dev_name)[] = {			\
  	COND_CODE_1(DT_NODE_EXISTS(node_id), (				\
  			DT_DEP_ORD(node_id),				\
  			DT_REQUIRES_DEP_ORDS(node_id)			\
  		), (							\
  			DEVICE_HANDLE_NULL,				\
  		))							\
  			DEVICE_HANDLE_SEP,				\
  			Z_DEVICE_EXTRA_HANDLES(__VA_ARGS__)		\
  			DEVICE_HANDLE_SEP,				\
  	COND_CODE_1(DT_NODE_EXISTS(node_id),				\
  			(DT_SUPPORTS_DEP_ORDS(node_id)), ())		\
  		};
  
  #define Z_DEVICE_DEFINE_INIT(node_id, dev_name)				\
  	.handles = Z_DEVICE_HANDLE_NAME(node_id, dev_name),
  
  /* Like DEVICE_DEFINE but takes a node_id AND a dev_name, and trailing
   * dependency handles that come from outside devicetree.
   */
  #define Z_DEVICE_DEFINE(node_id, dev_name, drv_name, init_fn, pm_device,\
  			data_ptr, cfg_ptr, level, prio, api_ptr, state_ptr, ...)	\
  	Z_DEVICE_DEFINE_PRE(node_id, dev_name, __VA_ARGS__)		\
  	COND_CODE_1(DT_NODE_EXISTS(node_id), (), (static))		\
  		const Z_DECL_ALIGN(struct device)			\
  		DEVICE_NAME_GET(dev_name) __used			\
  	__attribute__((__section__(".z_device_" #level STRINGIFY(prio)"_"))) = { \
  		.name = drv_name,					\
  		.config = (cfg_ptr),					\
  		.api = (api_ptr),					\
  		.state = (state_ptr),					\
  		.data = (data_ptr),					\
  		COND_CODE_1(CONFIG_PM_DEVICE, (.pm = pm_device,), ())	\
  		Z_DEVICE_DEFINE_INIT(node_id, dev_name)			\
  	};								\
  	BUILD_ASSERT(sizeof(Z_STRINGIFY(drv_name)) <= Z_DEVICE_MAX_NAME_LEN, \
  		     Z_STRINGIFY(DEVICE_NAME_GET(drv_name)) " too long"); \
  	Z_INIT_ENTRY_DEFINE(DEVICE_NAME_GET(dev_name), init_fn,		\
  		(&DEVICE_NAME_GET(dev_name)), level, prio)
  
  #ifdef __cplusplus
  }
  #endif
  
  /* device_extern is generated based on devicetree nodes */
  #include <device_extern.h>
  
  #include <syscalls/device.h>
  
  #endif /* ZEPHYR_INCLUDE_DEVICE_H_ */
  