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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 730376d was 2f8f480, checked in by Jakub Jermar <jakub@…>, 19 years ago

Rewrite OFW device tree traversal algorithms to iterate over the list of peers rather than recurse on each
peer node. This saves us from big troubles with stack overflows.

  • Property mode set to 100644
File size: 6.8 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 <arch/memstr.h>
40#include <mm/slab.h>
41#include <func.h>
42#include <print.h>
43#include <panic.h>
44
45#define PATH_MAX_LEN 80
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 property.
61 */
62ofw_tree_property_t *ofw_tree_getprop(const ofw_tree_node_t *node, const char *name)
63{
64 int i;
65
66 for (i = 0; i < node->properties; i++) {
67 if (strcmp(node->property[i].name, name) == 0)
68 return &node->property[i];
69 }
70
71 return NULL;
72}
73
74/** Return value of the 'name' property.
75 *
76 * @param node Node of interest.
77 *
78 * @return Value of the 'name' property belonging to the node.
79 */
80const char *ofw_tree_node_name(const ofw_tree_node_t *node)
81{
82 ofw_tree_property_t *prop;
83
84 prop = ofw_tree_getprop(node, "name");
85 if (!prop)
86 panic("Node without name property.\n");
87
88 if (prop->size < 2)
89 panic("Invalid name property.\n");
90
91 return prop->value;
92}
93
94/** Lookup child of given name.
95 *
96 * @param node Node whose child is being looked up.
97 * @param name Name of the child being looked up.
98 *
99 * @return NULL if there is no such child or pointer to the matching child node.
100 */
101ofw_tree_node_t *ofw_tree_find_child(ofw_tree_node_t *node, const char *name)
102{
103 ofw_tree_node_t *cur;
104
105 /*
106 * Try to find the disambigued name.
107 */
108 for (cur = node->child; cur; cur = cur->peer) {
109 if (strcmp(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 (cur = node->child; cur; cur = cur->peer) {
121 if (strcmp(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 name Device type of the child being looked up.
132 *
133 * @return NULL if there is no such child or pointer to the matching child node.
134 */
135ofw_tree_node_t *ofw_tree_find_child_by_device_type(ofw_tree_node_t *node, const char *name)
136{
137 ofw_tree_node_t *cur;
138 ofw_tree_property_t *prop;
139
140 for (cur = node->child; cur; cur = cur->peer) {
141 prop = ofw_tree_getprop(cur, "device_type");
142 if (!prop || !prop->value)
143 continue;
144 if (strcmp(prop->value, name) == 0)
145 return cur;
146 }
147
148 return NULL;
149}
150
151/** Lookup node with matching node_handle.
152 *
153 * Child nodes are looked up recursively contrary to peer nodes that
154 * are looked up iteratively to avoid stack overflow.
155 *
156 * @param root Root of the searched subtree.
157 * @param handle OpenFirmware handle.
158 *
159 * @return NULL if there is no such node or pointer to the matching node.
160 */
161ofw_tree_node_t *ofw_tree_find_node_by_handle(ofw_tree_node_t *root, uint32_t handle)
162{
163 ofw_tree_node_t *cur;
164
165 for (cur = root; cur; cur = cur->peer) {
166 if (cur->node_handle == handle)
167 return cur;
168
169 if (cur->child) {
170 ofw_tree_node_t *node;
171
172 node = ofw_tree_find_node_by_handle(cur->child, handle);
173 if (node)
174 return node;
175 }
176 }
177
178 return NULL;
179}
180
181/** Lookup first peer of given device type.
182 *
183 * @param node Node whose peer is being looked up.
184 * @param name Device type of the child being looked up.
185 *
186 * @return NULL if there is no such child or pointer to the matching child node.
187 */
188ofw_tree_node_t *ofw_tree_find_peer_by_device_type(ofw_tree_node_t *node, const char *name)
189{
190 ofw_tree_node_t *cur;
191 ofw_tree_property_t *prop;
192
193 for (cur = node->peer; cur; cur = cur->peer) {
194 prop = ofw_tree_getprop(cur, "device_type");
195 if (!prop || !prop->value)
196 continue;
197 if (strcmp(prop->value, name) == 0)
198 return cur;
199 }
200
201 return NULL;
202}
203
204
205/** Lookup OpenFirmware node by its path.
206 *
207 * @param path Path to the node.
208 *
209 * @return NULL if there is no such node or pointer to the leaf node.
210 */
211ofw_tree_node_t *ofw_tree_lookup(const char *path)
212{
213 char buf[NAME_BUF_LEN+1];
214 ofw_tree_node_t *node = ofw_root;
215 index_t i, j;
216
217 if (path[0] != '/')
218 return NULL;
219
220 for (i = 1; i < strlen(path) && node; i = j + 1) {
221 for (j = i; j < strlen(path) && path[j] != '/'; j++)
222 ;
223 if (i == j) /* skip extra slashes */
224 continue;
225
226 memcpy(buf, &path[i], j - i);
227 buf[j - i] = '\0';
228 node = ofw_tree_find_child(node, buf);
229 }
230
231 return node;
232}
233
234/** Print OpenFirmware device subtree rooted in a node.
235 *
236 * Child nodes are processed recursively and peer nodes are processed
237 * iteratively in order to avoid stack overflow.
238 *
239 * @param node Root of the subtree.
240 * @param path Current path, NULL for the very root of the entire tree.
241 */
242static void ofw_tree_node_print(const ofw_tree_node_t *node, const char *path)
243{
244 char *p;
245 const ofw_tree_node_t *cur;
246
247 p = (char *) malloc(PATH_MAX_LEN, 0);
248
249 for (cur = node; cur; cur = cur->peer) {
250 if (cur->parent) {
251 snprintf(p, PATH_MAX_LEN, "%s/%s", path, cur->da_name);
252 printf("%s\n", p);
253 } else {
254 snprintf(p, PATH_MAX_LEN, "%s", cur->da_name);
255 printf("/\n");
256 }
257
258 if (cur->child)
259 ofw_tree_node_print(cur->child, p);
260 }
261
262 free(p);
263}
264
265/** Print the structure of the OpenFirmware device tree. */
266void ofw_tree_print(void)
267{
268 ofw_tree_node_print(ofw_root, NULL);
269}
270
271/** @}
272 */
Note: See TracBrowser for help on using the repository browser.