device: inject device dependency information from devicetree nodes
Generate arrays of dependency information for each device. If a device definition is being constructed from devicetree these come from the devicetree dependency information. Additional dependencies may be passed through using the DT_ macros. Define flag values for device handles so we can partition the dependency array into distinct sets, which include things it requires, things it supports (may not be needed), and child nodes (not implemented, may not be needed). Signed-off-by: Peter Bigot <peter.bigot@nordicsemi.no>
This commit is contained in:
parent
91869f3ba5
commit
669bc6b86f
1 changed files with 160 additions and 4 deletions
164
include/device.h
164
include/device.h
|
@ -21,11 +21,37 @@
|
|||
|
||||
#include <init.h>
|
||||
#include <sys/device_mmio.h>
|
||||
#include <sys/util.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/** @brief Type used to represent devices and functions.
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
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
|
||||
|
||||
/**
|
||||
|
@ -168,11 +194,13 @@ extern "C" {
|
|||
* used by the driver. Can be NULL.
|
||||
*/
|
||||
#define DEVICE_DT_DEFINE(node_id, init_fn, pm_control_fn, \
|
||||
data_ptr, cfg_ptr, level, prio, api_ptr) \
|
||||
data_ptr, cfg_ptr, level, prio, \
|
||||
api_ptr, ...) \
|
||||
Z_DEVICE_DEFINE(node_id, Z_DEVICE_DT_DEV_NAME(node_id), \
|
||||
DT_PROP_OR(node_id, label, ""), init_fn, \
|
||||
pm_control_fn, \
|
||||
data_ptr, cfg_ptr, level, prio, api_ptr)
|
||||
data_ptr, cfg_ptr, level, prio, \
|
||||
api_ptr, __VA_ARGS__)
|
||||
|
||||
/**
|
||||
* @def DEVICE_DT_INST_DEFINE
|
||||
|
@ -335,6 +363,14 @@ struct device {
|
|||
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
|
||||
/** Power Management function */
|
||||
int (*device_pm_control)(const struct device *dev, uint32_t command,
|
||||
|
@ -344,6 +380,86 @@ struct device {
|
|||
#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 Get the set of handles for devicetree dependencies of this device.
|
||||
*
|
||||
* These are the device dependencies inferred from devicetree.
|
||||
*
|
||||
* @param dev the device for which dependencies are desired.
|
||||
*
|
||||
* @param count pointer to a place to store the number of devices provided at
|
||||
* the returned pointer. The value is not set if the call returns a null
|
||||
* pointer. The value may be set to zero.
|
||||
*
|
||||
* @return a pointer to a sequence of @p *count device handles, or a null
|
||||
* pointer if @p dh does not provide dependency information.
|
||||
*/
|
||||
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 Retrieve the device structure for a driver by name
|
||||
*
|
||||
|
@ -776,9 +892,49 @@ static inline int device_pm_put_sync(const struct device *dev) { return -ENOTSUP
|
|||
*/
|
||||
#define Z_DEVICE_STATE_NAME(dev_name) _CONCAT(__devstate_, dev_name)
|
||||
|
||||
/** 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__)
|
||||
|
||||
/* 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__)
|
||||
|
||||
#define Z_DEVICE_DEFINE_HANDLES(node_id, dev_name, ...) \
|
||||
static const device_handle_t 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_ENDS, \
|
||||
};
|
||||
|
||||
#define Z_DEVICE_DEFINE_INIT(node_id, dev_name, pm_control_fn) \
|
||||
.handles = Z_DEVICE_HANDLE_NAME(node_id, dev_name), \
|
||||
Z_DEVICE_DEFINE_PM_INIT(dev_name, pm_control_fn)
|
||||
|
||||
/* 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_control_fn, \
|
||||
data_ptr, cfg_ptr, level, prio, api_ptr) \
|
||||
data_ptr, cfg_ptr, level, prio, api_ptr, ...) \
|
||||
static struct device_state Z_DEVICE_STATE_NAME(dev_name); \
|
||||
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 \
|
||||
|
@ -788,7 +944,7 @@ static inline int device_pm_put_sync(const struct device *dev) { return -ENOTSUP
|
|||
.api = (api_ptr), \
|
||||
.state = &Z_DEVICE_STATE_NAME(dev_name), \
|
||||
.data = (data_ptr), \
|
||||
Z_DEVICE_DEFINE_PM_INIT(dev_name, pm_control_fn) \
|
||||
Z_DEVICE_DEFINE_INIT(node_id, dev_name, pm_control_fn) \
|
||||
}; \
|
||||
BUILD_ASSERT(sizeof(Z_STRINGIFY(drv_name)) <= Z_DEVICE_MAX_NAME_LEN, \
|
||||
Z_STRINGIFY(DEVICE_GET_NAME(drv_name)) " too long"); \
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue