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