source: mainline/kernel/genarch/src/ofw/ofw_tree.c@ a35b458

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since a35b458 was a35b458, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 8 years ago

style: Remove trailing whitespace on _all_ lines, including empty ones, for particular file types.

Command used: tools/srepl '\s\+$' '' -- *.c *.h *.py *.sh *.s *.S *.ag

Currently, whitespace on empty lines is very inconsistent.
There are two basic choices: Either remove the whitespace, or keep empty lines
indented to the level of surrounding code. The former is AFAICT more common,
and also much easier to do automatically.

Alternatively, we could write script for automatic indentation, and use that
instead. However, if such a script exists, it's possible to use the indented
style locally, by having the editor apply relevant conversions on load/save,
without affecting remote repository. IMO, it makes more sense to adopt
the simpler rule.

  • Property mode set to 100644
File size: 10.5 KB
Line 
1/*
2 * Copyright (c) 2006 Jakub Jermar
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup ofw
30 * @{
31 */
32/**
33 * @file
34 * @brief OpenFirmware device tree navigation.
35 *
36 */
37
38#include <genarch/ofw/ofw_tree.h>
39#include <mm/slab.h>
40#include <sysinfo/sysinfo.h>
41#include <mem.h>
42#include <str.h>
43#include <panic.h>
44#include <print.h>
45
46#define PATH_MAX_LEN 256
47#define NAME_BUF_LEN 50
48
49static ofw_tree_node_t *ofw_root;
50
51void ofw_tree_init(ofw_tree_node_t *root)
52{
53 ofw_root = root;
54}
55
56/** Get OpenFirmware node property.
57 *
58 * @param node Node in which to lookup the property.
59 * @param name Name of the property.
60 *
61 * @return Pointer to the property structure or NULL if no such
62 * property.
63 *
64 */
65ofw_tree_property_t *ofw_tree_getprop(const ofw_tree_node_t *node,
66 const char *name)
67{
68 for (size_t i = 0; i < node->properties; i++) {
69 if (str_cmp(node->property[i].name, name) == 0)
70 return &node->property[i];
71 }
72
73 return NULL;
74}
75
76/** Return value of the 'name' property.
77 *
78 * @param node Node of interest.
79 *
80 * @return Value of the 'name' property belonging to the node
81 * or NULL if the property is invalid.
82 *
83 */
84const char *ofw_tree_node_name(const ofw_tree_node_t *node)
85{
86 ofw_tree_property_t *prop = ofw_tree_getprop(node, "name");
87 if ((!prop) || (prop->size < 2))
88 return NULL;
89
90 return prop->value;
91}
92
93/** Lookup child of given name.
94 *
95 * @param node Node whose child is being looked up.
96 * @param name Name of the child being looked up.
97 *
98 * @return NULL if there is no such child or pointer to the
99 * matching child node.
100 *
101 */
102ofw_tree_node_t *ofw_tree_find_child(ofw_tree_node_t *node,
103 const char *name)
104{
105 /*
106 * Try to find the disambigued name.
107 */
108 for (ofw_tree_node_t *cur = node->child; cur; cur = cur->peer) {
109 if (str_cmp(cur->da_name, name) == 0)
110 return cur;
111 }
112
113 /*
114 * Disambigued name not found.
115 * Lets try our luck with possibly ambiguous "name" property.
116 *
117 * We need to do this because paths stored in "/aliases"
118 * are not always fully-qualified.
119 */
120 for (ofw_tree_node_t *cur = node->child; cur; cur = cur->peer) {
121 if (str_cmp(ofw_tree_node_name(cur), name) == 0)
122 return cur;
123 }
124
125 return NULL;
126}
127
128/** Lookup first child of given device type.
129 *
130 * @param node Node whose child is being looked up.
131 * @param dtype Device type of the child being looked up.
132 *
133 * @return NULL if there is no such child or pointer to the
134 * matching child node.
135 *
136 */
137ofw_tree_node_t *ofw_tree_find_child_by_device_type(ofw_tree_node_t *node,
138 const char *dtype)
139{
140 for (ofw_tree_node_t *cur = node->child; cur; cur = cur->peer) {
141 ofw_tree_property_t *prop =
142 ofw_tree_getprop(cur, "device_type");
143
144 if ((!prop) || (!prop->value))
145 continue;
146
147 if (str_cmp(prop->value, dtype) == 0)
148 return cur;
149 }
150
151 return NULL;
152}
153
154/** Lookup node with matching node_handle.
155 *
156 * Child nodes are looked up recursively contrary to peer nodes that
157 * are looked up iteratively to avoid stack overflow.
158 *
159 * @param root Root of the searched subtree.
160 * @param handle OpenFirmware handle.
161 *
162 * @return NULL if there is no such node or pointer to the matching
163 * node.
164 *
165 */
166ofw_tree_node_t *ofw_tree_find_node_by_handle(ofw_tree_node_t *root,
167 phandle handle)
168{
169 for (ofw_tree_node_t *cur = root; cur; cur = cur->peer) {
170 if (cur->node_handle == handle)
171 return cur;
172
173 if (cur->child) {
174 ofw_tree_node_t *node =
175 ofw_tree_find_node_by_handle(cur->child, handle);
176 if (node)
177 return node;
178 }
179 }
180
181 return NULL;
182}
183
184/** Lookup first peer of given device type.
185 *
186 * @param node Node whose peer is being looked up.
187 * @param dtype Device type of the child being looked up.
188 *
189 * @return NULL if there is no such child or pointer to the
190 * matching child node.
191 *
192 */
193ofw_tree_node_t *ofw_tree_find_peer_by_device_type(ofw_tree_node_t *node,
194 const char *dtype)
195{
196 for (ofw_tree_node_t *cur = node->peer; cur; cur = cur->peer) {
197 ofw_tree_property_t *prop =
198 ofw_tree_getprop(cur, "device_type");
199
200 if ((!prop) || (!prop->value))
201 continue;
202
203 if (str_cmp(prop->value, dtype) == 0)
204 return cur;
205 }
206
207 return NULL;
208}
209
210/** Lookup first peer of given name.
211 *
212 * @param node Node whose peer is being looked up.
213 * @param name Name of the child being looked up.
214 *
215 * @return NULL if there is no such peer or pointer to the matching
216 * peer node.
217 *
218 */
219ofw_tree_node_t *ofw_tree_find_peer_by_name(ofw_tree_node_t *node,
220 const char *name)
221{
222 for (ofw_tree_node_t *cur = node->peer; cur; cur = cur->peer) {
223 ofw_tree_property_t *prop =
224 ofw_tree_getprop(cur, "name");
225
226 if ((!prop) || (!prop->value))
227 continue;
228
229 if (str_cmp(prop->value, name) == 0)
230 return cur;
231 }
232
233 return NULL;
234}
235
236/** Lookup OpenFirmware node by its path.
237 *
238 * @param path Path to the node.
239 *
240 * @return NULL if there is no such node or pointer to the leaf
241 * node.
242 *
243 */
244ofw_tree_node_t *ofw_tree_lookup(const char *path)
245{
246 if (path[0] != '/')
247 return NULL;
248
249 ofw_tree_node_t *node = ofw_root;
250 size_t j;
251
252 for (size_t i = 1; (i < str_size(path)) && (node); i = j + 1) {
253 for (j = i; (j < str_size(path)) && (path[j] != '/'); j++);
254
255 /* Skip extra slashes */
256 if (i == j)
257 continue;
258
259 char buf[NAME_BUF_LEN + 1];
260 memcpy(buf, &path[i], j - i);
261 buf[j - i] = 0;
262 node = ofw_tree_find_child(node, buf);
263 }
264
265 return node;
266}
267
268/** Walk the OpenFirmware device subtree rooted in a node.
269 *
270 * Child nodes are processed recursively and peer nodes are processed
271 * iteratively in order to avoid stack overflow.
272 *
273 * @param node Root of the subtree.
274 * @param dtype Device type to look for.
275 * @param walker Routine to be invoked on found device.
276 * @param arg User argument to the walker.
277 *
278 * @return True if the walk should continue.
279 *
280 */
281static bool ofw_tree_walk_by_device_type_internal(ofw_tree_node_t *node,
282 const char *dtype, ofw_tree_walker_t walker, void *arg)
283{
284 for (ofw_tree_node_t *cur = node; cur; cur = cur->peer) {
285 ofw_tree_property_t *prop =
286 ofw_tree_getprop(cur, "device_type");
287
288 if ((prop) && (prop->value) && (str_cmp(prop->value, dtype) == 0)) {
289 bool ret = walker(cur, arg);
290 if (!ret)
291 return false;
292 }
293
294 if (cur->child) {
295 bool ret =
296 ofw_tree_walk_by_device_type_internal(cur->child, dtype, walker, arg);
297 if (!ret)
298 return false;
299 }
300 }
301
302 return true;
303}
304
305/** Walk the OpenFirmware device tree and find devices by type.
306 *
307 * Walk the whole OpenFirmware device tree and if any node has
308 * the property "device_type" equal to dtype, run a walker on it.
309 * If the walker returns false, the walk does not continue.
310 *
311 * @param dtype Device type to look for.
312 * @param walker Routine to be invoked on found device.
313 * @param arg User argument to the walker.
314 *
315 */
316void ofw_tree_walk_by_device_type(const char *dtype, ofw_tree_walker_t walker,
317 void *arg)
318{
319 (void) ofw_tree_walk_by_device_type_internal(ofw_root, dtype, walker, arg);
320}
321
322/** Get OpenFirmware node properties.
323 *
324 * @param item Sysinfo item (unused).
325 * @param size Size of the returned data.
326 * @param dry_run Do not get the data, just calculate the size.
327 * @param data OpenFirmware node.
328 *
329 * @return Data containing a serialized dump of all node
330 * properties. If the return value is not NULL, it
331 * should be freed in the context of the sysinfo request.
332 *
333 */
334static void *ofw_sysinfo_properties(struct sysinfo_item *item, size_t *size,
335 bool dry_run, void *data)
336{
337 ofw_tree_node_t *node = (ofw_tree_node_t *) data;
338
339 /* Compute serialized data size */
340 *size = 0;
341 for (size_t i = 0; i < node->properties; i++)
342 *size += str_size(node->property[i].name) + 1 +
343 sizeof(node->property[i].size) + node->property[i].size;
344
345 if (dry_run)
346 return NULL;
347
348 void *dump = malloc(*size, FRAME_ATOMIC);
349 if (dump == NULL) {
350 *size = 0;
351 return NULL;
352 }
353
354 /* Serialize the data */
355 size_t pos = 0;
356 for (size_t i = 0; i < node->properties; i++) {
357 /* Property name */
358 str_cpy(dump + pos, *size - pos, node->property[i].name);
359 pos += str_size(node->property[i].name) + 1;
360
361 /* Value size */
362 memcpy(dump + pos, &node->property[i].size,
363 sizeof(node->property[i].size));
364 pos += sizeof(node->property[i].size);
365
366 /* Value */
367 memcpy(dump + pos, node->property[i].value,
368 node->property[i].size);
369 pos += node->property[i].size;
370 }
371
372 return ((void *) dump);
373}
374
375/** Map OpenFirmware device subtree rooted in a node into sysinfo.
376 *
377 * Child nodes are processed recursively and peer nodes are processed
378 * iteratively in order to avoid stack overflow.
379 *
380 * @param node Root of the subtree.
381 * @param path Current path, NULL for the very root of the entire tree.
382 *
383 */
384static void ofw_tree_node_sysinfo(ofw_tree_node_t *node, const char *path)
385{
386 char *cur_path = (char *) malloc(PATH_MAX_LEN, 0);
387
388 for (ofw_tree_node_t *cur = node; cur; cur = cur->peer) {
389 if ((cur->parent) && (path))
390 snprintf(cur_path, PATH_MAX_LEN, "%s.%s", path, cur->da_name);
391 else
392 snprintf(cur_path, PATH_MAX_LEN, "firmware.%s", cur->da_name);
393
394 sysinfo_set_item_gen_data(cur_path, NULL, ofw_sysinfo_properties,
395 (void *) cur);
396
397 if (cur->child)
398 ofw_tree_node_sysinfo(cur->child, cur_path);
399 }
400
401 free(cur_path);
402}
403
404/** Map the OpenFirmware device tree into sysinfo. */
405void ofw_sysinfo_map(void)
406{
407 ofw_tree_node_sysinfo(ofw_root, NULL);
408}
409
410/** @}
411 */
Note: See TracBrowser for help on using the repository browser.