device: Provide de-init device function only if requested
This feature, fixing a specific corner case, is unilateraly growing all struct device with a pointer that 99% of the time is not used. Thus uselessly utilizing ROM. Making the feature Kconfig controlled. Signed-off-by: Tomasz Bursztyka <tobu@bang-olufsen.dk>
This commit is contained in:
parent
2edb6d2517
commit
c14ee16463
3 changed files with 39 additions and 2 deletions
|
@ -144,6 +144,8 @@ typedef int16_t device_handle_t;
|
||||||
* device from a devicetree node, use DEVICE_DT_DEINIT_DEFINE() or
|
* device from a devicetree node, use DEVICE_DT_DEINIT_DEFINE() or
|
||||||
* DEVICE_DT_INST_DEINIT_DEFINE() instead.
|
* DEVICE_DT_INST_DEINIT_DEFINE() instead.
|
||||||
*
|
*
|
||||||
|
* Note: deinit_fn will only be used if CONFIG_DEVICE_DEINIT_SUPPORT is enabled.
|
||||||
|
*
|
||||||
* @param dev_id A unique token which is used in the name of the global device
|
* @param dev_id A unique token which is used in the name of the global device
|
||||||
* structure as a C identifier.
|
* structure as a C identifier.
|
||||||
* @param name A string name for the device, which will be stored in
|
* @param name A string name for the device, which will be stored in
|
||||||
|
@ -214,6 +216,8 @@ typedef int16_t device_handle_t;
|
||||||
* @kconfig{CONFIG_LLEXT_EXPORT_DEVICES} is enabled). Before using the
|
* @kconfig{CONFIG_LLEXT_EXPORT_DEVICES} is enabled). Before using the
|
||||||
* pointer, the referenced object should be checked using device_is_ready().
|
* pointer, the referenced object should be checked using device_is_ready().
|
||||||
*
|
*
|
||||||
|
* Note: deinit_fn will only be used if CONFIG_DEVICE_DEINIT_SUPPORT is enabled.
|
||||||
|
*
|
||||||
* @param node_id The devicetree node identifier.
|
* @param node_id The devicetree node identifier.
|
||||||
* @param init_fn Pointer to the device's initialization function, which will be
|
* @param init_fn Pointer to the device's initialization function, which will be
|
||||||
* run by the kernel during system initialization. Can be `NULL`.
|
* run by the kernel during system initialization. Can be `NULL`.
|
||||||
|
@ -494,8 +498,10 @@ typedef uint8_t device_flags_t;
|
||||||
struct device_ops {
|
struct device_ops {
|
||||||
/** Initialization function */
|
/** Initialization function */
|
||||||
int (*init)(const struct device *dev);
|
int (*init)(const struct device *dev);
|
||||||
|
#ifdef CONFIG_DEVICE_DEINIT_SUPPORT
|
||||||
/** De-initialization function */
|
/** De-initialization function */
|
||||||
int (*deinit)(const struct device *dev);
|
int (*deinit)(const struct device *dev);
|
||||||
|
#endif /* CONFIG_DEVICE_DEINIT_SUPPORT */
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -881,6 +887,8 @@ __syscall int device_init(const struct device *dev);
|
||||||
* acquired (e.g. pins, memory, clocks, DMA channels, etc.) and its status will
|
* acquired (e.g. pins, memory, clocks, DMA channels, etc.) and its status will
|
||||||
* be left as in its reset state.
|
* be left as in its reset state.
|
||||||
*
|
*
|
||||||
|
* Note: this will be available if CONFIG_DEVICE_DEINIT_SUPPORT is enabled.
|
||||||
|
*
|
||||||
* @warning It is the responsibility of the caller to ensure that the device is
|
* @warning It is the responsibility of the caller to ensure that the device is
|
||||||
* ready to be de-initialized.
|
* ready to be de-initialized.
|
||||||
*
|
*
|
||||||
|
@ -888,7 +896,8 @@ __syscall int device_init(const struct device *dev);
|
||||||
*
|
*
|
||||||
* @retval 0 If successful
|
* @retval 0 If successful
|
||||||
* @retval -EPERM If device has not been initialized.
|
* @retval -EPERM If device has not been initialized.
|
||||||
* @retval -ENOTSUP If device does not support de-initialization.
|
* @retval -ENOTSUP If device does not support de-initialization, or if the
|
||||||
|
* feature is not enabled (see CONFIG_DEVICE_DEINIT_SUPPORT)
|
||||||
* @retval -errno For any other errors.
|
* @retval -errno For any other errors.
|
||||||
*/
|
*/
|
||||||
__syscall int device_deinit(const struct device *dev);
|
__syscall int device_deinit(const struct device *dev);
|
||||||
|
@ -1132,6 +1141,19 @@ device_get_dt_nodelabels(const struct device *dev)
|
||||||
BUILD_ASSERT(sizeof(Z_STRINGIFY(name)) <= Z_DEVICE_MAX_NAME_LEN, \
|
BUILD_ASSERT(sizeof(Z_STRINGIFY(name)) <= Z_DEVICE_MAX_NAME_LEN, \
|
||||||
Z_STRINGIFY(name) " too long")
|
Z_STRINGIFY(name) " too long")
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Fill in the struct device_ops
|
||||||
|
*
|
||||||
|
* @param init_fn_ Initialization function
|
||||||
|
* @param deinit_fn_ De-initialization function
|
||||||
|
*/
|
||||||
|
#define Z_DEVICE_OPS(init_fn_, deinit_fn_) \
|
||||||
|
{ \
|
||||||
|
.init = (init_fn_), \
|
||||||
|
IF_ENABLED(CONFIG_DEVICE_DEINIT_SUPPORT, \
|
||||||
|
(.deinit = (deinit_fn_),)) \
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Initializer for @ref device.
|
* @brief Initializer for @ref device.
|
||||||
*
|
*
|
||||||
|
@ -1156,7 +1178,7 @@ device_get_dt_nodelabels(const struct device *dev)
|
||||||
.api = (api_), \
|
.api = (api_), \
|
||||||
.state = (state_), \
|
.state = (state_), \
|
||||||
.data = (data_), \
|
.data = (data_), \
|
||||||
.ops = { .init = (init_fn_), .deinit = (deinit_fn_) }, \
|
.ops = Z_DEVICE_OPS(init_fn_, deinit_fn_), \
|
||||||
.flags = (flags_), \
|
.flags = (flags_), \
|
||||||
IF_ENABLED(CONFIG_DEVICE_DEPS, (.deps = (deps_),)) /**/ \
|
IF_ENABLED(CONFIG_DEVICE_DEPS, (.deps = (deps_),)) /**/ \
|
||||||
IF_ENABLED(CONFIG_PM_DEVICE, Z_DEVICE_INIT_PM_BASE(pm_)) /**/ \
|
IF_ENABLED(CONFIG_PM_DEVICE, Z_DEVICE_INIT_PM_BASE(pm_)) /**/ \
|
||||||
|
|
|
@ -33,6 +33,16 @@ config DEVICE_DT_METADATA
|
||||||
each device. This allows you to use device_get_by_dt_nodelabel(),
|
each device. This allows you to use device_get_by_dt_nodelabel(),
|
||||||
device_get_dt_metadata(), etc.
|
device_get_dt_metadata(), etc.
|
||||||
|
|
||||||
|
config DEVICE_DEINIT_SUPPORT
|
||||||
|
bool "Support device de-initialization"
|
||||||
|
default y
|
||||||
|
help
|
||||||
|
In very specific case, it might be necessary to de-initialize
|
||||||
|
a device at runtime. This is possible by providing a function
|
||||||
|
to do so. Note, that this will grow every struct device by a
|
||||||
|
function pointer. All device drivers that use the relevant
|
||||||
|
macros and provide such function should select this option.
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
|
||||||
menu "Initialization Priorities"
|
menu "Initialization Priorities"
|
||||||
|
|
|
@ -145,6 +145,7 @@ bool z_impl_device_is_ready(const struct device *dev)
|
||||||
|
|
||||||
int z_impl_device_deinit(const struct device *dev)
|
int z_impl_device_deinit(const struct device *dev)
|
||||||
{
|
{
|
||||||
|
#ifdef CONFIG_DEVICE_DEINIT_SUPPORT
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!dev->state->initialized) {
|
if (!dev->state->initialized) {
|
||||||
|
@ -163,6 +164,10 @@ int z_impl_device_deinit(const struct device *dev)
|
||||||
dev->state->initialized = false;
|
dev->state->initialized = false;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
#else
|
||||||
|
ARG_UNUSED(dev);
|
||||||
|
return -ENOTSUP;
|
||||||
|
#endif /* CONFIG_DEVICE_DEINIT_SUPPORT */
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_USERSPACE
|
#ifdef CONFIG_USERSPACE
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue