Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * tree.c: Basic device tree traversal/scanning for the Linux
0004  *         prom library.
0005  *
0006  * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
0007  */
0008 
0009 #include <linux/string.h>
0010 #include <linux/types.h>
0011 #include <linux/kernel.h>
0012 #include <linux/sched.h>
0013 #include <linux/ctype.h>
0014 #include <linux/module.h>
0015 
0016 #include <asm/openprom.h>
0017 #include <asm/oplib.h>
0018 
0019 extern void restore_current(void);
0020 
0021 static char promlib_buf[128];
0022 
0023 /* Internal version of prom_getchild that does not alter return values. */
0024 static phandle __prom_getchild(phandle node)
0025 {
0026     unsigned long flags;
0027     phandle cnode;
0028 
0029     spin_lock_irqsave(&prom_lock, flags);
0030     cnode = prom_nodeops->no_child(node);
0031     restore_current();
0032     spin_unlock_irqrestore(&prom_lock, flags);
0033 
0034     return cnode;
0035 }
0036 
0037 /* Return the child of node 'node' or zero if no this node has no
0038  * direct descendent.
0039  */
0040 phandle prom_getchild(phandle node)
0041 {
0042     phandle cnode;
0043 
0044     if ((s32)node == -1)
0045         return 0;
0046 
0047     cnode = __prom_getchild(node);
0048     if (cnode == 0 || (s32)cnode == -1)
0049         return 0;
0050 
0051     return cnode;
0052 }
0053 EXPORT_SYMBOL(prom_getchild);
0054 
0055 /* Internal version of prom_getsibling that does not alter return values. */
0056 static phandle __prom_getsibling(phandle node)
0057 {
0058     unsigned long flags;
0059     phandle cnode;
0060 
0061     spin_lock_irqsave(&prom_lock, flags);
0062     cnode = prom_nodeops->no_nextnode(node);
0063     restore_current();
0064     spin_unlock_irqrestore(&prom_lock, flags);
0065 
0066     return cnode;
0067 }
0068 
0069 /* Return the next sibling of node 'node' or zero if no more siblings
0070  * at this level of depth in the tree.
0071  */
0072 phandle prom_getsibling(phandle node)
0073 {
0074     phandle sibnode;
0075 
0076     if ((s32)node == -1)
0077         return 0;
0078 
0079     sibnode = __prom_getsibling(node);
0080     if (sibnode == 0 || (s32)sibnode == -1)
0081         return 0;
0082 
0083     return sibnode;
0084 }
0085 EXPORT_SYMBOL(prom_getsibling);
0086 
0087 /* Return the length in bytes of property 'prop' at node 'node'.
0088  * Return -1 on error.
0089  */
0090 int prom_getproplen(phandle node, const char *prop)
0091 {
0092     int ret;
0093     unsigned long flags;
0094 
0095     if((!node) || (!prop))
0096         return -1;
0097         
0098     spin_lock_irqsave(&prom_lock, flags);
0099     ret = prom_nodeops->no_proplen(node, prop);
0100     restore_current();
0101     spin_unlock_irqrestore(&prom_lock, flags);
0102     return ret;
0103 }
0104 EXPORT_SYMBOL(prom_getproplen);
0105 
0106 /* Acquire a property 'prop' at node 'node' and place it in
0107  * 'buffer' which has a size of 'bufsize'.  If the acquisition
0108  * was successful the length will be returned, else -1 is returned.
0109  */
0110 int prom_getproperty(phandle node, const char *prop, char *buffer, int bufsize)
0111 {
0112     int plen, ret;
0113     unsigned long flags;
0114 
0115     plen = prom_getproplen(node, prop);
0116     if((plen > bufsize) || (plen == 0) || (plen == -1))
0117         return -1;
0118     /* Ok, things seem all right. */
0119     spin_lock_irqsave(&prom_lock, flags);
0120     ret = prom_nodeops->no_getprop(node, prop, buffer);
0121     restore_current();
0122     spin_unlock_irqrestore(&prom_lock, flags);
0123     return ret;
0124 }
0125 EXPORT_SYMBOL(prom_getproperty);
0126 
0127 /* Acquire an integer property and return its value.  Returns -1
0128  * on failure.
0129  */
0130 int prom_getint(phandle node, char *prop)
0131 {
0132     static int intprop;
0133 
0134     if(prom_getproperty(node, prop, (char *) &intprop, sizeof(int)) != -1)
0135         return intprop;
0136 
0137     return -1;
0138 }
0139 EXPORT_SYMBOL(prom_getint);
0140 
0141 /* Acquire an integer property, upon error return the passed default
0142  * integer.
0143  */
0144 int prom_getintdefault(phandle node, char *property, int deflt)
0145 {
0146     int retval;
0147 
0148     retval = prom_getint(node, property);
0149     if(retval == -1) return deflt;
0150 
0151     return retval;
0152 }
0153 EXPORT_SYMBOL(prom_getintdefault);
0154 
0155 /* Acquire a boolean property, 1=TRUE 0=FALSE. */
0156 int prom_getbool(phandle node, char *prop)
0157 {
0158     int retval;
0159 
0160     retval = prom_getproplen(node, prop);
0161     if(retval == -1) return 0;
0162     return 1;
0163 }
0164 EXPORT_SYMBOL(prom_getbool);
0165 
0166 /* Acquire a property whose value is a string, returns a null
0167  * string on error.  The char pointer is the user supplied string
0168  * buffer.
0169  */
0170 void prom_getstring(phandle node, char *prop, char *user_buf, int ubuf_size)
0171 {
0172     int len;
0173 
0174     len = prom_getproperty(node, prop, user_buf, ubuf_size);
0175     if(len != -1) return;
0176     user_buf[0] = 0;
0177 }
0178 EXPORT_SYMBOL(prom_getstring);
0179 
0180 
0181 /* Search siblings at 'node_start' for a node with name
0182  * 'nodename'.  Return node if successful, zero if not.
0183  */
0184 phandle prom_searchsiblings(phandle node_start, char *nodename)
0185 {
0186 
0187     phandle thisnode;
0188     int error;
0189 
0190     for(thisnode = node_start; thisnode;
0191         thisnode=prom_getsibling(thisnode)) {
0192         error = prom_getproperty(thisnode, "name", promlib_buf,
0193                      sizeof(promlib_buf));
0194         /* Should this ever happen? */
0195         if(error == -1) continue;
0196         if(strcmp(nodename, promlib_buf)==0) return thisnode;
0197     }
0198 
0199     return 0;
0200 }
0201 EXPORT_SYMBOL(prom_searchsiblings);
0202 
0203 /* Interal version of nextprop that does not alter return values. */
0204 static char *__prom_nextprop(phandle node, char * oprop)
0205 {
0206     unsigned long flags;
0207     char *prop;
0208 
0209     spin_lock_irqsave(&prom_lock, flags);
0210     prop = prom_nodeops->no_nextprop(node, oprop);
0211     restore_current();
0212     spin_unlock_irqrestore(&prom_lock, flags);
0213 
0214     return prop;
0215 }
0216 
0217 /* Return the property type string after property type 'oprop'
0218  * at node 'node' .  Returns empty string if no more
0219  * property types for this node.
0220  */
0221 char *prom_nextprop(phandle node, char *oprop, char *buffer)
0222 {
0223     if (node == 0 || (s32)node == -1)
0224         return "";
0225 
0226     return __prom_nextprop(node, oprop);
0227 }
0228 EXPORT_SYMBOL(prom_nextprop);
0229 
0230 phandle prom_finddevice(char *name)
0231 {
0232     char nbuf[128];
0233     char *s = name, *d;
0234     phandle node = prom_root_node, node2;
0235     unsigned int which_io, phys_addr;
0236     struct linux_prom_registers reg[PROMREG_MAX];
0237 
0238     while (*s++) {
0239         if (!*s) return node; /* path '.../' is legal */
0240         node = prom_getchild(node);
0241 
0242         for (d = nbuf; *s != 0 && *s != '@' && *s != '/';)
0243             *d++ = *s++;
0244         *d = 0;
0245         
0246         node = prom_searchsiblings(node, nbuf);
0247         if (!node)
0248             return 0;
0249 
0250         if (*s == '@') {
0251             if (isxdigit(s[1]) && s[2] == ',') {
0252                 which_io = simple_strtoul(s+1, NULL, 16);
0253                 phys_addr = simple_strtoul(s+3, &d, 16);
0254                 if (d != s + 3 && (!*d || *d == '/')
0255                     && d <= s + 3 + 8) {
0256                     node2 = node;
0257                     while (node2 && (s32)node2 != -1) {
0258                         if (prom_getproperty (node2, "reg", (char *)reg, sizeof (reg)) > 0) {
0259                             if (which_io == reg[0].which_io && phys_addr == reg[0].phys_addr) {
0260                                 node = node2;
0261                                 break;
0262                             }
0263                         }
0264                         node2 = prom_getsibling(node2);
0265                         if (!node2 || (s32)node2 == -1)
0266                             break;
0267                         node2 = prom_searchsiblings(prom_getsibling(node2), nbuf);
0268                     }
0269                 }
0270             }
0271             while (*s != 0 && *s != '/') s++;
0272         }
0273     }
0274     return node;
0275 }
0276 EXPORT_SYMBOL(prom_finddevice);
0277 
0278 /* Set property 'pname' at node 'node' to value 'value' which has a length
0279  * of 'size' bytes.  Return the number of bytes the prom accepted.
0280  */
0281 int prom_setprop(phandle node, const char *pname, char *value, int size)
0282 {
0283     unsigned long flags;
0284     int ret;
0285 
0286     if (size == 0)
0287         return 0;
0288     if ((pname == NULL) || (value == NULL))
0289         return 0;
0290     spin_lock_irqsave(&prom_lock, flags);
0291     ret = prom_nodeops->no_setprop(node, pname, value, size);
0292     restore_current();
0293     spin_unlock_irqrestore(&prom_lock, flags);
0294     return ret;
0295 }
0296 EXPORT_SYMBOL(prom_setprop);
0297 
0298 phandle prom_inst2pkg(int inst)
0299 {
0300     phandle node;
0301     unsigned long flags;
0302     
0303     spin_lock_irqsave(&prom_lock, flags);
0304     node = (*romvec->pv_v2devops.v2_inst2pkg)(inst);
0305     restore_current();
0306     spin_unlock_irqrestore(&prom_lock, flags);
0307     if ((s32)node == -1)
0308         return 0;
0309     return node;
0310 }