Branch data Line data Source code
1 : : /*
2 : : * Copyright (c) 2015-2016 Intel Corporation.
3 : : *
4 : : * SPDX-License-Identifier: Apache-2.0
5 : : */
6 : :
7 : : #include <errno.h>
8 : : #include <stddef.h>
9 : : #include <string.h>
10 : : #include <zephyr/device.h>
11 : : #include <zephyr/sys/atomic.h>
12 : : #include <zephyr/sys/iterable_sections.h>
13 : : #include <zephyr/sys/kobject.h>
14 : : #include <zephyr/internal/syscall_handler.h>
15 : : #include <zephyr/toolchain.h>
16 : : #include <zephyr/pm/device_runtime.h>
17 : :
18 : 0 : int do_device_init(const struct device *dev)
19 : : {
20 : 0 : int rc = 0;
21 : :
22 [ # # ]: 0 : if (dev->ops.init != NULL) {
23 : 0 : rc = dev->ops.init(dev);
24 : : /* If initialization failed, record in dev->state->init_res
25 : : * the POSITIVE value of the resulting errno
26 : : */
27 [ # # ]: 0 : if (rc != 0) {
28 : : /* device's init function should return:
29 : : * 0 on success
30 : : * a negative value on failure (-errno)
31 : : * errno value maps to an uint8_t range as of now.
32 : : */
33 [ # # ]: 0 : __ASSERT(rc >= -UINT8_MAX && rc < 0, "device %s init: invalid error (%d)",
34 : : dev->name, rc);
35 : :
36 : 0 : if (rc < 0) {
37 : 0 : rc = -rc;
38 : : }
39 : : /* handle error value overflow in production
40 : : * this is likely a bug in the device's init function. Signals it
41 : : */
42 : 0 : if (rc > UINT8_MAX) {
43 : : rc = UINT8_MAX;
44 : : }
45 : 0 : dev->state->init_res = rc;
46 : : }
47 : : }
48 : :
49 : : /* device initialization has been invoked */
50 : 0 : dev->state->initialized = true;
51 : :
52 : 0 : if (rc == 0) {
53 : : /* Run automatic device runtime enablement */
54 : : (void)pm_device_runtime_auto_enable(dev);
55 : : }
56 : :
57 : : /* here, the value of rc is either 0 or +errno
58 : : * flip the sign to return a negative value on failure as expected
59 : : */
60 : 0 : return -rc;
61 : : }
62 : :
63 : 0 : int z_impl_device_init(const struct device *dev)
64 : : {
65 [ # # ]: 0 : if (dev->state->initialized) {
66 : : return -EALREADY;
67 : : }
68 : :
69 : 0 : return do_device_init(dev);
70 : : }
71 : :
72 : : #ifdef CONFIG_USERSPACE
73 : : static inline int z_vrfy_device_init(const struct device *dev)
74 : : {
75 : : K_OOPS(K_SYSCALL_OBJ_INIT(dev, K_OBJ_ANY));
76 : :
77 : : return z_impl_device_init(dev);
78 : : }
79 : : #include <zephyr/syscalls/device_init_mrsh.c>
80 : : #endif
81 : :
82 : :
83 : 0 : const struct device *z_impl_device_get_binding(const char *name)
84 : : {
85 : : /* A null string identifies no device. So does an empty
86 : : * string.
87 : : */
88 [ # # # # ]: 0 : if ((name == NULL) || (name[0] == '\0')) {
89 : : return NULL;
90 : : }
91 : :
92 : : /* Return NULL if the device matching 'name' is not ready. */
93 [ # # # # ]: 0 : STRUCT_SECTION_FOREACH(device, dev) {
94 [ # # # # ]: 0 : if ((dev->name == name) || (strcmp(name, dev->name) == 0)) {
95 [ # # ]: 0 : return z_impl_device_is_ready(dev) ? dev : NULL;
96 : : }
97 : : }
98 : :
99 : : return NULL;
100 : : }
101 : :
102 : : #ifdef CONFIG_USERSPACE
103 : : static inline const struct device *z_vrfy_device_get_binding(const char *name)
104 : : {
105 : : char name_copy[Z_DEVICE_MAX_NAME_LEN];
106 : :
107 : : if (k_usermode_string_copy(name_copy, name, sizeof(name_copy))
108 : : != 0) {
109 : : return NULL;
110 : : }
111 : :
112 : : return z_impl_device_get_binding(name_copy);
113 : : }
114 : : #include <zephyr/syscalls/device_get_binding_mrsh.c>
115 : :
116 : : static inline bool z_vrfy_device_is_ready(const struct device *dev)
117 : : {
118 : : K_OOPS(K_SYSCALL_OBJ_INIT(dev, K_OBJ_ANY));
119 : :
120 : : return z_impl_device_is_ready(dev);
121 : : }
122 : : #include <zephyr/syscalls/device_is_ready_mrsh.c>
123 : : #endif /* CONFIG_USERSPACE */
124 : :
125 : : #ifdef CONFIG_DEVICE_DT_METADATA
126 : : const struct device *z_impl_device_get_by_dt_nodelabel(const char *nodelabel)
127 : : {
128 : : /* For consistency with device_get_binding(). */
129 : : if ((nodelabel == NULL) || (nodelabel[0] == '\0')) {
130 : : return NULL;
131 : : }
132 : :
133 : : /* Unlike device_get_binding(), which has a history of being
134 : : * used in application code, we don't expect
135 : : * device_get_by_dt_nodelabel() to be used outside of
136 : : * scenarios where a human is in the loop. The shell is the
137 : : * main expected use case. Therefore, nodelabel is probably
138 : : * not the same pointer as any of the entry->nodelabel
139 : : * elements. We therefore skip the pointer comparison that
140 : : * device_get_binding() does.
141 : : */
142 : : STRUCT_SECTION_FOREACH(device, dev) {
143 : : const struct device_dt_nodelabels *nl = device_get_dt_nodelabels(dev);
144 : :
145 : : if (!z_impl_device_is_ready(dev) || nl == NULL) {
146 : : continue;
147 : : }
148 : :
149 : : for (size_t i = 0; i < nl->num_nodelabels; i++) {
150 : : const char *dev_nodelabel = nl->nodelabels[i];
151 : :
152 : : if (strcmp(nodelabel, dev_nodelabel) == 0) {
153 : : return dev;
154 : : }
155 : : }
156 : : }
157 : :
158 : : return NULL;
159 : : }
160 : :
161 : : #ifdef CONFIG_USERSPACE
162 : : static inline const struct device *z_vrfy_device_get_by_dt_nodelabel(const char *nodelabel)
163 : : {
164 : : char nl_copy[Z_DEVICE_MAX_NODELABEL_LEN];
165 : :
166 : : if (k_usermode_string_copy(nl_copy, (char *)nodelabel, sizeof(nl_copy)) != 0) {
167 : : return NULL;
168 : : }
169 : :
170 : : return z_impl_device_get_by_dt_nodelabel(nl_copy);
171 : : }
172 : : #include <zephyr/syscalls/device_get_by_dt_nodelabel_mrsh.c>
173 : : #endif /* CONFIG_USERSPACE */
174 : : #endif /* CONFIG_DEVICE_DT_METADATA */
175 : :
176 : 0 : size_t z_device_get_all_static(struct device const **devices)
177 : : {
178 : 0 : size_t cnt;
179 : :
180 : 0 : STRUCT_SECTION_GET(device, 0, devices);
181 : 0 : STRUCT_SECTION_COUNT(device, &cnt);
182 : :
183 : 0 : return cnt;
184 : : }
185 : :
186 : 0 : bool z_impl_device_is_ready(const struct device *dev)
187 : : {
188 : : /*
189 : : * if an invalid device pointer is passed as argument, this call
190 : : * reports the `device` as not ready for usage.
191 : : */
192 [ # # ]: 0 : if (dev == NULL) {
193 : : return false;
194 : : }
195 : :
196 [ # # # # ]: 0 : return dev->state->initialized && (dev->state->init_res == 0U);
197 : : }
198 : :
199 : 0 : int z_impl_device_deinit(const struct device *dev)
200 : : {
201 : : #ifdef CONFIG_DEVICE_DEINIT_SUPPORT
202 : : int ret;
203 : :
204 : : if (!dev->state->initialized) {
205 : : return -EPERM;
206 : : }
207 : :
208 : : if (dev->ops.deinit == NULL) {
209 : : return -ENOTSUP;
210 : : }
211 : :
212 : : ret = dev->ops.deinit(dev);
213 : : if (ret < 0) {
214 : : return ret;
215 : : }
216 : :
217 : : dev->state->initialized = false;
218 : :
219 : : return 0;
220 : : #else
221 : 0 : ARG_UNUSED(dev);
222 : 0 : return -ENOTSUP;
223 : : #endif /* CONFIG_DEVICE_DEINIT_SUPPORT */
224 : : }
225 : :
226 : : #ifdef CONFIG_USERSPACE
227 : : static inline int z_vrfy_device_deinit(const struct device *dev)
228 : : {
229 : : K_OOPS(K_SYSCALL_OBJ_INIT(dev, K_OBJ_ANY));
230 : :
231 : : return z_impl_device_deinit(dev);
232 : : }
233 : : #include <zephyr/syscalls/device_deinit_mrsh.c>
234 : : #endif
235 : :
236 : : #ifdef CONFIG_DEVICE_DEPS
237 : :
238 : : static int device_visitor(const device_handle_t *handles,
239 : : size_t handle_count,
240 : : device_visitor_callback_t visitor_cb,
241 : : void *context)
242 : : {
243 : : /* Iterate over fixed devices */
244 : : for (size_t i = 0; i < handle_count; ++i) {
245 : : device_handle_t dh = handles[i];
246 : : const struct device *rdev = device_from_handle(dh);
247 : : int rc = visitor_cb(rdev, context);
248 : :
249 : : if (rc < 0) {
250 : : return rc;
251 : : }
252 : : }
253 : :
254 : : return handle_count;
255 : : }
256 : :
257 : : int device_required_foreach(const struct device *dev,
258 : : device_visitor_callback_t visitor_cb,
259 : : void *context)
260 : : {
261 : : size_t handle_count = 0;
262 : : const device_handle_t *handles = device_required_handles_get(dev, &handle_count);
263 : :
264 : : return device_visitor(handles, handle_count, visitor_cb, context);
265 : : }
266 : :
267 : : int device_supported_foreach(const struct device *dev,
268 : : device_visitor_callback_t visitor_cb,
269 : : void *context)
270 : : {
271 : : size_t handle_count = 0;
272 : : const device_handle_t *handles = device_supported_handles_get(dev, &handle_count);
273 : :
274 : : return device_visitor(handles, handle_count, visitor_cb, context);
275 : : }
276 : :
277 : : #endif /* CONFIG_DEVICE_DEPS */
|