Skip to content

Commit 8f7b425

Browse files
committed
device: introduce device_get
Add a new API to claim a device. This function will increase device usage count and, if not initialized, it will perform its initialization. Function is thread-safe and will block until initialization completes, returning the result. If device has been initialized at boot time, regardless of its usage count, device reference count will be increased but no initialization will be performed. Signed-off-by: Gerard Marull-Paretas <gerard.marull@nordicsemi.no>
1 parent f39828c commit 8f7b425

File tree

3 files changed

+86
-4
lines changed

3 files changed

+86
-4
lines changed

include/zephyr/device.h

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
#include <zephyr/devicetree.h>
1313
#include <zephyr/init.h>
14+
#include <zephyr/kernel.h>
1415
#include <zephyr/linker/sections.h>
1516
#include <zephyr/pm/state.h>
1617
#include <zephyr/sys/device_mmio.h>
@@ -433,6 +434,12 @@ struct device_state {
433434
* invoked.
434435
*/
435436
bool initialized : 1;
437+
/** Usage count. */
438+
uint8_t usage;
439+
#if defined(CONFIG_MULTITHREADING) || defined(__DOXYGEN__)
440+
/** Usage lock (@kconfig_dep(CONFIG_MULTITHREADING}). */
441+
struct k_sem usage_lock;
442+
#endif
436443
};
437444

438445
struct pm_device_base;
@@ -844,6 +851,21 @@ __syscall bool device_is_ready(const struct device *dev);
844851
*/
845852
__syscall int device_init(const struct device *dev);
846853

854+
/**
855+
* Get a device.
856+
*
857+
* When getting a device, its usage count will be increased and, if not yet
858+
* initialized, its initialization routine will be called. This function will
859+
* not return until device initialization has finished.
860+
*
861+
* @param dev Device instance
862+
*
863+
* @retval -errno Device failed to initialize.
864+
* @retval >=0 Device was successfully initialized and can be used. Values > 0
865+
* indicate the current reference count.
866+
*/
867+
__syscall int device_get(const struct device *dev);
868+
847869
/**
848870
* @}
849871
*/
@@ -861,9 +883,13 @@ __syscall int device_init(const struct device *dev);
861883
*
862884
* @param dev_id Device identifier.
863885
*/
864-
#define Z_DEVICE_STATE_DEFINE(dev_id) \
865-
static Z_DECL_ALIGN(struct device_state) Z_DEVICE_STATE_NAME(dev_id) \
866-
__attribute__((__section__(".z_devstate")))
886+
#define Z_DEVICE_STATE_DEFINE(dev_id) \
887+
static Z_DECL_ALIGN(struct device_state) Z_DEVICE_STATE_NAME(dev_id) \
888+
__attribute__((__section__(".z_devstate"))) = { \
889+
IF_ENABLED(CONFIG_MULTITHREADING, \
890+
(.usage_lock = Z_SEM_INITIALIZER( \
891+
Z_DEVICE_STATE_NAME(dev_id).usage_lock, 1, 1),)) \
892+
}
867893

868894
/**
869895
* @brief Device flags obtained from DT.

include/zephyr/sw_isr_table.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
#define ZEPHYR_INCLUDE_SW_ISR_TABLE_H_
1616

1717
#if !defined(_ASMLANGUAGE)
18-
#include <zephyr/device.h>
1918
#include <zephyr/sys/iterable_sections.h>
2019
#include <zephyr/types.h>
2120
#include <zephyr/toolchain.h>
@@ -25,6 +24,8 @@
2524
extern "C" {
2625
#endif
2726

27+
struct device;
28+
2829
/* Default vector for the IRQ vector table */
2930
void _isr_wrapper(void);
3031

kernel/device.c

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,61 @@ bool z_impl_device_is_ready(const struct device *dev)
142142
return dev->state->initialized && (dev->state->init_res == 0U);
143143
}
144144

145+
int z_impl_device_get(const struct device *dev)
146+
{
147+
int ret = 0;
148+
149+
if (dev == NULL) {
150+
return -ENODEV;
151+
}
152+
153+
#ifdef CONFIG_MULTITHREADING
154+
if (!k_is_pre_kernel()) {
155+
(void)k_sem_take(&dev->state->usage_lock, K_FOREVER);
156+
}
157+
#endif
158+
159+
if (dev->state->usage == UINT8_MAX) {
160+
ret = -EPERM;
161+
goto out;
162+
}
163+
164+
if ((dev->state->usage == 0U) && (dev->ops.init != NULL)) {
165+
if (dev->state->initialized) {
166+
if (dev->state->init_res != 0U) {
167+
ret = dev->ops.init(dev);
168+
}
169+
dev->state->initialized = false;
170+
} else {
171+
ret = dev->ops.init(dev);
172+
}
173+
}
174+
175+
if (ret == 0) {
176+
dev->state->usage++;
177+
ret = dev->state->usage;
178+
}
179+
180+
out:
181+
#ifdef CONFIG_MULTITHREADING
182+
if (!k_is_pre_kernel()) {
183+
(void)k_sem_give(&dev->state->usage_lock);
184+
}
185+
#endif
186+
187+
return ret;
188+
}
189+
190+
#ifdef CONFIG_USERSPACE
191+
static inline int z_vrfy_device_get(const struct device *dev)
192+
{
193+
K_OOPS(K_SYSCALL_OBJ_INIT(dev, K_OBJ_ANY));
194+
195+
return z_impl_device_get(dev);
196+
}
197+
#include <zephyr/syscalls/device_get_mrsh.c>
198+
#endif
199+
145200
#ifdef CONFIG_DEVICE_DEPS
146201

147202
static int device_visitor(const device_handle_t *handles,

0 commit comments

Comments
 (0)