1 /* 2 * tree.c: Basic device tree traversal/scanning for the Linux 3 * prom library. 4 * 5 * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) 6 * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) 7 */ 8 9 #include <linux/string.h> 10 #include <linux/types.h> 11 #include <linux/kernel.h> 12 #include <linux/sched.h> 13 #include <linux/module.h> 14 15 #include <asm/openprom.h> 16 #include <asm/oplib.h> 17 #include <asm/ldc.h> 18 19 static phandle prom_node_to_node(const char *type, phandle node) 20 { 21 unsigned long args[5]; 22 23 args[0] = (unsigned long) type; 24 args[1] = 1; 25 args[2] = 1; 26 args[3] = (unsigned int) node; 27 args[4] = (unsigned long) -1; 28 29 p1275_cmd_direct(args); 30 31 return (phandle) args[4]; 32 } 33 34 /* Return the child of node 'node' or zero if no this node has no 35 * direct descendent. 36 */ 37 inline phandle __prom_getchild(phandle node) 38 { 39 return prom_node_to_node("child", node); 40 } 41 42 inline phandle prom_getchild(phandle node) 43 { 44 phandle cnode; 45 46 if (node == -1) 47 return 0; 48 cnode = __prom_getchild(node); 49 if (cnode == -1) 50 return 0; 51 return cnode; 52 } 53 EXPORT_SYMBOL(prom_getchild); 54 55 inline phandle prom_getparent(phandle node) 56 { 57 phandle cnode; 58 59 if (node == -1) 60 return 0; 61 cnode = prom_node_to_node("parent", node); 62 if (cnode == -1) 63 return 0; 64 return cnode; 65 } 66 67 /* Return the next sibling of node 'node' or zero if no more siblings 68 * at this level of depth in the tree. 69 */ 70 inline phandle __prom_getsibling(phandle node) 71 { 72 return prom_node_to_node(prom_peer_name, node); 73 } 74 75 inline phandle prom_getsibling(phandle node) 76 { 77 phandle sibnode; 78 79 if (node == -1) 80 return 0; 81 sibnode = __prom_getsibling(node); 82 if (sibnode == -1) 83 return 0; 84 85 return sibnode; 86 } 87 EXPORT_SYMBOL(prom_getsibling); 88 89 /* Return the length in bytes of property 'prop' at node 'node'. 90 * Return -1 on error. 91 */ 92 inline int prom_getproplen(phandle node, const char *prop) 93 { 94 unsigned long args[6]; 95 96 if (!node || !prop) 97 return -1; 98 99 args[0] = (unsigned long) "getproplen"; 100 args[1] = 2; 101 args[2] = 1; 102 args[3] = (unsigned int) node; 103 args[4] = (unsigned long) prop; 104 args[5] = (unsigned long) -1; 105 106 p1275_cmd_direct(args); 107 108 return (int) args[5]; 109 } 110 EXPORT_SYMBOL(prom_getproplen); 111 112 /* Acquire a property 'prop' at node 'node' and place it in 113 * 'buffer' which has a size of 'bufsize'. If the acquisition 114 * was successful the length will be returned, else -1 is returned. 115 */ 116 inline int prom_getproperty(phandle node, const char *prop, 117 char *buffer, int bufsize) 118 { 119 unsigned long args[8]; 120 int plen; 121 122 plen = prom_getproplen(node, prop); 123 if ((plen > bufsize) || (plen == 0) || (plen == -1)) 124 return -1; 125 126 args[0] = (unsigned long) prom_getprop_name; 127 args[1] = 4; 128 args[2] = 1; 129 args[3] = (unsigned int) node; 130 args[4] = (unsigned long) prop; 131 args[5] = (unsigned long) buffer; 132 args[6] = bufsize; 133 args[7] = (unsigned long) -1; 134 135 p1275_cmd_direct(args); 136 137 return (int) args[7]; 138 } 139 EXPORT_SYMBOL(prom_getproperty); 140 141 /* Acquire an integer property and return its value. Returns -1 142 * on failure. 143 */ 144 inline int prom_getint(phandle node, const char *prop) 145 { 146 int intprop; 147 148 if (prom_getproperty(node, prop, (char *) &intprop, sizeof(int)) != -1) 149 return intprop; 150 151 return -1; 152 } 153 EXPORT_SYMBOL(prom_getint); 154 155 /* Acquire an integer property, upon error return the passed default 156 * integer. 157 */ 158 159 int prom_getintdefault(phandle node, const char *property, int deflt) 160 { 161 int retval; 162 163 retval = prom_getint(node, property); 164 if (retval == -1) 165 return deflt; 166 167 return retval; 168 } 169 EXPORT_SYMBOL(prom_getintdefault); 170 171 /* Acquire a boolean property, 1=TRUE 0=FALSE. */ 172 int prom_getbool(phandle node, const char *prop) 173 { 174 int retval; 175 176 retval = prom_getproplen(node, prop); 177 if (retval == -1) 178 return 0; 179 return 1; 180 } 181 EXPORT_SYMBOL(prom_getbool); 182 183 /* Acquire a property whose value is a string, returns a null 184 * string on error. The char pointer is the user supplied string 185 * buffer. 186 */ 187 void prom_getstring(phandle node, const char *prop, char *user_buf, 188 int ubuf_size) 189 { 190 int len; 191 192 len = prom_getproperty(node, prop, user_buf, ubuf_size); 193 if (len != -1) 194 return; 195 user_buf[0] = 0; 196 } 197 EXPORT_SYMBOL(prom_getstring); 198 199 /* Does the device at node 'node' have name 'name'? 200 * YES = 1 NO = 0 201 */ 202 int prom_nodematch(phandle node, const char *name) 203 { 204 char namebuf[128]; 205 prom_getproperty(node, "name", namebuf, sizeof(namebuf)); 206 if (strcmp(namebuf, name) == 0) 207 return 1; 208 return 0; 209 } 210 211 /* Search siblings at 'node_start' for a node with name 212 * 'nodename'. Return node if successful, zero if not. 213 */ 214 phandle prom_searchsiblings(phandle node_start, const char *nodename) 215 { 216 phandle thisnode; 217 int error; 218 char promlib_buf[128]; 219 220 for(thisnode = node_start; thisnode; 221 thisnode=prom_getsibling(thisnode)) { 222 error = prom_getproperty(thisnode, "name", promlib_buf, 223 sizeof(promlib_buf)); 224 /* Should this ever happen? */ 225 if(error == -1) continue; 226 if(strcmp(nodename, promlib_buf)==0) return thisnode; 227 } 228 229 return 0; 230 } 231 EXPORT_SYMBOL(prom_searchsiblings); 232 233 static const char *prom_nextprop_name = "nextprop"; 234 235 /* Return the first property type for node 'node'. 236 * buffer should be at least 32B in length 237 */ 238 inline char *prom_firstprop(phandle node, char *buffer) 239 { 240 unsigned long args[7]; 241 242 *buffer = 0; 243 if (node == -1) 244 return buffer; 245 246 args[0] = (unsigned long) prom_nextprop_name; 247 args[1] = 3; 248 args[2] = 1; 249 args[3] = (unsigned int) node; 250 args[4] = 0; 251 args[5] = (unsigned long) buffer; 252 args[6] = (unsigned long) -1; 253 254 p1275_cmd_direct(args); 255 256 return buffer; 257 } 258 EXPORT_SYMBOL(prom_firstprop); 259 260 /* Return the property type string after property type 'oprop' 261 * at node 'node' . Returns NULL string if no more 262 * property types for this node. 263 */ 264 inline char *prom_nextprop(phandle node, const char *oprop, char *buffer) 265 { 266 unsigned long args[7]; 267 char buf[32]; 268 269 if (node == -1) { 270 *buffer = 0; 271 return buffer; 272 } 273 if (oprop == buffer) { 274 strcpy (buf, oprop); 275 oprop = buf; 276 } 277 278 args[0] = (unsigned long) prom_nextprop_name; 279 args[1] = 3; 280 args[2] = 1; 281 args[3] = (unsigned int) node; 282 args[4] = (unsigned long) oprop; 283 args[5] = (unsigned long) buffer; 284 args[6] = (unsigned long) -1; 285 286 p1275_cmd_direct(args); 287 288 return buffer; 289 } 290 EXPORT_SYMBOL(prom_nextprop); 291 292 phandle prom_finddevice(const char *name) 293 { 294 unsigned long args[5]; 295 296 if (!name) 297 return 0; 298 args[0] = (unsigned long) "finddevice"; 299 args[1] = 1; 300 args[2] = 1; 301 args[3] = (unsigned long) name; 302 args[4] = (unsigned long) -1; 303 304 p1275_cmd_direct(args); 305 306 return (int) args[4]; 307 } 308 EXPORT_SYMBOL(prom_finddevice); 309 310 int prom_node_has_property(phandle node, const char *prop) 311 { 312 char buf [32]; 313 314 *buf = 0; 315 do { 316 prom_nextprop(node, buf, buf); 317 if (!strcmp(buf, prop)) 318 return 1; 319 } while (*buf); 320 return 0; 321 } 322 EXPORT_SYMBOL(prom_node_has_property); 323 324 /* Set property 'pname' at node 'node' to value 'value' which has a length 325 * of 'size' bytes. Return the number of bytes the prom accepted. 326 */ 327 int 328 prom_setprop(phandle node, const char *pname, char *value, int size) 329 { 330 unsigned long args[8]; 331 332 if (size == 0) 333 return 0; 334 if ((pname == 0) || (value == 0)) 335 return 0; 336 337 #ifdef CONFIG_SUN_LDOMS 338 if (ldom_domaining_enabled) { 339 ldom_set_var(pname, value); 340 return 0; 341 } 342 #endif 343 args[0] = (unsigned long) "setprop"; 344 args[1] = 4; 345 args[2] = 1; 346 args[3] = (unsigned int) node; 347 args[4] = (unsigned long) pname; 348 args[5] = (unsigned long) value; 349 args[6] = size; 350 args[7] = (unsigned long) -1; 351 352 p1275_cmd_direct(args); 353 354 return (int) args[7]; 355 } 356 EXPORT_SYMBOL(prom_setprop); 357 358 inline phandle prom_inst2pkg(int inst) 359 { 360 unsigned long args[5]; 361 phandle node; 362 363 args[0] = (unsigned long) "instance-to-package"; 364 args[1] = 1; 365 args[2] = 1; 366 args[3] = (unsigned int) inst; 367 args[4] = (unsigned long) -1; 368 369 p1275_cmd_direct(args); 370 371 node = (int) args[4]; 372 if (node == -1) 373 return 0; 374 return node; 375 } 376 377 int prom_ihandle2path(int handle, char *buffer, int bufsize) 378 { 379 unsigned long args[7]; 380 381 args[0] = (unsigned long) "instance-to-path"; 382 args[1] = 3; 383 args[2] = 1; 384 args[3] = (unsigned int) handle; 385 args[4] = (unsigned long) buffer; 386 args[5] = bufsize; 387 args[6] = (unsigned long) -1; 388 389 p1275_cmd_direct(args); 390 391 return (int) args[6]; 392 } 393