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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 8b9a443 was 8b9a443, checked in by Martin Decky <martin@…>, 14 years ago

cstyle

  • Property mode set to 100644
File size: 9.1 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 <memstr.h>
41#include <str.h>
42#include <panic.h>
43#include <print.h>
44
45#define PATH_MAX_LEN 256
46#define NAME_BUF_LEN 50
47
48static ofw_tree_node_t *ofw_root;
49
50void ofw_tree_init(ofw_tree_node_t *root)
51{
52 ofw_root = root;
53}
54
55/** Get OpenFirmware node property.
56 *
57 * @param node Node in which to lookup the property.
58 * @param name Name of the property.
59 *
60 * @return Pointer to the property structure or NULL if no such
61 * property.
62 *
63 */
64ofw_tree_property_t *ofw_tree_getprop(const ofw_tree_node_t *node,
65 const char *name)
66{
67 for (size_t i = 0; i < node->properties; i++) {
68 if (str_cmp(node->property[i].name, name) == 0)
69 return &node->property[i];
70 }
71
72 return NULL;
73}
74
75/** Return value of the 'name' property.
76 *
77 * @param node Node of interest.
78 *
79 * @return Value of the 'name' property belonging to the node
80 * or NULL if the property is invalid.
81 *
82 */
83const char *ofw_tree_node_name(const ofw_tree_node_t *node)
84{
85 ofw_tree_property_t *prop = ofw_tree_getprop(node, "name");
86 if ((!prop) || (prop->size < 2))
87 return NULL;
88
89 return prop->value;
90}
91
92/** Lookup child of given name.
93 *
94 * @param node Node whose child is being looked up.
95 * @param name Name of the child being looked up.
96 *
97 * @return NULL if there is no such child or pointer to the
98 * matching child node.
99 *
100 */
101ofw_tree_node_t *ofw_tree_find_child(ofw_tree_node_t *node,
102 const char *name)
103{
104 /*
105 * Try to find the disambigued name.
106 */
107 for (ofw_tree_node_t *cur = node->child; cur; cur = cur->peer) {
108 if (str_cmp(cur->da_name, name) == 0)
109 return cur;
110 }
111
112 /*
113 * Disambigued name not found.
114 * Lets try our luck with possibly ambiguous "name" property.
115 *
116 * We need to do this because paths stored in "/aliases"
117 * are not always fully-qualified.
118 */
119 for (ofw_tree_node_t *cur = node->child; cur; cur = cur->peer) {
120 if (str_cmp(ofw_tree_node_name(cur), name) == 0)
121 return cur;
122 }
123
124 return NULL;
125}
126
127/** Lookup first child of given device type.
128 *
129 * @param node Node whose child is being looked up.
130 * @param dtype Device type of the child being looked up.
131 *
132 * @return NULL if there is no such child or pointer to the
133 * matching child node.
134 *
135 */
136ofw_tree_node_t *ofw_tree_find_child_by_device_type(ofw_tree_node_t *node,
137 const char *dtype)
138{
139 for (ofw_tree_node_t *cur = node->child; cur; cur = cur->peer) {
140 ofw_tree_property_t *prop =
141 ofw_tree_getprop(cur, "device_type");
142
143 if ((!prop) || (!prop->value))
144 continue;
145
146 if (str_cmp(prop->value, dtype) == 0)
147 return cur;
148 }
149
150 return NULL;
151}
152
153/** Lookup node with matching node_handle.
154 *
155 * Child nodes are looked up recursively contrary to peer nodes that
156 * are looked up iteratively to avoid stack overflow.
157 *
158 * @param root Root of the searched subtree.
159 * @param handle OpenFirmware handle.
160 *
161 * @return NULL if there is no such node or pointer to the matching
162 * node.
163 *
164 */
165ofw_tree_node_t *ofw_tree_find_node_by_handle(ofw_tree_node_t *root,
166 phandle handle)
167{
168 for (ofw_tree_node_t *cur = root; cur; cur = cur->peer) {
169 if (cur->node_handle == handle)
170 return cur;
171
172 if (cur->child) {
173 ofw_tree_node_t *node =
174 ofw_tree_find_node_by_handle(cur->child, handle);
175 if (node)
176 return node;
177 }
178 }
179
180 return NULL;
181}
182
183/** Lookup first peer of given device type.
184 *
185 * @param node Node whose peer is being looked up.
186 * @param dtype Device type of the child being looked up.
187 *
188 * @return NULL if there is no such child or pointer to the
189 * matching child node.
190 *
191 */
192ofw_tree_node_t *ofw_tree_find_peer_by_device_type(ofw_tree_node_t *node,
193 const char *dtype)
194{
195 for (ofw_tree_node_t *cur = node->peer; cur; cur = cur->peer) {
196 ofw_tree_property_t *prop =
197 ofw_tree_getprop(cur, "device_type");
198
199 if ((!prop) || (!prop->value))
200 continue;
201
202 if (str_cmp(prop->value, dtype) == 0)
203 return cur;
204 }
205
206 return NULL;
207}
208
209/** Lookup first peer of given name.
210 *
211 * @param node Node whose peer is being looked up.
212 * @param name Name of the child being looked up.
213 *
214 * @return NULL if there is no such peer or pointer to the matching
215 * peer node.
216 *
217 */
218ofw_tree_node_t *ofw_tree_find_peer_by_name(ofw_tree_node_t *node,
219 const char *name)
220{
221 for (ofw_tree_node_t *cur = node->peer; cur; cur = cur->peer) {
222 ofw_tree_property_t *prop =
223 ofw_tree_getprop(cur, "name");
224
225 if ((!prop) || (!prop->value))
226 continue;
227
228 if (str_cmp(prop->value, name) == 0)
229 return cur;
230 }
231
232 return NULL;
233}
234
235/** Lookup OpenFirmware node by its path.
236 *
237 * @param path Path to the node.
238 *
239 * @return NULL if there is no such node or pointer to the leaf
240 * node.
241 *
242 */
243ofw_tree_node_t *ofw_tree_lookup(const char *path)
244{
245 if (path[0] != '/')
246 return NULL;
247
248 ofw_tree_node_t *node = ofw_root;
249 size_t j;
250
251 for (size_t i = 1; (i < str_size(path)) && (node); i = j + 1) {
252 for (j = i; (j < str_size(path)) && (path[j] != '/'); j++);
253
254 /* Skip extra slashes */
255 if (i == j)
256 continue;
257
258 char buf[NAME_BUF_LEN + 1];
259 memcpy(buf, &path[i], j - i);
260 buf[j - i] = 0;
261 node = ofw_tree_find_child(node, buf);
262 }
263
264 return node;
265}
266
267/** Walk the OpenFirmware device subtree rooted in a node.
268 *
269 * Child nodes are processed recursively and peer nodes are processed
270 * iteratively in order to avoid stack overflow.
271 *
272 * @param node Root of the subtree.
273 * @param dtype Device type to look for.
274 * @param walker Routine to be invoked on found device.
275 * @param arg User argument to the walker.
276 *
277 * @return True if the walk should continue.
278 *
279 */
280static bool ofw_tree_walk_by_device_type_internal(ofw_tree_node_t *node,
281 const char *dtype, ofw_tree_walker_t walker, void *arg)
282{
283 for (ofw_tree_node_t *cur = node; cur; cur = cur->peer) {
284 ofw_tree_property_t *prop =
285 ofw_tree_getprop(cur, "device_type");
286
287 if ((prop) && (prop->value) && (str_cmp(prop->value, dtype) == 0)) {
288 bool ret = walker(cur, arg);
289 if (!ret)
290 return false;
291 }
292
293 if (cur->child) {
294 bool ret =
295 ofw_tree_walk_by_device_type_internal(cur->child, dtype, walker, arg);
296 if (!ret)
297 return false;
298 }
299 }
300
301 return true;
302}
303
304/** Walk the OpenFirmware device tree and find devices by type.
305 *
306 * Walk the whole OpenFirmware device tree and if any node has
307 * the property "device_type" equal to dtype, run a walker on it.
308 * If the walker returns false, the walk does not continue.
309 *
310 * @param dtype Device type to look for.
311 * @param walker Routine to be invoked on found device.
312 * @param arg User argument to the walker.
313 *
314 */
315void ofw_tree_walk_by_device_type(const char *dtype, ofw_tree_walker_t walker,
316 void *arg)
317{
318 (void) ofw_tree_walk_by_device_type_internal(ofw_root, dtype, walker, arg);
319}
320
321/** Print OpenFirmware device subtree rooted in a node.
322 *
323 * Child nodes are processed recursively and peer nodes are processed
324 * iteratively in order to avoid stack overflow.
325 *
326 * @param node Root of the subtree.
327 * @param path Current path, NULL for the very root of the entire tree.
328 *
329 */
330static void ofw_tree_node_print(ofw_tree_node_t *node, const char *path)
331{
332 char *cur_path = (char *) malloc(PATH_MAX_LEN, 0);
333 ofw_tree_node_t *cur;
334
335 for (cur = node; cur; cur = cur->peer) {
336 if ((cur->parent) && (path)) {
337 snprintf(cur_path, PATH_MAX_LEN, "%s/%s", path, cur->da_name);
338 printf("%s\n", cur_path);
339 } else {
340 snprintf(cur_path, PATH_MAX_LEN, "%s", cur->da_name);
341 printf("/\n");
342 }
343
344 if (cur->child)
345 ofw_tree_node_print(cur->child, cur_path);
346 }
347
348 free(cur_path);
349}
350
351/** Print the structure of the OpenFirmware device tree. */
352void ofw_tree_print(void)
353{
354 ofw_tree_node_print(ofw_root, NULL);
355}
356
357/** @}
358 */
Note: See TracBrowser for help on using the repository browser.