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. */
  23int __prom_getchild(int node)
  24{
  25        unsigned long flags;
  26        int 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 */
  39int prom_getchild(int node)
  40{
  41        int cnode;
  42
  43        if (node == -1)
  44                return 0;
  45
  46        cnode = __prom_getchild(node);
  47        if (cnode == 0 || 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. */
  55int __prom_getsibling(int node)
  56{
  57        unsigned long flags;
  58        int 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 */
  71int prom_getsibling(int node)
  72{
  73        int sibnode;
  74
  75        if (node == -1)
  76                return 0;
  77
  78        sibnode = __prom_getsibling(node);
  79        if (sibnode == 0 || 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(int 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(int 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(int 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(int 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(int 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(int 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        return;
 177}
 178EXPORT_SYMBOL(prom_getstring);
 179
 180
 181/* Does the device at node 'node' have name 'name'?
 182 * YES = 1   NO = 0
 183 */
 184int prom_nodematch(int node, char *name)
 185{
 186        int error;
 187
 188        static char namebuf[128];
 189        error = prom_getproperty(node, "name", namebuf, sizeof(namebuf));
 190        if (error == -1) return 0;
 191        if(strcmp(namebuf, name) == 0) return 1;
 192        return 0;
 193}
 194
 195/* Search siblings at 'node_start' for a node with name
 196 * 'nodename'.  Return node if successful, zero if not.
 197 */
 198int prom_searchsiblings(int node_start, char *nodename)
 199{
 200
 201        int thisnode, error;
 202
 203        for(thisnode = node_start; thisnode;
 204            thisnode=prom_getsibling(thisnode)) {
 205                error = prom_getproperty(thisnode, "name", promlib_buf,
 206                                         sizeof(promlib_buf));
 207                /* Should this ever happen? */
 208                if(error == -1) continue;
 209                if(strcmp(nodename, promlib_buf)==0) return thisnode;
 210        }
 211
 212        return 0;
 213}
 214EXPORT_SYMBOL(prom_searchsiblings);
 215
 216/* Interal version of nextprop that does not alter return values. */
 217char * __prom_nextprop(int node, char * oprop)
 218{
 219        unsigned long flags;
 220        char *prop;
 221
 222        spin_lock_irqsave(&prom_lock, flags);
 223        prop = prom_nodeops->no_nextprop(node, oprop);
 224        restore_current();
 225        spin_unlock_irqrestore(&prom_lock, flags);
 226
 227        return prop;
 228}
 229
 230/* Return the first property name for node 'node'. */
 231/* buffer is unused argument, but as v9 uses it, we need to have the same interface */
 232char * prom_firstprop(int node, char *bufer)
 233{
 234        if (node == 0 || node == -1)
 235                return "";
 236
 237        return __prom_nextprop(node, "");
 238}
 239EXPORT_SYMBOL(prom_firstprop);
 240
 241/* Return the property type string after property type 'oprop'
 242 * at node 'node' .  Returns empty string if no more
 243 * property types for this node.
 244 */
 245char * prom_nextprop(int node, char *oprop, char *buffer)
 246{
 247        if (node == 0 || node == -1)
 248                return "";
 249
 250        return __prom_nextprop(node, oprop);
 251}
 252EXPORT_SYMBOL(prom_nextprop);
 253
 254int prom_finddevice(char *name)
 255{
 256        char nbuf[128];
 257        char *s = name, *d;
 258        int node = prom_root_node, node2;
 259        unsigned int which_io, phys_addr;
 260        struct linux_prom_registers reg[PROMREG_MAX];
 261
 262        while (*s++) {
 263                if (!*s) return node; /* path '.../' is legal */
 264                node = prom_getchild(node);
 265
 266                for (d = nbuf; *s != 0 && *s != '@' && *s != '/';)
 267                        *d++ = *s++;
 268                *d = 0;
 269                
 270                node = prom_searchsiblings(node, nbuf);
 271                if (!node)
 272                        return 0;
 273
 274                if (*s == '@') {
 275                        if (isxdigit(s[1]) && s[2] == ',') {
 276                                which_io = simple_strtoul(s+1, NULL, 16);
 277                                phys_addr = simple_strtoul(s+3, &d, 16);
 278                                if (d != s + 3 && (!*d || *d == '/')
 279                                    && d <= s + 3 + 8) {
 280                                        node2 = node;
 281                                        while (node2 && node2 != -1) {
 282                                                if (prom_getproperty (node2, "reg", (char *)reg, sizeof (reg)) > 0) {
 283                                                        if (which_io == reg[0].which_io && phys_addr == reg[0].phys_addr) {
 284                                                                node = node2;
 285                                                                break;
 286                                                        }
 287                                                }
 288                                                node2 = prom_getsibling(node2);
 289                                                if (!node2 || node2 == -1)
 290                                                        break;
 291                                                node2 = prom_searchsiblings(prom_getsibling(node2), nbuf);
 292                                        }
 293                                }
 294                        }
 295                        while (*s != 0 && *s != '/') s++;
 296                }
 297        }
 298        return node;
 299}
 300EXPORT_SYMBOL(prom_finddevice);
 301
 302int prom_node_has_property(int node, char *prop)
 303{
 304        char *current_property = "";
 305
 306        do {
 307                current_property = prom_nextprop(node, current_property, NULL);
 308                if(!strcmp(current_property, prop))
 309                   return 1;
 310        } while (*current_property);
 311        return 0;
 312}
 313EXPORT_SYMBOL(prom_node_has_property);
 314
 315/* Set property 'pname' at node 'node' to value 'value' which has a length
 316 * of 'size' bytes.  Return the number of bytes the prom accepted.
 317 */
 318int prom_setprop(int node, const char *pname, char *value, int size)
 319{
 320        unsigned long flags;
 321        int ret;
 322
 323        if(size == 0) return 0;
 324        if((pname == 0) || (value == 0)) return 0;
 325        spin_lock_irqsave(&prom_lock, flags);
 326        ret = prom_nodeops->no_setprop(node, pname, value, size);
 327        restore_current();
 328        spin_unlock_irqrestore(&prom_lock, flags);
 329        return ret;
 330}
 331EXPORT_SYMBOL(prom_setprop);
 332
 333int prom_inst2pkg(int inst)
 334{
 335        int node;
 336        unsigned long flags;
 337        
 338        spin_lock_irqsave(&prom_lock, flags);
 339        node = (*romvec->pv_v2devops.v2_inst2pkg)(inst);
 340        restore_current();
 341        spin_unlock_irqrestore(&prom_lock, flags);
 342        if (node == -1) return 0;
 343        return node;
 344}
 345
 346/* Return 'node' assigned to a particular prom 'path'
 347 * FIXME: Should work for v0 as well
 348 */
 349int prom_pathtoinode(char *path)
 350{
 351        int node, inst;
 352        
 353        inst = prom_devopen (path);
 354        if (inst == -1) return 0;
 355        node = prom_inst2pkg (inst);
 356        prom_devclose (inst);
 357        if (node == -1) return 0;
 358        return node;
 359}
 360