1 // SPDX-License-Identifier: GPL-2.0 1 // SPDX-License-Identifier: GPL-2.0 2 /* 2 /* 3 * tree.c: Basic device tree traversal/scannin 3 * tree.c: Basic device tree traversal/scanning for the Linux 4 * prom library. 4 * prom library. 5 * 5 * 6 * Copyright (C) 1995 David S. Miller (davem@c 6 * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) 7 */ 7 */ 8 8 9 #include <linux/string.h> 9 #include <linux/string.h> 10 #include <linux/types.h> 10 #include <linux/types.h> 11 #include <linux/kernel.h> 11 #include <linux/kernel.h> 12 #include <linux/sched.h> 12 #include <linux/sched.h> 13 #include <linux/ctype.h> 13 #include <linux/ctype.h> 14 #include <linux/module.h> 14 #include <linux/module.h> 15 15 16 #include <asm/openprom.h> 16 #include <asm/openprom.h> 17 #include <asm/oplib.h> 17 #include <asm/oplib.h> 18 18 19 extern void restore_current(void); 19 extern void restore_current(void); 20 20 21 static char promlib_buf[128]; 21 static char promlib_buf[128]; 22 22 23 /* Internal version of prom_getchild that does 23 /* Internal version of prom_getchild that does not alter return values. */ 24 static phandle __prom_getchild(phandle node) 24 static phandle __prom_getchild(phandle node) 25 { 25 { 26 unsigned long flags; 26 unsigned long flags; 27 phandle cnode; 27 phandle cnode; 28 28 29 spin_lock_irqsave(&prom_lock, flags); 29 spin_lock_irqsave(&prom_lock, flags); 30 cnode = prom_nodeops->no_child(node); 30 cnode = prom_nodeops->no_child(node); 31 restore_current(); 31 restore_current(); 32 spin_unlock_irqrestore(&prom_lock, fla 32 spin_unlock_irqrestore(&prom_lock, flags); 33 33 34 return cnode; 34 return cnode; 35 } 35 } 36 36 37 /* Return the child of node 'node' or zero if 37 /* Return the child of node 'node' or zero if no this node has no 38 * direct descendent. 38 * direct descendent. 39 */ 39 */ 40 phandle prom_getchild(phandle node) 40 phandle prom_getchild(phandle node) 41 { 41 { 42 phandle cnode; 42 phandle cnode; 43 43 44 if ((s32)node == -1) 44 if ((s32)node == -1) 45 return 0; 45 return 0; 46 46 47 cnode = __prom_getchild(node); 47 cnode = __prom_getchild(node); 48 if (cnode == 0 || (s32)cnode == -1) 48 if (cnode == 0 || (s32)cnode == -1) 49 return 0; 49 return 0; 50 50 51 return cnode; 51 return cnode; 52 } 52 } 53 EXPORT_SYMBOL(prom_getchild); 53 EXPORT_SYMBOL(prom_getchild); 54 54 55 /* Internal version of prom_getsibling that do 55 /* Internal version of prom_getsibling that does not alter return values. */ 56 static phandle __prom_getsibling(phandle node) 56 static phandle __prom_getsibling(phandle node) 57 { 57 { 58 unsigned long flags; 58 unsigned long flags; 59 phandle cnode; 59 phandle cnode; 60 60 61 spin_lock_irqsave(&prom_lock, flags); 61 spin_lock_irqsave(&prom_lock, flags); 62 cnode = prom_nodeops->no_nextnode(node 62 cnode = prom_nodeops->no_nextnode(node); 63 restore_current(); 63 restore_current(); 64 spin_unlock_irqrestore(&prom_lock, fla 64 spin_unlock_irqrestore(&prom_lock, flags); 65 65 66 return cnode; 66 return cnode; 67 } 67 } 68 68 69 /* Return the next sibling of node 'node' or z 69 /* Return the next sibling of node 'node' or zero if no more siblings 70 * at this level of depth in the tree. 70 * at this level of depth in the tree. 71 */ 71 */ 72 phandle prom_getsibling(phandle node) 72 phandle prom_getsibling(phandle node) 73 { 73 { 74 phandle sibnode; 74 phandle sibnode; 75 75 76 if ((s32)node == -1) 76 if ((s32)node == -1) 77 return 0; 77 return 0; 78 78 79 sibnode = __prom_getsibling(node); 79 sibnode = __prom_getsibling(node); 80 if (sibnode == 0 || (s32)sibnode == -1 80 if (sibnode == 0 || (s32)sibnode == -1) 81 return 0; 81 return 0; 82 82 83 return sibnode; 83 return sibnode; 84 } 84 } 85 EXPORT_SYMBOL(prom_getsibling); 85 EXPORT_SYMBOL(prom_getsibling); 86 86 87 /* Return the length in bytes of property 'pro 87 /* Return the length in bytes of property 'prop' at node 'node'. 88 * Return -1 on error. 88 * Return -1 on error. 89 */ 89 */ 90 int prom_getproplen(phandle node, const char * 90 int prom_getproplen(phandle node, const char *prop) 91 { 91 { 92 int ret; 92 int ret; 93 unsigned long flags; 93 unsigned long flags; 94 94 95 if((!node) || (!prop)) 95 if((!node) || (!prop)) 96 return -1; 96 return -1; 97 97 98 spin_lock_irqsave(&prom_lock, flags); 98 spin_lock_irqsave(&prom_lock, flags); 99 ret = prom_nodeops->no_proplen(node, p 99 ret = prom_nodeops->no_proplen(node, prop); 100 restore_current(); 100 restore_current(); 101 spin_unlock_irqrestore(&prom_lock, fla 101 spin_unlock_irqrestore(&prom_lock, flags); 102 return ret; 102 return ret; 103 } 103 } 104 EXPORT_SYMBOL(prom_getproplen); 104 EXPORT_SYMBOL(prom_getproplen); 105 105 106 /* Acquire a property 'prop' at node 'node' an 106 /* Acquire a property 'prop' at node 'node' and place it in 107 * 'buffer' which has a size of 'bufsize'. If 107 * 'buffer' which has a size of 'bufsize'. If the acquisition 108 * was successful the length will be returned, 108 * was successful the length will be returned, else -1 is returned. 109 */ 109 */ 110 int prom_getproperty(phandle node, const char 110 int prom_getproperty(phandle node, const char *prop, char *buffer, int bufsize) 111 { 111 { 112 int plen, ret; 112 int plen, ret; 113 unsigned long flags; 113 unsigned long flags; 114 114 115 plen = prom_getproplen(node, prop); 115 plen = prom_getproplen(node, prop); 116 if((plen > bufsize) || (plen == 0) || 116 if((plen > bufsize) || (plen == 0) || (plen == -1)) 117 return -1; 117 return -1; 118 /* Ok, things seem all right. */ 118 /* Ok, things seem all right. */ 119 spin_lock_irqsave(&prom_lock, flags); 119 spin_lock_irqsave(&prom_lock, flags); 120 ret = prom_nodeops->no_getprop(node, p 120 ret = prom_nodeops->no_getprop(node, prop, buffer); 121 restore_current(); 121 restore_current(); 122 spin_unlock_irqrestore(&prom_lock, fla 122 spin_unlock_irqrestore(&prom_lock, flags); 123 return ret; 123 return ret; 124 } 124 } 125 EXPORT_SYMBOL(prom_getproperty); 125 EXPORT_SYMBOL(prom_getproperty); 126 126 127 /* Acquire an integer property and return its 127 /* Acquire an integer property and return its value. Returns -1 128 * on failure. 128 * on failure. 129 */ 129 */ 130 int prom_getint(phandle node, char *prop) 130 int prom_getint(phandle node, char *prop) 131 { 131 { 132 static int intprop; 132 static int intprop; 133 133 134 if(prom_getproperty(node, prop, (char 134 if(prom_getproperty(node, prop, (char *) &intprop, sizeof(int)) != -1) 135 return intprop; 135 return intprop; 136 136 137 return -1; 137 return -1; 138 } 138 } 139 EXPORT_SYMBOL(prom_getint); 139 EXPORT_SYMBOL(prom_getint); 140 140 141 /* Acquire an integer property, upon error ret 141 /* Acquire an integer property, upon error return the passed default 142 * integer. 142 * integer. 143 */ 143 */ 144 int prom_getintdefault(phandle node, char *pro 144 int prom_getintdefault(phandle node, char *property, int deflt) 145 { 145 { 146 int retval; 146 int retval; 147 147 148 retval = prom_getint(node, property); 148 retval = prom_getint(node, property); 149 if(retval == -1) return deflt; 149 if(retval == -1) return deflt; 150 150 151 return retval; 151 return retval; 152 } 152 } 153 EXPORT_SYMBOL(prom_getintdefault); 153 EXPORT_SYMBOL(prom_getintdefault); 154 154 155 /* Acquire a boolean property, 1=TRUE 0=FALSE. 155 /* Acquire a boolean property, 1=TRUE 0=FALSE. */ 156 int prom_getbool(phandle node, char *prop) 156 int prom_getbool(phandle node, char *prop) 157 { 157 { 158 int retval; 158 int retval; 159 159 160 retval = prom_getproplen(node, prop); 160 retval = prom_getproplen(node, prop); 161 if(retval == -1) return 0; 161 if(retval == -1) return 0; 162 return 1; 162 return 1; 163 } 163 } 164 EXPORT_SYMBOL(prom_getbool); 164 EXPORT_SYMBOL(prom_getbool); 165 165 166 /* Acquire a property whose value is a string, 166 /* Acquire a property whose value is a string, returns a null 167 * string on error. The char pointer is the u 167 * string on error. The char pointer is the user supplied string 168 * buffer. 168 * buffer. 169 */ 169 */ 170 void prom_getstring(phandle node, char *prop, 170 void prom_getstring(phandle node, char *prop, char *user_buf, int ubuf_size) 171 { 171 { 172 int len; 172 int len; 173 173 174 len = prom_getproperty(node, prop, use 174 len = prom_getproperty(node, prop, user_buf, ubuf_size); 175 if(len != -1) return; 175 if(len != -1) return; 176 user_buf[0] = 0; 176 user_buf[0] = 0; 177 } 177 } 178 EXPORT_SYMBOL(prom_getstring); 178 EXPORT_SYMBOL(prom_getstring); 179 179 180 180 181 /* Search siblings at 'node_start' for a node 181 /* Search siblings at 'node_start' for a node with name 182 * 'nodename'. Return node if successful, zer 182 * 'nodename'. Return node if successful, zero if not. 183 */ 183 */ 184 phandle prom_searchsiblings(phandle node_start 184 phandle prom_searchsiblings(phandle node_start, char *nodename) 185 { 185 { 186 186 187 phandle thisnode; 187 phandle thisnode; 188 int error; 188 int error; 189 189 190 for(thisnode = node_start; thisnode; 190 for(thisnode = node_start; thisnode; 191 thisnode=prom_getsibling(thisnode) 191 thisnode=prom_getsibling(thisnode)) { 192 error = prom_getproperty(thisn 192 error = prom_getproperty(thisnode, "name", promlib_buf, 193 sizeo 193 sizeof(promlib_buf)); 194 /* Should this ever happen? */ 194 /* Should this ever happen? */ 195 if(error == -1) continue; 195 if(error == -1) continue; 196 if(strcmp(nodename, promlib_bu 196 if(strcmp(nodename, promlib_buf)==0) return thisnode; 197 } 197 } 198 198 199 return 0; 199 return 0; 200 } 200 } 201 EXPORT_SYMBOL(prom_searchsiblings); 201 EXPORT_SYMBOL(prom_searchsiblings); 202 202 203 /* Interal version of nextprop that does not a 203 /* Interal version of nextprop that does not alter return values. */ 204 static char *__prom_nextprop(phandle node, cha 204 static char *__prom_nextprop(phandle node, char * oprop) 205 { 205 { 206 unsigned long flags; 206 unsigned long flags; 207 char *prop; 207 char *prop; 208 208 209 spin_lock_irqsave(&prom_lock, flags); 209 spin_lock_irqsave(&prom_lock, flags); 210 prop = prom_nodeops->no_nextprop(node, 210 prop = prom_nodeops->no_nextprop(node, oprop); 211 restore_current(); 211 restore_current(); 212 spin_unlock_irqrestore(&prom_lock, fla 212 spin_unlock_irqrestore(&prom_lock, flags); 213 213 214 return prop; 214 return prop; 215 } 215 } 216 216 217 /* Return the property type string after prope 217 /* Return the property type string after property type 'oprop' 218 * at node 'node' . Returns empty string if n 218 * at node 'node' . Returns empty string if no more 219 * property types for this node. 219 * property types for this node. 220 */ 220 */ 221 char *prom_nextprop(phandle node, char *oprop, 221 char *prom_nextprop(phandle node, char *oprop, char *buffer) 222 { 222 { 223 if (node == 0 || (s32)node == -1) 223 if (node == 0 || (s32)node == -1) 224 return ""; 224 return ""; 225 225 226 return __prom_nextprop(node, oprop); 226 return __prom_nextprop(node, oprop); 227 } 227 } 228 EXPORT_SYMBOL(prom_nextprop); 228 EXPORT_SYMBOL(prom_nextprop); 229 229 230 phandle prom_finddevice(char *name) 230 phandle prom_finddevice(char *name) 231 { 231 { 232 char nbuf[128]; 232 char nbuf[128]; 233 char *s = name, *d; 233 char *s = name, *d; 234 phandle node = prom_root_node, node2; 234 phandle node = prom_root_node, node2; 235 unsigned int which_io, phys_addr; 235 unsigned int which_io, phys_addr; 236 struct linux_prom_registers reg[PROMRE 236 struct linux_prom_registers reg[PROMREG_MAX]; 237 237 238 while (*s++) { 238 while (*s++) { 239 if (!*s) return node; /* path 239 if (!*s) return node; /* path '.../' is legal */ 240 node = prom_getchild(node); 240 node = prom_getchild(node); 241 241 242 for (d = nbuf; *s != 0 && *s ! 242 for (d = nbuf; *s != 0 && *s != '@' && *s != '/';) 243 *d++ = *s++; 243 *d++ = *s++; 244 *d = 0; 244 *d = 0; 245 245 246 node = prom_searchsiblings(nod 246 node = prom_searchsiblings(node, nbuf); 247 if (!node) 247 if (!node) 248 return 0; 248 return 0; 249 249 250 if (*s == '@') { 250 if (*s == '@') { 251 if (isxdigit(s[1]) && 251 if (isxdigit(s[1]) && s[2] == ',') { 252 which_io = sim 252 which_io = simple_strtoul(s+1, NULL, 16); 253 phys_addr = si 253 phys_addr = simple_strtoul(s+3, &d, 16); 254 if (d != s + 3 254 if (d != s + 3 && (!*d || *d == '/') 255 && d <= s 255 && d <= s + 3 + 8) { 256 node2 256 node2 = node; 257 while 257 while (node2 && (s32)node2 != -1) { 258 258 if (prom_getproperty (node2, "reg", (char *)reg, sizeof (reg)) > 0) { 259 259 if (which_io == reg[0].which_io && phys_addr == reg[0].phys_addr) { 260 260 node = node2; 261 261 break; 262 262 } 263 263 } 264 264 node2 = prom_getsibling(node2); 265 265 if (!node2 || (s32)node2 == -1) 266 266 break; 267 267 node2 = prom_searchsiblings(prom_getsibling(node2), nbuf); 268 } 268 } 269 } 269 } 270 } 270 } 271 while (*s != 0 && *s ! 271 while (*s != 0 && *s != '/') s++; 272 } 272 } 273 } 273 } 274 return node; 274 return node; 275 } 275 } 276 EXPORT_SYMBOL(prom_finddevice); 276 EXPORT_SYMBOL(prom_finddevice); 277 277 278 /* Set property 'pname' at node 'node' to valu 278 /* Set property 'pname' at node 'node' to value 'value' which has a length 279 * of 'size' bytes. Return the number of byte 279 * of 'size' bytes. Return the number of bytes the prom accepted. 280 */ 280 */ 281 int prom_setprop(phandle node, const char *pna 281 int prom_setprop(phandle node, const char *pname, char *value, int size) 282 { 282 { 283 unsigned long flags; 283 unsigned long flags; 284 int ret; 284 int ret; 285 285 286 if (size == 0) 286 if (size == 0) 287 return 0; 287 return 0; 288 if ((pname == NULL) || (value == NULL) 288 if ((pname == NULL) || (value == NULL)) 289 return 0; 289 return 0; 290 spin_lock_irqsave(&prom_lock, flags); 290 spin_lock_irqsave(&prom_lock, flags); 291 ret = prom_nodeops->no_setprop(node, p 291 ret = prom_nodeops->no_setprop(node, pname, value, size); 292 restore_current(); 292 restore_current(); 293 spin_unlock_irqrestore(&prom_lock, fla 293 spin_unlock_irqrestore(&prom_lock, flags); 294 return ret; 294 return ret; 295 } 295 } 296 EXPORT_SYMBOL(prom_setprop); 296 EXPORT_SYMBOL(prom_setprop); 297 297 298 phandle prom_inst2pkg(int inst) 298 phandle prom_inst2pkg(int inst) 299 { 299 { 300 phandle node; 300 phandle node; 301 unsigned long flags; 301 unsigned long flags; 302 302 303 spin_lock_irqsave(&prom_lock, flags); 303 spin_lock_irqsave(&prom_lock, flags); 304 node = (*romvec->pv_v2devops.v2_inst2p 304 node = (*romvec->pv_v2devops.v2_inst2pkg)(inst); 305 restore_current(); 305 restore_current(); 306 spin_unlock_irqrestore(&prom_lock, fla 306 spin_unlock_irqrestore(&prom_lock, flags); 307 if ((s32)node == -1) 307 if ((s32)node == -1) 308 return 0; 308 return 0; 309 return node; 309 return node; 310 } 310 } 311 311
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.