1*5de18cdeSSam Ravnborg /* 2*5de18cdeSSam Ravnborg * tree.c: Basic device tree traversal/scanning for the Linux 3*5de18cdeSSam Ravnborg * prom library. 4*5de18cdeSSam Ravnborg * 5*5de18cdeSSam Ravnborg * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) 6*5de18cdeSSam Ravnborg * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) 7*5de18cdeSSam Ravnborg */ 8*5de18cdeSSam Ravnborg 9*5de18cdeSSam Ravnborg #include <linux/string.h> 10*5de18cdeSSam Ravnborg #include <linux/types.h> 11*5de18cdeSSam Ravnborg #include <linux/kernel.h> 12*5de18cdeSSam Ravnborg #include <linux/sched.h> 13*5de18cdeSSam Ravnborg 14*5de18cdeSSam Ravnborg #include <asm/openprom.h> 15*5de18cdeSSam Ravnborg #include <asm/oplib.h> 16*5de18cdeSSam Ravnborg #include <asm/ldc.h> 17*5de18cdeSSam Ravnborg 18*5de18cdeSSam Ravnborg /* Return the child of node 'node' or zero if no this node has no 19*5de18cdeSSam Ravnborg * direct descendent. 20*5de18cdeSSam Ravnborg */ 21*5de18cdeSSam Ravnborg inline int __prom_getchild(int node) 22*5de18cdeSSam Ravnborg { 23*5de18cdeSSam Ravnborg return p1275_cmd ("child", P1275_INOUT(1, 1), node); 24*5de18cdeSSam Ravnborg } 25*5de18cdeSSam Ravnborg 26*5de18cdeSSam Ravnborg inline int prom_getchild(int node) 27*5de18cdeSSam Ravnborg { 28*5de18cdeSSam Ravnborg int cnode; 29*5de18cdeSSam Ravnborg 30*5de18cdeSSam Ravnborg if(node == -1) return 0; 31*5de18cdeSSam Ravnborg cnode = __prom_getchild(node); 32*5de18cdeSSam Ravnborg if(cnode == -1) return 0; 33*5de18cdeSSam Ravnborg return (int)cnode; 34*5de18cdeSSam Ravnborg } 35*5de18cdeSSam Ravnborg 36*5de18cdeSSam Ravnborg inline int prom_getparent(int node) 37*5de18cdeSSam Ravnborg { 38*5de18cdeSSam Ravnborg int cnode; 39*5de18cdeSSam Ravnborg 40*5de18cdeSSam Ravnborg if(node == -1) return 0; 41*5de18cdeSSam Ravnborg cnode = p1275_cmd ("parent", P1275_INOUT(1, 1), node); 42*5de18cdeSSam Ravnborg if(cnode == -1) return 0; 43*5de18cdeSSam Ravnborg return (int)cnode; 44*5de18cdeSSam Ravnborg } 45*5de18cdeSSam Ravnborg 46*5de18cdeSSam Ravnborg /* Return the next sibling of node 'node' or zero if no more siblings 47*5de18cdeSSam Ravnborg * at this level of depth in the tree. 48*5de18cdeSSam Ravnborg */ 49*5de18cdeSSam Ravnborg inline int __prom_getsibling(int node) 50*5de18cdeSSam Ravnborg { 51*5de18cdeSSam Ravnborg return p1275_cmd(prom_peer_name, P1275_INOUT(1, 1), node); 52*5de18cdeSSam Ravnborg } 53*5de18cdeSSam Ravnborg 54*5de18cdeSSam Ravnborg inline int prom_getsibling(int node) 55*5de18cdeSSam Ravnborg { 56*5de18cdeSSam Ravnborg int sibnode; 57*5de18cdeSSam Ravnborg 58*5de18cdeSSam Ravnborg if (node == -1) 59*5de18cdeSSam Ravnborg return 0; 60*5de18cdeSSam Ravnborg sibnode = __prom_getsibling(node); 61*5de18cdeSSam Ravnborg if (sibnode == -1) 62*5de18cdeSSam Ravnborg return 0; 63*5de18cdeSSam Ravnborg 64*5de18cdeSSam Ravnborg return sibnode; 65*5de18cdeSSam Ravnborg } 66*5de18cdeSSam Ravnborg 67*5de18cdeSSam Ravnborg /* Return the length in bytes of property 'prop' at node 'node'. 68*5de18cdeSSam Ravnborg * Return -1 on error. 69*5de18cdeSSam Ravnborg */ 70*5de18cdeSSam Ravnborg inline int prom_getproplen(int node, const char *prop) 71*5de18cdeSSam Ravnborg { 72*5de18cdeSSam Ravnborg if((!node) || (!prop)) return -1; 73*5de18cdeSSam Ravnborg return p1275_cmd ("getproplen", 74*5de18cdeSSam Ravnborg P1275_ARG(1,P1275_ARG_IN_STRING)| 75*5de18cdeSSam Ravnborg P1275_INOUT(2, 1), 76*5de18cdeSSam Ravnborg node, prop); 77*5de18cdeSSam Ravnborg } 78*5de18cdeSSam Ravnborg 79*5de18cdeSSam Ravnborg /* Acquire a property 'prop' at node 'node' and place it in 80*5de18cdeSSam Ravnborg * 'buffer' which has a size of 'bufsize'. If the acquisition 81*5de18cdeSSam Ravnborg * was successful the length will be returned, else -1 is returned. 82*5de18cdeSSam Ravnborg */ 83*5de18cdeSSam Ravnborg inline int prom_getproperty(int node, const char *prop, 84*5de18cdeSSam Ravnborg char *buffer, int bufsize) 85*5de18cdeSSam Ravnborg { 86*5de18cdeSSam Ravnborg int plen; 87*5de18cdeSSam Ravnborg 88*5de18cdeSSam Ravnborg plen = prom_getproplen(node, prop); 89*5de18cdeSSam Ravnborg if ((plen > bufsize) || (plen == 0) || (plen == -1)) { 90*5de18cdeSSam Ravnborg return -1; 91*5de18cdeSSam Ravnborg } else { 92*5de18cdeSSam Ravnborg /* Ok, things seem all right. */ 93*5de18cdeSSam Ravnborg return p1275_cmd(prom_getprop_name, 94*5de18cdeSSam Ravnborg P1275_ARG(1,P1275_ARG_IN_STRING)| 95*5de18cdeSSam Ravnborg P1275_ARG(2,P1275_ARG_OUT_BUF)| 96*5de18cdeSSam Ravnborg P1275_INOUT(4, 1), 97*5de18cdeSSam Ravnborg node, prop, buffer, P1275_SIZE(plen)); 98*5de18cdeSSam Ravnborg } 99*5de18cdeSSam Ravnborg } 100*5de18cdeSSam Ravnborg 101*5de18cdeSSam Ravnborg /* Acquire an integer property and return its value. Returns -1 102*5de18cdeSSam Ravnborg * on failure. 103*5de18cdeSSam Ravnborg */ 104*5de18cdeSSam Ravnborg inline int prom_getint(int node, const char *prop) 105*5de18cdeSSam Ravnborg { 106*5de18cdeSSam Ravnborg int intprop; 107*5de18cdeSSam Ravnborg 108*5de18cdeSSam Ravnborg if(prom_getproperty(node, prop, (char *) &intprop, sizeof(int)) != -1) 109*5de18cdeSSam Ravnborg return intprop; 110*5de18cdeSSam Ravnborg 111*5de18cdeSSam Ravnborg return -1; 112*5de18cdeSSam Ravnborg } 113*5de18cdeSSam Ravnborg 114*5de18cdeSSam Ravnborg /* Acquire an integer property, upon error return the passed default 115*5de18cdeSSam Ravnborg * integer. 116*5de18cdeSSam Ravnborg */ 117*5de18cdeSSam Ravnborg 118*5de18cdeSSam Ravnborg int prom_getintdefault(int node, const char *property, int deflt) 119*5de18cdeSSam Ravnborg { 120*5de18cdeSSam Ravnborg int retval; 121*5de18cdeSSam Ravnborg 122*5de18cdeSSam Ravnborg retval = prom_getint(node, property); 123*5de18cdeSSam Ravnborg if(retval == -1) return deflt; 124*5de18cdeSSam Ravnborg 125*5de18cdeSSam Ravnborg return retval; 126*5de18cdeSSam Ravnborg } 127*5de18cdeSSam Ravnborg 128*5de18cdeSSam Ravnborg /* Acquire a boolean property, 1=TRUE 0=FALSE. */ 129*5de18cdeSSam Ravnborg int prom_getbool(int node, const char *prop) 130*5de18cdeSSam Ravnborg { 131*5de18cdeSSam Ravnborg int retval; 132*5de18cdeSSam Ravnborg 133*5de18cdeSSam Ravnborg retval = prom_getproplen(node, prop); 134*5de18cdeSSam Ravnborg if(retval == -1) return 0; 135*5de18cdeSSam Ravnborg return 1; 136*5de18cdeSSam Ravnborg } 137*5de18cdeSSam Ravnborg 138*5de18cdeSSam Ravnborg /* Acquire a property whose value is a string, returns a null 139*5de18cdeSSam Ravnborg * string on error. The char pointer is the user supplied string 140*5de18cdeSSam Ravnborg * buffer. 141*5de18cdeSSam Ravnborg */ 142*5de18cdeSSam Ravnborg void prom_getstring(int node, const char *prop, char *user_buf, int ubuf_size) 143*5de18cdeSSam Ravnborg { 144*5de18cdeSSam Ravnborg int len; 145*5de18cdeSSam Ravnborg 146*5de18cdeSSam Ravnborg len = prom_getproperty(node, prop, user_buf, ubuf_size); 147*5de18cdeSSam Ravnborg if(len != -1) return; 148*5de18cdeSSam Ravnborg user_buf[0] = 0; 149*5de18cdeSSam Ravnborg return; 150*5de18cdeSSam Ravnborg } 151*5de18cdeSSam Ravnborg 152*5de18cdeSSam Ravnborg 153*5de18cdeSSam Ravnborg /* Does the device at node 'node' have name 'name'? 154*5de18cdeSSam Ravnborg * YES = 1 NO = 0 155*5de18cdeSSam Ravnborg */ 156*5de18cdeSSam Ravnborg int prom_nodematch(int node, const char *name) 157*5de18cdeSSam Ravnborg { 158*5de18cdeSSam Ravnborg char namebuf[128]; 159*5de18cdeSSam Ravnborg prom_getproperty(node, "name", namebuf, sizeof(namebuf)); 160*5de18cdeSSam Ravnborg if(strcmp(namebuf, name) == 0) return 1; 161*5de18cdeSSam Ravnborg return 0; 162*5de18cdeSSam Ravnborg } 163*5de18cdeSSam Ravnborg 164*5de18cdeSSam Ravnborg /* Search siblings at 'node_start' for a node with name 165*5de18cdeSSam Ravnborg * 'nodename'. Return node if successful, zero if not. 166*5de18cdeSSam Ravnborg */ 167*5de18cdeSSam Ravnborg int prom_searchsiblings(int node_start, const char *nodename) 168*5de18cdeSSam Ravnborg { 169*5de18cdeSSam Ravnborg 170*5de18cdeSSam Ravnborg int thisnode, error; 171*5de18cdeSSam Ravnborg char promlib_buf[128]; 172*5de18cdeSSam Ravnborg 173*5de18cdeSSam Ravnborg for(thisnode = node_start; thisnode; 174*5de18cdeSSam Ravnborg thisnode=prom_getsibling(thisnode)) { 175*5de18cdeSSam Ravnborg error = prom_getproperty(thisnode, "name", promlib_buf, 176*5de18cdeSSam Ravnborg sizeof(promlib_buf)); 177*5de18cdeSSam Ravnborg /* Should this ever happen? */ 178*5de18cdeSSam Ravnborg if(error == -1) continue; 179*5de18cdeSSam Ravnborg if(strcmp(nodename, promlib_buf)==0) return thisnode; 180*5de18cdeSSam Ravnborg } 181*5de18cdeSSam Ravnborg 182*5de18cdeSSam Ravnborg return 0; 183*5de18cdeSSam Ravnborg } 184*5de18cdeSSam Ravnborg 185*5de18cdeSSam Ravnborg /* Return the first property type for node 'node'. 186*5de18cdeSSam Ravnborg * buffer should be at least 32B in length 187*5de18cdeSSam Ravnborg */ 188*5de18cdeSSam Ravnborg inline char *prom_firstprop(int node, char *buffer) 189*5de18cdeSSam Ravnborg { 190*5de18cdeSSam Ravnborg *buffer = 0; 191*5de18cdeSSam Ravnborg if(node == -1) return buffer; 192*5de18cdeSSam Ravnborg p1275_cmd ("nextprop", P1275_ARG(2,P1275_ARG_OUT_32B)| 193*5de18cdeSSam Ravnborg P1275_INOUT(3, 0), 194*5de18cdeSSam Ravnborg node, (char *) 0x0, buffer); 195*5de18cdeSSam Ravnborg return buffer; 196*5de18cdeSSam Ravnborg } 197*5de18cdeSSam Ravnborg 198*5de18cdeSSam Ravnborg /* Return the property type string after property type 'oprop' 199*5de18cdeSSam Ravnborg * at node 'node' . Returns NULL string if no more 200*5de18cdeSSam Ravnborg * property types for this node. 201*5de18cdeSSam Ravnborg */ 202*5de18cdeSSam Ravnborg inline char *prom_nextprop(int node, const char *oprop, char *buffer) 203*5de18cdeSSam Ravnborg { 204*5de18cdeSSam Ravnborg char buf[32]; 205*5de18cdeSSam Ravnborg 206*5de18cdeSSam Ravnborg if(node == -1) { 207*5de18cdeSSam Ravnborg *buffer = 0; 208*5de18cdeSSam Ravnborg return buffer; 209*5de18cdeSSam Ravnborg } 210*5de18cdeSSam Ravnborg if (oprop == buffer) { 211*5de18cdeSSam Ravnborg strcpy (buf, oprop); 212*5de18cdeSSam Ravnborg oprop = buf; 213*5de18cdeSSam Ravnborg } 214*5de18cdeSSam Ravnborg p1275_cmd ("nextprop", P1275_ARG(1,P1275_ARG_IN_STRING)| 215*5de18cdeSSam Ravnborg P1275_ARG(2,P1275_ARG_OUT_32B)| 216*5de18cdeSSam Ravnborg P1275_INOUT(3, 0), 217*5de18cdeSSam Ravnborg node, oprop, buffer); 218*5de18cdeSSam Ravnborg return buffer; 219*5de18cdeSSam Ravnborg } 220*5de18cdeSSam Ravnborg 221*5de18cdeSSam Ravnborg int 222*5de18cdeSSam Ravnborg prom_finddevice(const char *name) 223*5de18cdeSSam Ravnborg { 224*5de18cdeSSam Ravnborg if (!name) 225*5de18cdeSSam Ravnborg return 0; 226*5de18cdeSSam Ravnborg return p1275_cmd(prom_finddev_name, 227*5de18cdeSSam Ravnborg P1275_ARG(0,P1275_ARG_IN_STRING)| 228*5de18cdeSSam Ravnborg P1275_INOUT(1, 1), 229*5de18cdeSSam Ravnborg name); 230*5de18cdeSSam Ravnborg } 231*5de18cdeSSam Ravnborg 232*5de18cdeSSam Ravnborg int prom_node_has_property(int node, const char *prop) 233*5de18cdeSSam Ravnborg { 234*5de18cdeSSam Ravnborg char buf [32]; 235*5de18cdeSSam Ravnborg 236*5de18cdeSSam Ravnborg *buf = 0; 237*5de18cdeSSam Ravnborg do { 238*5de18cdeSSam Ravnborg prom_nextprop(node, buf, buf); 239*5de18cdeSSam Ravnborg if(!strcmp(buf, prop)) 240*5de18cdeSSam Ravnborg return 1; 241*5de18cdeSSam Ravnborg } while (*buf); 242*5de18cdeSSam Ravnborg return 0; 243*5de18cdeSSam Ravnborg } 244*5de18cdeSSam Ravnborg 245*5de18cdeSSam Ravnborg /* Set property 'pname' at node 'node' to value 'value' which has a length 246*5de18cdeSSam Ravnborg * of 'size' bytes. Return the number of bytes the prom accepted. 247*5de18cdeSSam Ravnborg */ 248*5de18cdeSSam Ravnborg int 249*5de18cdeSSam Ravnborg prom_setprop(int node, const char *pname, char *value, int size) 250*5de18cdeSSam Ravnborg { 251*5de18cdeSSam Ravnborg if (size == 0) 252*5de18cdeSSam Ravnborg return 0; 253*5de18cdeSSam Ravnborg if ((pname == 0) || (value == 0)) 254*5de18cdeSSam Ravnborg return 0; 255*5de18cdeSSam Ravnborg 256*5de18cdeSSam Ravnborg #ifdef CONFIG_SUN_LDOMS 257*5de18cdeSSam Ravnborg if (ldom_domaining_enabled) { 258*5de18cdeSSam Ravnborg ldom_set_var(pname, value); 259*5de18cdeSSam Ravnborg return 0; 260*5de18cdeSSam Ravnborg } 261*5de18cdeSSam Ravnborg #endif 262*5de18cdeSSam Ravnborg return p1275_cmd ("setprop", P1275_ARG(1,P1275_ARG_IN_STRING)| 263*5de18cdeSSam Ravnborg P1275_ARG(2,P1275_ARG_IN_BUF)| 264*5de18cdeSSam Ravnborg P1275_INOUT(4, 1), 265*5de18cdeSSam Ravnborg node, pname, value, P1275_SIZE(size)); 266*5de18cdeSSam Ravnborg } 267*5de18cdeSSam Ravnborg 268*5de18cdeSSam Ravnborg inline int prom_inst2pkg(int inst) 269*5de18cdeSSam Ravnborg { 270*5de18cdeSSam Ravnborg int node; 271*5de18cdeSSam Ravnborg 272*5de18cdeSSam Ravnborg node = p1275_cmd ("instance-to-package", P1275_INOUT(1, 1), inst); 273*5de18cdeSSam Ravnborg if (node == -1) return 0; 274*5de18cdeSSam Ravnborg return node; 275*5de18cdeSSam Ravnborg } 276*5de18cdeSSam Ravnborg 277*5de18cdeSSam Ravnborg /* Return 'node' assigned to a particular prom 'path' 278*5de18cdeSSam Ravnborg * FIXME: Should work for v0 as well 279*5de18cdeSSam Ravnborg */ 280*5de18cdeSSam Ravnborg int 281*5de18cdeSSam Ravnborg prom_pathtoinode(const char *path) 282*5de18cdeSSam Ravnborg { 283*5de18cdeSSam Ravnborg int node, inst; 284*5de18cdeSSam Ravnborg 285*5de18cdeSSam Ravnborg inst = prom_devopen (path); 286*5de18cdeSSam Ravnborg if (inst == 0) return 0; 287*5de18cdeSSam Ravnborg node = prom_inst2pkg (inst); 288*5de18cdeSSam Ravnborg prom_devclose (inst); 289*5de18cdeSSam Ravnborg if (node == -1) return 0; 290*5de18cdeSSam Ravnborg return node; 291*5de18cdeSSam Ravnborg } 292*5de18cdeSSam Ravnborg 293*5de18cdeSSam Ravnborg int prom_ihandle2path(int handle, char *buffer, int bufsize) 294*5de18cdeSSam Ravnborg { 295*5de18cdeSSam Ravnborg return p1275_cmd("instance-to-path", 296*5de18cdeSSam Ravnborg P1275_ARG(1,P1275_ARG_OUT_BUF)| 297*5de18cdeSSam Ravnborg P1275_INOUT(3, 1), 298*5de18cdeSSam Ravnborg handle, buffer, P1275_SIZE(bufsize)); 299*5de18cdeSSam Ravnborg } 300