1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 1994,1998-2000,2002 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate #include <sys/promif.h> 30*0Sstevel@tonic-gate #include <sys/promimpl.h> 31*0Sstevel@tonic-gate 32*0Sstevel@tonic-gate /* 33*0Sstevel@tonic-gate * Routines for walking the PROMs devinfo tree 34*0Sstevel@tonic-gate */ 35*0Sstevel@tonic-gate dnode_t 36*0Sstevel@tonic-gate prom_nextnode(dnode_t nodeid) 37*0Sstevel@tonic-gate { 38*0Sstevel@tonic-gate cell_t ci[5]; 39*0Sstevel@tonic-gate 40*0Sstevel@tonic-gate ci[0] = p1275_ptr2cell("peer"); /* Service name */ 41*0Sstevel@tonic-gate ci[1] = (cell_t)1; /* #argument cells */ 42*0Sstevel@tonic-gate ci[2] = (cell_t)1; /* #result cells */ 43*0Sstevel@tonic-gate ci[3] = p1275_dnode2cell(nodeid); /* Arg1: input phandle */ 44*0Sstevel@tonic-gate ci[4] = p1275_dnode2cell(OBP_NONODE); /* Res1: Prime result */ 45*0Sstevel@tonic-gate 46*0Sstevel@tonic-gate promif_preprom(); 47*0Sstevel@tonic-gate (void) p1275_cif_handler(&ci); 48*0Sstevel@tonic-gate promif_postprom(); 49*0Sstevel@tonic-gate 50*0Sstevel@tonic-gate return (p1275_cell2dnode(ci[4])); /* Res1: peer phandle */ 51*0Sstevel@tonic-gate } 52*0Sstevel@tonic-gate 53*0Sstevel@tonic-gate dnode_t 54*0Sstevel@tonic-gate prom_childnode(dnode_t nodeid) 55*0Sstevel@tonic-gate { 56*0Sstevel@tonic-gate cell_t ci[5]; 57*0Sstevel@tonic-gate 58*0Sstevel@tonic-gate ci[0] = p1275_ptr2cell("child"); /* Service name */ 59*0Sstevel@tonic-gate ci[1] = (cell_t)1; /* #argument cells */ 60*0Sstevel@tonic-gate ci[2] = (cell_t)1; /* #result cells */ 61*0Sstevel@tonic-gate ci[3] = p1275_dnode2cell(nodeid); /* Arg1: input phandle */ 62*0Sstevel@tonic-gate ci[4] = p1275_dnode2cell(OBP_NONODE); /* Res1: Prime result */ 63*0Sstevel@tonic-gate 64*0Sstevel@tonic-gate promif_preprom(); 65*0Sstevel@tonic-gate (void) p1275_cif_handler(&ci); 66*0Sstevel@tonic-gate promif_postprom(); 67*0Sstevel@tonic-gate 68*0Sstevel@tonic-gate return (p1275_cell2dnode(ci[4])); /* Res1: child phandle */ 69*0Sstevel@tonic-gate } 70*0Sstevel@tonic-gate 71*0Sstevel@tonic-gate /* 72*0Sstevel@tonic-gate * prom_walk_devs() implements a generic walker for the OBP tree; this 73*0Sstevel@tonic-gate * implementation uses an explicitly managed stack in order to save the 74*0Sstevel@tonic-gate * overhead of a recursive implementation. 75*0Sstevel@tonic-gate */ 76*0Sstevel@tonic-gate void 77*0Sstevel@tonic-gate prom_walk_devs(dnode_t node, int (*cb)(dnode_t, void *, void *), void *arg, 78*0Sstevel@tonic-gate void *result) 79*0Sstevel@tonic-gate { 80*0Sstevel@tonic-gate dnode_t stack[OBP_STACKDEPTH]; 81*0Sstevel@tonic-gate int stackidx = 0; 82*0Sstevel@tonic-gate 83*0Sstevel@tonic-gate if (node == OBP_NONODE || node == OBP_BADNODE) { 84*0Sstevel@tonic-gate prom_panic("Invalid node specified as root of prom tree walk"); 85*0Sstevel@tonic-gate } 86*0Sstevel@tonic-gate 87*0Sstevel@tonic-gate stack[0] = node; 88*0Sstevel@tonic-gate 89*0Sstevel@tonic-gate for (;;) { 90*0Sstevel@tonic-gate dnode_t curnode = stack[stackidx]; 91*0Sstevel@tonic-gate dnode_t child; 92*0Sstevel@tonic-gate 93*0Sstevel@tonic-gate /* 94*0Sstevel@tonic-gate * We're out of stuff to do at this level, bump back up a level 95*0Sstevel@tonic-gate * in the tree, and move to the next node; if the new level 96*0Sstevel@tonic-gate * will be level -1, we're done. 97*0Sstevel@tonic-gate */ 98*0Sstevel@tonic-gate if (curnode == OBP_NONODE || curnode == OBP_BADNODE) { 99*0Sstevel@tonic-gate stackidx--; 100*0Sstevel@tonic-gate 101*0Sstevel@tonic-gate if (stackidx < 0) 102*0Sstevel@tonic-gate return; 103*0Sstevel@tonic-gate 104*0Sstevel@tonic-gate stack[stackidx] = prom_nextnode(stack[stackidx]); 105*0Sstevel@tonic-gate continue; 106*0Sstevel@tonic-gate } 107*0Sstevel@tonic-gate 108*0Sstevel@tonic-gate switch ((*cb)(curnode, arg, result)) { 109*0Sstevel@tonic-gate 110*0Sstevel@tonic-gate case PROM_WALK_TERMINATE: 111*0Sstevel@tonic-gate return; 112*0Sstevel@tonic-gate 113*0Sstevel@tonic-gate case PROM_WALK_CONTINUE: 114*0Sstevel@tonic-gate /* 115*0Sstevel@tonic-gate * If curnode has a child, traverse to it, 116*0Sstevel@tonic-gate * otherwise move to curnode's sibling. 117*0Sstevel@tonic-gate */ 118*0Sstevel@tonic-gate child = prom_childnode(curnode); 119*0Sstevel@tonic-gate if (child != OBP_NONODE && child != OBP_BADNODE) { 120*0Sstevel@tonic-gate stackidx++; 121*0Sstevel@tonic-gate stack[stackidx] = child; 122*0Sstevel@tonic-gate } else { 123*0Sstevel@tonic-gate stack[stackidx] = 124*0Sstevel@tonic-gate prom_nextnode(stack[stackidx]); 125*0Sstevel@tonic-gate } 126*0Sstevel@tonic-gate break; 127*0Sstevel@tonic-gate 128*0Sstevel@tonic-gate default: 129*0Sstevel@tonic-gate prom_panic("unrecognized walk directive"); 130*0Sstevel@tonic-gate } 131*0Sstevel@tonic-gate } 132*0Sstevel@tonic-gate } 133*0Sstevel@tonic-gate 134*0Sstevel@tonic-gate /* 135*0Sstevel@tonic-gate * prom_findnode_bydevtype() searches the prom device subtree rooted at 'node' 136*0Sstevel@tonic-gate * and returns the first node whose device type property matches the type 137*0Sstevel@tonic-gate * supplied in 'devtype'. 138*0Sstevel@tonic-gate */ 139*0Sstevel@tonic-gate static int 140*0Sstevel@tonic-gate bytype_cb(dnode_t node, void *arg, void *result) 141*0Sstevel@tonic-gate { 142*0Sstevel@tonic-gate if (prom_devicetype(node, (char *)arg)) { 143*0Sstevel@tonic-gate *((dnode_t *)result) = node; 144*0Sstevel@tonic-gate return (PROM_WALK_TERMINATE); 145*0Sstevel@tonic-gate } 146*0Sstevel@tonic-gate return (PROM_WALK_CONTINUE); 147*0Sstevel@tonic-gate } 148*0Sstevel@tonic-gate 149*0Sstevel@tonic-gate dnode_t 150*0Sstevel@tonic-gate prom_findnode_bydevtype(dnode_t node, char *devtype) 151*0Sstevel@tonic-gate { 152*0Sstevel@tonic-gate dnode_t result = OBP_NONODE; 153*0Sstevel@tonic-gate prom_walk_devs(node, bytype_cb, devtype, &result); 154*0Sstevel@tonic-gate return (result); 155*0Sstevel@tonic-gate } 156*0Sstevel@tonic-gate 157*0Sstevel@tonic-gate 158*0Sstevel@tonic-gate /* 159*0Sstevel@tonic-gate * prom_findnode_byname() searches the prom device subtree rooted at 'node' and 160*0Sstevel@tonic-gate * returns the first node whose name matches the name supplied in 'name'. 161*0Sstevel@tonic-gate */ 162*0Sstevel@tonic-gate static int 163*0Sstevel@tonic-gate byname_cb(dnode_t node, void *arg, void *result) 164*0Sstevel@tonic-gate { 165*0Sstevel@tonic-gate if (prom_getnode_byname(node, (char *)arg)) { 166*0Sstevel@tonic-gate *((dnode_t *)result) = node; 167*0Sstevel@tonic-gate return (PROM_WALK_TERMINATE); 168*0Sstevel@tonic-gate } 169*0Sstevel@tonic-gate return (PROM_WALK_CONTINUE); 170*0Sstevel@tonic-gate } 171*0Sstevel@tonic-gate 172*0Sstevel@tonic-gate dnode_t 173*0Sstevel@tonic-gate prom_findnode_byname(dnode_t node, char *name) 174*0Sstevel@tonic-gate { 175*0Sstevel@tonic-gate dnode_t result = OBP_NONODE; 176*0Sstevel@tonic-gate prom_walk_devs(node, byname_cb, name, &result); 177*0Sstevel@tonic-gate return (result); 178*0Sstevel@tonic-gate } 179*0Sstevel@tonic-gate 180*0Sstevel@tonic-gate /* 181*0Sstevel@tonic-gate * Return the root nodeid. 182*0Sstevel@tonic-gate * Calling prom_nextnode(0) returns the root nodeid. 183*0Sstevel@tonic-gate */ 184*0Sstevel@tonic-gate dnode_t 185*0Sstevel@tonic-gate prom_rootnode(void) 186*0Sstevel@tonic-gate { 187*0Sstevel@tonic-gate static dnode_t rootnode; 188*0Sstevel@tonic-gate 189*0Sstevel@tonic-gate return (rootnode ? rootnode : (rootnode = prom_nextnode(OBP_NONODE))); 190*0Sstevel@tonic-gate } 191*0Sstevel@tonic-gate 192*0Sstevel@tonic-gate dnode_t 193*0Sstevel@tonic-gate prom_parentnode(dnode_t nodeid) 194*0Sstevel@tonic-gate { 195*0Sstevel@tonic-gate cell_t ci[5]; 196*0Sstevel@tonic-gate 197*0Sstevel@tonic-gate ci[0] = p1275_ptr2cell("parent"); /* Service name */ 198*0Sstevel@tonic-gate ci[1] = (cell_t)1; /* #argument cells */ 199*0Sstevel@tonic-gate ci[2] = (cell_t)1; /* #result cells */ 200*0Sstevel@tonic-gate ci[3] = p1275_dnode2cell(nodeid); /* Arg1: input phandle */ 201*0Sstevel@tonic-gate ci[4] = p1275_dnode2cell(OBP_NONODE); /* Res1: Prime result */ 202*0Sstevel@tonic-gate 203*0Sstevel@tonic-gate promif_preprom(); 204*0Sstevel@tonic-gate (void) p1275_cif_handler(&ci); 205*0Sstevel@tonic-gate promif_postprom(); 206*0Sstevel@tonic-gate 207*0Sstevel@tonic-gate return (p1275_cell2dnode(ci[4])); /* Res1: parent phandle */ 208*0Sstevel@tonic-gate } 209*0Sstevel@tonic-gate 210*0Sstevel@tonic-gate dnode_t 211*0Sstevel@tonic-gate prom_finddevice(char *path) 212*0Sstevel@tonic-gate { 213*0Sstevel@tonic-gate cell_t ci[5]; 214*0Sstevel@tonic-gate #ifdef PROM_32BIT_ADDRS 215*0Sstevel@tonic-gate char *opath = NULL; 216*0Sstevel@tonic-gate size_t len; 217*0Sstevel@tonic-gate 218*0Sstevel@tonic-gate if ((uintptr_t)path > (uint32_t)-1) { 219*0Sstevel@tonic-gate opath = path; 220*0Sstevel@tonic-gate len = prom_strlen(opath) + 1; /* include terminating NUL */ 221*0Sstevel@tonic-gate path = promplat_alloc(len); 222*0Sstevel@tonic-gate if (path == NULL) { 223*0Sstevel@tonic-gate return (OBP_BADNODE); 224*0Sstevel@tonic-gate } 225*0Sstevel@tonic-gate (void) prom_strcpy(path, opath); 226*0Sstevel@tonic-gate } 227*0Sstevel@tonic-gate #endif 228*0Sstevel@tonic-gate 229*0Sstevel@tonic-gate promif_preprom(); 230*0Sstevel@tonic-gate 231*0Sstevel@tonic-gate ci[0] = p1275_ptr2cell("finddevice"); /* Service name */ 232*0Sstevel@tonic-gate ci[1] = (cell_t)1; /* #argument cells */ 233*0Sstevel@tonic-gate ci[2] = (cell_t)1; /* #result cells */ 234*0Sstevel@tonic-gate ci[3] = p1275_ptr2cell(path); /* Arg1: pathname */ 235*0Sstevel@tonic-gate ci[4] = p1275_dnode2cell(OBP_BADNODE); /* Res1: Prime result */ 236*0Sstevel@tonic-gate 237*0Sstevel@tonic-gate (void) p1275_cif_handler(&ci); 238*0Sstevel@tonic-gate 239*0Sstevel@tonic-gate promif_postprom(); 240*0Sstevel@tonic-gate 241*0Sstevel@tonic-gate #ifdef PROM_32BIT_ADDRS 242*0Sstevel@tonic-gate if (opath != NULL) 243*0Sstevel@tonic-gate promplat_free(path, len); 244*0Sstevel@tonic-gate #endif 245*0Sstevel@tonic-gate 246*0Sstevel@tonic-gate return ((dnode_t)p1275_cell2dnode(ci[4])); /* Res1: phandle */ 247*0Sstevel@tonic-gate } 248*0Sstevel@tonic-gate 249*0Sstevel@tonic-gate dnode_t 250*0Sstevel@tonic-gate prom_chosennode(void) 251*0Sstevel@tonic-gate { 252*0Sstevel@tonic-gate static dnode_t chosen; 253*0Sstevel@tonic-gate dnode_t node; 254*0Sstevel@tonic-gate 255*0Sstevel@tonic-gate if (chosen) 256*0Sstevel@tonic-gate return (chosen); 257*0Sstevel@tonic-gate 258*0Sstevel@tonic-gate node = prom_finddevice("/chosen"); 259*0Sstevel@tonic-gate 260*0Sstevel@tonic-gate if (node != OBP_BADNODE) 261*0Sstevel@tonic-gate return (chosen = node); 262*0Sstevel@tonic-gate 263*0Sstevel@tonic-gate prom_fatal_error("prom_chosennode: Can't find </chosen>\n"); 264*0Sstevel@tonic-gate /*NOTREACHED*/ 265*0Sstevel@tonic-gate } 266*0Sstevel@tonic-gate 267*0Sstevel@tonic-gate /* 268*0Sstevel@tonic-gate * Returns the nodeid of /aliases. 269*0Sstevel@tonic-gate * /aliases exists in OBP >= 2.4 and in Open Firmware. 270*0Sstevel@tonic-gate * Returns OBP_BADNODE if it doesn't exist. 271*0Sstevel@tonic-gate */ 272*0Sstevel@tonic-gate dnode_t 273*0Sstevel@tonic-gate prom_alias_node(void) 274*0Sstevel@tonic-gate { 275*0Sstevel@tonic-gate static dnode_t node; 276*0Sstevel@tonic-gate 277*0Sstevel@tonic-gate if (node == 0) 278*0Sstevel@tonic-gate node = prom_finddevice("/aliases"); 279*0Sstevel@tonic-gate return (node); 280*0Sstevel@tonic-gate } 281*0Sstevel@tonic-gate 282*0Sstevel@tonic-gate /* 283*0Sstevel@tonic-gate * Returns the nodeid of /options. 284*0Sstevel@tonic-gate * Returns OBP_BADNODE if it doesn't exist. 285*0Sstevel@tonic-gate */ 286*0Sstevel@tonic-gate dnode_t 287*0Sstevel@tonic-gate prom_optionsnode(void) 288*0Sstevel@tonic-gate { 289*0Sstevel@tonic-gate static dnode_t node; 290*0Sstevel@tonic-gate 291*0Sstevel@tonic-gate if (node == 0) 292*0Sstevel@tonic-gate node = prom_finddevice("/options"); 293*0Sstevel@tonic-gate return (node); 294*0Sstevel@tonic-gate } 295