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