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
RevLine 
[61e90dd]1/*
[df4ed85]2 * Copyright (c) 2006 Jakub Jermar
[61e90dd]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
[e731b0d]34 * @brief OpenFirmware device tree navigation.
[61e90dd]35 *
36 */
37
[16529d5]38#include <genarch/ofw/ofw_tree.h>
[1b43a04]39#include <mm/slab.h>
[63b5493]40#include <memstr.h>
[19f857a]41#include <str.h>
[16529d5]42#include <panic.h>
[e731b0d]43#include <print.h>
[16529d5]44
[e731b0d]45#define PATH_MAX_LEN 256
46#define NAME_BUF_LEN 50
[16529d5]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
[28ecadb]55/** Get OpenFirmware node property.
56 *
[e731b0d]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.
[28ecadb]62 *
63 */
[e731b0d]64ofw_tree_property_t *ofw_tree_getprop(const ofw_tree_node_t *node,
65 const char *name)
[28ecadb]66{
[8b9a443]67 for (size_t i = 0; i < node->properties; i++) {
[b60c582]68 if (str_cmp(node->property[i].name, name) == 0)
[28ecadb]69 return &node->property[i];
70 }
[e731b0d]71
[28ecadb]72 return NULL;
73}
74
[16529d5]75/** Return value of the 'name' property.
76 *
[e731b0d]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.
[16529d5]81 *
82 */
83const char *ofw_tree_node_name(const ofw_tree_node_t *node)
84{
[e731b0d]85 ofw_tree_property_t *prop = ofw_tree_getprop(node, "name");
86 if ((!prop) || (prop->size < 2))
87 return NULL;
[16529d5]88
[28ecadb]89 return prop->value;
[16529d5]90}
91
92/** Lookup child of given name.
93 *
[e731b0d]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.
[16529d5]99 *
100 */
[e731b0d]101ofw_tree_node_t *ofw_tree_find_child(ofw_tree_node_t *node,
102 const char *name)
[16529d5]103{
[28ecadb]104 /*
105 * Try to find the disambigued name.
106 */
[8b9a443]107 for (ofw_tree_node_t *cur = node->child; cur; cur = cur->peer) {
[b60c582]108 if (str_cmp(cur->da_name, name) == 0)
[16529d5]109 return cur;
110 }
111
[28ecadb]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 */
[8b9a443]119 for (ofw_tree_node_t *cur = node->child; cur; cur = cur->peer) {
[b60c582]120 if (str_cmp(ofw_tree_node_name(cur), name) == 0)
[28ecadb]121 return cur;
122 }
[e731b0d]123
[16529d5]124 return NULL;
125}
126
[45b26dad]127/** Lookup first child of given device type.
128 *
[e731b0d]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.
[45b26dad]134 *
135 */
[e731b0d]136ofw_tree_node_t *ofw_tree_find_child_by_device_type(ofw_tree_node_t *node,
137 const char *dtype)
[45b26dad]138{
[8b9a443]139 for (ofw_tree_node_t *cur = node->child; cur; cur = cur->peer) {
[e731b0d]140 ofw_tree_property_t *prop =
141 ofw_tree_getprop(cur, "device_type");
142
143 if ((!prop) || (!prop->value))
[45b26dad]144 continue;
[e731b0d]145
146 if (str_cmp(prop->value, dtype) == 0)
[45b26dad]147 return cur;
148 }
[e731b0d]149
[45b26dad]150 return NULL;
151}
152
[36db5ac]153/** Lookup node with matching node_handle.
[2f8f480]154 *
155 * Child nodes are looked up recursively contrary to peer nodes that
156 * are looked up iteratively to avoid stack overflow.
[36db5ac]157 *
[e731b0d]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.
[36db5ac]163 *
164 */
[e731b0d]165ofw_tree_node_t *ofw_tree_find_node_by_handle(ofw_tree_node_t *root,
[4872160]166 phandle handle)
[36db5ac]167{
[8b9a443]168 for (ofw_tree_node_t *cur = root; cur; cur = cur->peer) {
[2f8f480]169 if (cur->node_handle == handle)
170 return cur;
[e731b0d]171
[2f8f480]172 if (cur->child) {
[8b9a443]173 ofw_tree_node_t *node =
174 ofw_tree_find_node_by_handle(cur->child, handle);
[2f8f480]175 if (node)
176 return node;
177 }
[36db5ac]178 }
179
[e731b0d]180 return NULL;
[36db5ac]181}
182
[45b26dad]183/** Lookup first peer of given device type.
184 *
[e731b0d]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.
[45b26dad]190 *
191 */
[e731b0d]192ofw_tree_node_t *ofw_tree_find_peer_by_device_type(ofw_tree_node_t *node,
193 const char *dtype)
[45b26dad]194{
[8b9a443]195 for (ofw_tree_node_t *cur = node->peer; cur; cur = cur->peer) {
[e731b0d]196 ofw_tree_property_t *prop =
197 ofw_tree_getprop(cur, "device_type");
198
199 if ((!prop) || (!prop->value))
[45b26dad]200 continue;
[e731b0d]201
202 if (str_cmp(prop->value, dtype) == 0)
[45b26dad]203 return cur;
204 }
[e731b0d]205
[45b26dad]206 return NULL;
207}
208
[965dc18]209/** Lookup first peer of given name.
210 *
[e731b0d]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.
[965dc18]216 *
217 */
[e731b0d]218ofw_tree_node_t *ofw_tree_find_peer_by_name(ofw_tree_node_t *node,
219 const char *name)
[965dc18]220{
[8b9a443]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");
[e731b0d]224
225 if ((!prop) || (!prop->value))
[965dc18]226 continue;
[e731b0d]227
[b60c582]228 if (str_cmp(prop->value, name) == 0)
[965dc18]229 return cur;
230 }
[e731b0d]231
[965dc18]232 return NULL;
233}
234
[16529d5]235/** Lookup OpenFirmware node by its path.
236 *
[e731b0d]237 * @param path Path to the node.
238 *
239 * @return NULL if there is no such node or pointer to the leaf
240 * node.
[16529d5]241 *
242 */
243ofw_tree_node_t *ofw_tree_lookup(const char *path)
244{
[e731b0d]245 if (path[0] != '/')
246 return NULL;
247
[16529d5]248 ofw_tree_node_t *node = ofw_root;
[98000fb]249 size_t j;
[16529d5]250
[8b9a443]251 for (size_t i = 1; (i < str_size(path)) && (node); i = j + 1) {
[b60c582]252 for (j = i; (j < str_size(path)) && (path[j] != '/'); j++);
253
254 /* Skip extra slashes */
255 if (i == j)
[16529d5]256 continue;
[b60c582]257
[e731b0d]258 char buf[NAME_BUF_LEN + 1];
[16529d5]259 memcpy(buf, &path[i], j - i);
[b60c582]260 buf[j - i] = 0;
[16529d5]261 node = ofw_tree_find_child(node, buf);
262 }
263
264 return node;
265}
266
[e731b0d]267/** Walk the OpenFirmware device subtree rooted in a node.
[2f8f480]268 *
269 * Child nodes are processed recursively and peer nodes are processed
270 * iteratively in order to avoid stack overflow.
[16529d5]271 *
[e731b0d]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 *
[16529d5]279 */
[e731b0d]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)
[16529d5]282{
[8b9a443]283 for (ofw_tree_node_t *cur = node; cur; cur = cur->peer) {
[e731b0d]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}
[1b43a04]303
[e731b0d]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}
[1b43a04]320
[e731b0d]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
[2f8f480]335 for (cur = node; cur; cur = cur->peer) {
[e731b0d]336 if ((cur->parent) && (path)) {
337 snprintf(cur_path, PATH_MAX_LEN, "%s/%s", path, cur->da_name);
338 printf("%s\n", cur_path);
[2f8f480]339 } else {
[e731b0d]340 snprintf(cur_path, PATH_MAX_LEN, "%s", cur->da_name);
[2f8f480]341 printf("/\n");
342 }
[e731b0d]343
[2f8f480]344 if (cur->child)
[e731b0d]345 ofw_tree_node_print(cur->child, cur_path);
[2f8f480]346 }
[e731b0d]347
348 free(cur_path);
[16529d5]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
[61e90dd]357/** @}
358 */
Note: See TracBrowser for help on using the repository browser.