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 <stddef.h>
8 : : #include <string.h>
9 : : #include <zephyr/device.h>
10 : : #include <zephyr/sys/atomic.h>
11 : : #include <zephyr/sys/iterable_sections.h>
12 : : #include <zephyr/sys/kobject.h>
13 : : #include <zephyr/internal/syscall_handler.h>
14 : : #include <zephyr/toolchain.h>
15 : :
16 : : /**
17 : : * @brief Initialize state for all static devices.
18 : : *
19 : : * The state object is always zero-initialized, but this may not be
20 : : * sufficient.
21 : : */
22 : 1 : void z_device_state_init(void)
23 : : {
24 [ - + - + ]: 1 : STRUCT_SECTION_FOREACH(device, dev) {
25 : 0 : k_object_init(dev);
26 : : }
27 : 1 : }
28 : :
29 : 0 : const struct device *z_impl_device_get_binding(const char *name)
30 : : {
31 : : /* A null string identifies no device. So does an empty
32 : : * string.
33 : : */
34 [ # # # # ]: 0 : if ((name == NULL) || (name[0] == '\0')) {
35 : : return NULL;
36 : : }
37 : :
38 : : /* Split the search into two loops: in the common scenario, where
39 : : * device names are stored in ROM (and are referenced by the user
40 : : * with CONFIG_* macros), only cheap pointer comparisons will be
41 : : * performed. Reserve string comparisons for a fallback.
42 : : */
43 [ # # # # ]: 0 : STRUCT_SECTION_FOREACH(device, dev) {
44 [ # # # # ]: 0 : if (z_impl_device_is_ready(dev) && (dev->name == name)) {
45 : 0 : return dev;
46 : : }
47 : : }
48 : :
49 [ # # # # ]: 0 : STRUCT_SECTION_FOREACH(device, dev) {
50 [ # # # # ]: 0 : if (z_impl_device_is_ready(dev) && (strcmp(name, dev->name) == 0)) {
51 : 0 : return dev;
52 : : }
53 : : }
54 : :
55 : : return NULL;
56 : : }
57 : :
58 : : #ifdef CONFIG_USERSPACE
59 : : static inline const struct device *z_vrfy_device_get_binding(const char *name)
60 : : {
61 : : char name_copy[Z_DEVICE_MAX_NAME_LEN];
62 : :
63 : : if (k_usermode_string_copy(name_copy, name, sizeof(name_copy))
64 : : != 0) {
65 : : return NULL;
66 : : }
67 : :
68 : : return z_impl_device_get_binding(name_copy);
69 : : }
70 : : #include <zephyr/syscalls/device_get_binding_mrsh.c>
71 : :
72 : : static inline bool z_vrfy_device_is_ready(const struct device *dev)
73 : : {
74 : : K_OOPS(K_SYSCALL_OBJ_INIT(dev, K_OBJ_ANY));
75 : :
76 : : return z_impl_device_is_ready(dev);
77 : : }
78 : : #include <zephyr/syscalls/device_is_ready_mrsh.c>
79 : : #endif /* CONFIG_USERSPACE */
80 : :
81 : : #ifdef CONFIG_DEVICE_DT_METADATA
82 : : const struct device *z_impl_device_get_by_dt_nodelabel(const char *nodelabel)
83 : : {
84 : : /* For consistency with device_get_binding(). */
85 : : if ((nodelabel == NULL) || (nodelabel[0] == '\0')) {
86 : : return NULL;
87 : : }
88 : :
89 : : /* Unlike device_get_binding(), which has a history of being
90 : : * used in application code, we don't expect
91 : : * device_get_by_dt_nodelabel() to be used outside of
92 : : * scenarios where a human is in the loop. The shell is the
93 : : * main expected use case. Therefore, nodelabel is probably
94 : : * not the same pointer as any of the entry->nodelabel
95 : : * elements. We therefore skip the pointer comparison that
96 : : * device_get_binding() does.
97 : : */
98 : : STRUCT_SECTION_FOREACH(device, dev) {
99 : : const struct device_dt_nodelabels *nl = device_get_dt_nodelabels(dev);
100 : :
101 : : if (!z_impl_device_is_ready(dev) || nl == NULL) {
102 : : continue;
103 : : }
104 : :
105 : : for (size_t i = 0; i < nl->num_nodelabels; i++) {
106 : : const char *dev_nodelabel = nl->nodelabels[i];
107 : :
108 : : if (strcmp(nodelabel, dev_nodelabel) == 0) {
109 : : return dev;
110 : : }
111 : : }
112 : : }
113 : :
114 : : return NULL;
115 : : }
116 : :
117 : : #ifdef CONFIG_USERSPACE
118 : : static inline const struct device *z_vrfy_device_get_by_dt_nodelabel(const char *nodelabel)
119 : : {
120 : : char nl_copy[Z_DEVICE_MAX_NODELABEL_LEN];
121 : :
122 : : if (k_usermode_string_copy(nl_copy, (char *)nodelabel, sizeof(nl_copy)) != 0) {
123 : : return NULL;
124 : : }
125 : :
126 : : return z_impl_device_get_by_dt_nodelabel(nl_copy);
127 : : }
128 : : #include <zephyr/syscalls/device_get_by_dt_nodelabel_mrsh.c>
129 : : #endif /* CONFIG_USERSPACE */
130 : : #endif /* CONFIG_DEVICE_DT_METADATA */
131 : :
132 : 0 : size_t z_device_get_all_static(struct device const **devices)
133 : : {
134 : 0 : size_t cnt;
135 : :
136 : 0 : STRUCT_SECTION_GET(device, 0, devices);
137 : 0 : STRUCT_SECTION_COUNT(device, &cnt);
138 : :
139 : 0 : return cnt;
140 : : }
141 : :
142 : 0 : bool z_impl_device_is_ready(const struct device *dev)
143 : : {
144 : : /*
145 : : * if an invalid device pointer is passed as argument, this call
146 : : * reports the `device` as not ready for usage.
147 : : */
148 [ # # ]: 0 : if (dev == NULL) {
149 : : return false;
150 : : }
151 : :
152 [ # # # # ]: 0 : return dev->state->initialized && (dev->state->init_res == 0U);
153 : : }
154 : :
155 : : #ifdef CONFIG_DEVICE_DEPS
156 : :
157 : : static int device_visitor(const device_handle_t *handles,
158 : : size_t handle_count,
159 : : device_visitor_callback_t visitor_cb,
160 : : void *context)
161 : : {
162 : : /* Iterate over fixed devices */
163 : : for (size_t i = 0; i < handle_count; ++i) {
164 : : device_handle_t dh = handles[i];
165 : : const struct device *rdev = device_from_handle(dh);
166 : : int rc = visitor_cb(rdev, context);
167 : :
168 : : if (rc < 0) {
169 : : return rc;
170 : : }
171 : : }
172 : :
173 : : return handle_count;
174 : : }
175 : :
176 : : int device_required_foreach(const struct device *dev,
177 : : device_visitor_callback_t visitor_cb,
178 : : void *context)
179 : : {
180 : : size_t handle_count = 0;
181 : : const device_handle_t *handles = device_required_handles_get(dev, &handle_count);
182 : :
183 : : return device_visitor(handles, handle_count, visitor_cb, context);
184 : : }
185 : :
186 : : int device_supported_foreach(const struct device *dev,
187 : : device_visitor_callback_t visitor_cb,
188 : : void *context)
189 : : {
190 : : size_t handle_count = 0;
191 : : const device_handle_t *handles = device_supported_handles_get(dev, &handle_count);
192 : :
193 : : return device_visitor(handles, handle_count, visitor_cb, context);
194 : : }
195 : :
196 : : #endif /* CONFIG_DEVICE_DEPS */
|