import less(1)
[unleashed/tickless.git] / usr / src / psm / promif / ieee1275 / common / prom_node.c
blobefcd18a3045ee8a8e472010d34bda1a134778469
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
20 * CDDL HEADER END
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 #pragma ident "%Z%%M% %I% %E% SMI"
29 #include <sys/promif.h>
30 #include <sys/promimpl.h>
33 * Routines for walking the PROMs devinfo tree
35 pnode_t
36 prom_nextnode(pnode_t nodeid)
38 cell_t ci[5];
40 ci[0] = p1275_ptr2cell("peer"); /* Service name */
41 ci[1] = (cell_t)1; /* #argument cells */
42 ci[2] = (cell_t)1; /* #result cells */
43 ci[3] = p1275_dnode2cell(nodeid); /* Arg1: input phandle */
44 ci[4] = p1275_dnode2cell(OBP_NONODE); /* Res1: Prime result */
46 promif_preprom();
47 (void) p1275_cif_handler(&ci);
48 promif_postprom();
50 return (p1275_cell2dnode(ci[4])); /* Res1: peer phandle */
53 pnode_t
54 prom_childnode(pnode_t nodeid)
56 cell_t ci[5];
58 ci[0] = p1275_ptr2cell("child"); /* Service name */
59 ci[1] = (cell_t)1; /* #argument cells */
60 ci[2] = (cell_t)1; /* #result cells */
61 ci[3] = p1275_dnode2cell(nodeid); /* Arg1: input phandle */
62 ci[4] = p1275_dnode2cell(OBP_NONODE); /* Res1: Prime result */
64 promif_preprom();
65 (void) p1275_cif_handler(&ci);
66 promif_postprom();
68 return (p1275_cell2dnode(ci[4])); /* Res1: child phandle */
72 * prom_walk_devs() implements a generic walker for the OBP tree; this
73 * implementation uses an explicitly managed stack in order to save the
74 * overhead of a recursive implementation.
76 void
77 prom_walk_devs(pnode_t node, int (*cb)(pnode_t, void *, void *), void *arg,
78 void *result)
80 pnode_t stack[OBP_STACKDEPTH];
81 int stackidx = 0;
83 if (node == OBP_NONODE || node == OBP_BADNODE) {
84 prom_panic("Invalid node specified as root of prom tree walk");
87 stack[0] = node;
89 for (;;) {
90 pnode_t curnode = stack[stackidx];
91 pnode_t child;
94 * We're out of stuff to do at this level, bump back up a level
95 * in the tree, and move to the next node; if the new level
96 * will be level -1, we're done.
98 if (curnode == OBP_NONODE || curnode == OBP_BADNODE) {
99 stackidx--;
101 if (stackidx < 0)
102 return;
104 stack[stackidx] = prom_nextnode(stack[stackidx]);
105 continue;
108 switch ((*cb)(curnode, arg, result)) {
110 case PROM_WALK_TERMINATE:
111 return;
113 case PROM_WALK_CONTINUE:
115 * If curnode has a child, traverse to it,
116 * otherwise move to curnode's sibling.
118 child = prom_childnode(curnode);
119 if (child != OBP_NONODE && child != OBP_BADNODE) {
120 stackidx++;
121 stack[stackidx] = child;
122 } else {
123 stack[stackidx] =
124 prom_nextnode(stack[stackidx]);
126 break;
128 default:
129 prom_panic("unrecognized walk directive");
135 * prom_findnode_bydevtype() searches the prom device subtree rooted at 'node'
136 * and returns the first node whose device type property matches the type
137 * supplied in 'devtype'.
139 static int
140 bytype_cb(pnode_t node, void *arg, void *result)
142 if (prom_devicetype(node, (char *)arg)) {
143 *((pnode_t *)result) = node;
144 return (PROM_WALK_TERMINATE);
146 return (PROM_WALK_CONTINUE);
149 pnode_t
150 prom_findnode_bydevtype(pnode_t node, char *devtype)
152 pnode_t result = OBP_NONODE;
153 prom_walk_devs(node, bytype_cb, devtype, &result);
154 return (result);
159 * prom_findnode_byname() searches the prom device subtree rooted at 'node' and
160 * returns the first node whose name matches the name supplied in 'name'.
162 static int
163 byname_cb(pnode_t node, void *arg, void *result)
165 if (prom_getnode_byname(node, (char *)arg)) {
166 *((pnode_t *)result) = node;
167 return (PROM_WALK_TERMINATE);
169 return (PROM_WALK_CONTINUE);
172 pnode_t
173 prom_findnode_byname(pnode_t node, char *name)
175 pnode_t result = OBP_NONODE;
176 prom_walk_devs(node, byname_cb, name, &result);
177 return (result);
181 * Return the root nodeid.
182 * Calling prom_nextnode(0) returns the root nodeid.
184 pnode_t
185 prom_rootnode(void)
187 static pnode_t rootnode;
189 return (rootnode ? rootnode : (rootnode = prom_nextnode(OBP_NONODE)));
192 pnode_t
193 prom_parentnode(pnode_t nodeid)
195 cell_t ci[5];
197 ci[0] = p1275_ptr2cell("parent"); /* Service name */
198 ci[1] = (cell_t)1; /* #argument cells */
199 ci[2] = (cell_t)1; /* #result cells */
200 ci[3] = p1275_dnode2cell(nodeid); /* Arg1: input phandle */
201 ci[4] = p1275_dnode2cell(OBP_NONODE); /* Res1: Prime result */
203 promif_preprom();
204 (void) p1275_cif_handler(&ci);
205 promif_postprom();
207 return (p1275_cell2dnode(ci[4])); /* Res1: parent phandle */
210 pnode_t
211 prom_finddevice(char *path)
213 cell_t ci[5];
214 #ifdef PROM_32BIT_ADDRS
215 char *opath = NULL;
216 size_t len;
218 if ((uintptr_t)path > (uint32_t)-1) {
219 opath = path;
220 len = prom_strlen(opath) + 1; /* include terminating NUL */
221 path = promplat_alloc(len);
222 if (path == NULL) {
223 return (OBP_BADNODE);
225 (void) prom_strcpy(path, opath);
227 #endif
229 promif_preprom();
231 ci[0] = p1275_ptr2cell("finddevice"); /* Service name */
232 ci[1] = (cell_t)1; /* #argument cells */
233 ci[2] = (cell_t)1; /* #result cells */
234 ci[3] = p1275_ptr2cell(path); /* Arg1: pathname */
235 ci[4] = p1275_dnode2cell(OBP_BADNODE); /* Res1: Prime result */
237 (void) p1275_cif_handler(&ci);
239 promif_postprom();
241 #ifdef PROM_32BIT_ADDRS
242 if (opath != NULL)
243 promplat_free(path, len);
244 #endif
246 return ((pnode_t)p1275_cell2dnode(ci[4])); /* Res1: phandle */
249 pnode_t
250 prom_chosennode(void)
252 static pnode_t chosen;
253 pnode_t node;
255 if (chosen)
256 return (chosen);
258 node = prom_finddevice("/chosen");
260 if (node != OBP_BADNODE)
261 return (chosen = node);
263 prom_fatal_error("prom_chosennode: Can't find </chosen>\n");
264 /*NOTREACHED*/
267 * gcc doesn't recognize "NOTREACHED" and puts the warning.
268 * To surpress it, returning an integer value is required.
270 return ((pnode_t)0);
274 * Returns the nodeid of /aliases.
275 * /aliases exists in OBP >= 2.4 and in Open Firmware.
276 * Returns OBP_BADNODE if it doesn't exist.
278 pnode_t
279 prom_alias_node(void)
281 static pnode_t node;
283 if (node == 0)
284 node = prom_finddevice("/aliases");
285 return (node);
289 * Returns the nodeid of /options.
290 * Returns OBP_BADNODE if it doesn't exist.
292 pnode_t
293 prom_optionsnode(void)
295 static pnode_t node;
297 if (node == 0)
298 node = prom_finddevice("/options");
299 return (node);