/* * 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 #include #include #include #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 struct device 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 struct pm_device, 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 struct device 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 * DEVICE_DT_NAME(node_id). * * The device is declared with extern visibility, so a pointer to a * global device object can be obtained with * DEVICE_DT_GET(node_id) 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 struct pm_device, 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 DT_DRV_INST(inst). * * @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 const struct device* 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 undefined reference to * __device_dts_ord_, 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 const struct device* for an instance of a * DT_DRV_COMPAT compatible * * @details This is equivalent to DEVICE_DT_GET(DT_DRV_INST(inst)). * * @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 const struct device* 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 const struct device* 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 DEVICE_DT_GET(node_id). Otherwise, it * returns NULL. * * @param node_id devicetree node identifier * * @return a const struct device* 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; /** * @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(). */ 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 const struct device* 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 const device_handle_t \ Z_DEVICE_HANDLE_NAME(node_id, dev_name)[]; \ 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 #include #endif /* ZEPHYR_INCLUDE_DEVICE_H_ */