linux-old/arch/sparc/prom/tree.c
<<
>>
Prefs
   1/* $Id: tree.c,v 1.26 2000/08/26 02:38:03 anton Exp $
   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#define PROMLIB_INTERNAL
   9
  10#include <linux/string.h>
  11#include <linux/types.h>
  12#include <linux/kernel.h>
  13#include <linux/sched.h>
  14#include <linux/ctype.h>
  15
  16#include <asm/openprom.h>
  17#include <asm/oplib.h>
  18
  19extern void restore_current(void);
  20
  21static char promlib_buf[128];
  22
  23/* Internal version of prom_getchild that does not alter return values. */
  24int __prom_getchild(int node)
  25{
  26        unsigned long flags;
  27        int cnode;
  28
  29        spin_lock_irqsave(&prom_lock, flags);
  30        cnode = prom_nodeops->no_child(node);
  31        restore_current();
  32        spin_unlock_irqrestore(&prom_lock, flags);
  33
  34        return cnode;
  35}
  36
  37/* Return the child of node 'node' or zero if no this node has no
  38 * direct descendent.
  39 */
  40int prom_getchild(int node)
  41{
  42        int cnode;
  43
  44        if (node == -1)
  45                return 0;
  46
  47        cnode = __prom_getchild(node);
  48        if (cnode == 0 || cnode == -1)
  49                return 0;
  50
  51        return cnode;
  52}
  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}
  84
  85/* Return the length in bytes of property 'prop' at node 'node'.
  86 * Return -1 on error.
  87 */
  88int prom_getproplen(int node, char *prop)
  89{
  90        int ret;
  91        unsigned long flags;
  92
  93        if((!node) || (!prop))
  94                return -1;
  95                
  96        spin_lock_irqsave(&prom_lock, flags);
  97        ret = prom_nodeops->no_proplen(node, prop);
  98        restore_current();
  99        spin_unlock_irqrestore(&prom_lock, flags);
 100        return ret;
 101}
 102
 103/* Acquire a property 'prop' at node 'node' and place it in
 104 * 'buffer' which has a size of 'bufsize'.  If the acquisition
 105 * was successful the length will be returned, else -1 is returned.
 106 */
 107int prom_getproperty(int node, char *prop, char *buffer, int bufsize)
 108{
 109        int plen, ret;
 110        unsigned long flags;
 111
 112        plen = prom_getproplen(node, prop);
 113        if((plen > bufsize) || (plen == 0) || (plen == -1))
 114                return -1;
 115        /* Ok, things seem all right. */
 116        spin_lock_irqsave(&prom_lock, flags);
 117        ret = prom_nodeops->no_getprop(node, prop, buffer);
 118        restore_current();
 119        spin_unlock_irqrestore(&prom_lock, flags);
 120        return ret;
 121}
 122
 123/* Acquire an integer property and return its value.  Returns -1
 124 * on failure.
 125 */
 126int prom_getint(int node, char *prop)
 127{
 128        static int intprop;
 129
 130        if(prom_getproperty(node, prop, (char *) &intprop, sizeof(int)) != -1)
 131                return intprop;
 132
 133        return -1;
 134}
 135
 136/* Acquire an integer property, upon error return the passed default
 137 * integer.
 138 */
 139int prom_getintdefault(int node, char *property, int deflt)
 140{
 141        int retval;
 142
 143        retval = prom_getint(node, property);
 144        if(retval == -1) return deflt;
 145
 146        return retval;
 147}
 148
 149/* Acquire a boolean property, 1=TRUE 0=FALSE. */
 150int prom_getbool(int node, char *prop)
 151{
 152        int retval;
 153
 154        retval = prom_getproplen(node, prop);
 155        if(retval == -1) return 0;
 156        return 1;
 157}
 158
 159/* Acquire a property whose value is a string, returns a null
 160 * string on error.  The char pointer is the user supplied string
 161 * buffer.
 162 */
 163void prom_getstring(int node, char *prop, char *user_buf, int ubuf_size)
 164{
 165        int len;
 166
 167        len = prom_getproperty(node, prop, user_buf, ubuf_size);
 168        if(len != -1) return;
 169        user_buf[0] = 0;
 170        return;
 171}
 172
 173
 174/* Does the device at node 'node' have name 'name'?
 175 * YES = 1   NO = 0
 176 */
 177int prom_nodematch(int node, char *name)
 178{
 179        static char namebuf[128];
 180        prom_getproperty(node, "name", namebuf, sizeof(namebuf));
 181        if(strcmp(namebuf, name) == 0) return 1;
 182        return 0;
 183}
 184
 185/* Search siblings at 'node_start' for a node with name
 186 * 'nodename'.  Return node if successful, zero if not.
 187 */
 188int prom_searchsiblings(int node_start, char *nodename)
 189{
 190
 191        int thisnode, error;
 192
 193        for(thisnode = node_start; thisnode;
 194            thisnode=prom_getsibling(thisnode)) {
 195                error = prom_getproperty(thisnode, "name", promlib_buf,
 196                                         sizeof(promlib_buf));
 197                /* Should this ever happen? */
 198                if(error == -1) continue;
 199                if(strcmp(nodename, promlib_buf)==0) return thisnode;
 200        }
 201
 202        return 0;
 203}
 204
 205/* Gets name in the form prom v2+ uses it (name@x,yyyyy or name (if no reg)) */
 206int prom_getname (int node, char *buffer, int len)
 207{
 208        int i;
 209        struct linux_prom_registers reg[PROMREG_MAX];
 210        
 211        i = prom_getproperty (node, "name", buffer, len);
 212        if (i <= 0) return -1;
 213        buffer [i] = 0;
 214        len -= i;
 215        i = prom_getproperty (node, "reg", (char *)reg, sizeof (reg));
 216        if (i <= 0) return 0;
 217        if (len < 11) return -1;
 218        buffer = strchr (buffer, 0);
 219        sprintf (buffer, "@%x,%x", reg[0].which_io, (uint)reg[0].phys_addr);
 220        return 0;
 221}
 222
 223/* Interal version of nextprop that does not alter return values. */
 224char * __prom_nextprop(int node, char * oprop)
 225{
 226        unsigned long flags;
 227        char *prop;
 228
 229        spin_lock_irqsave(&prom_lock, flags);
 230        prop = prom_nodeops->no_nextprop(node, oprop);
 231        restore_current();
 232        spin_unlock_irqrestore(&prom_lock, flags);
 233
 234        return prop;
 235}
 236
 237/* Return the first property name for node 'node'. */
 238/* buffer is unused argument, but as v9 uses it, we need to have the same interface */
 239char * prom_firstprop(int node, char *bufer)
 240{
 241        if (node == 0 || node == -1)
 242                return "";
 243
 244        return __prom_nextprop(node, "");
 245}
 246
 247/* Return the property type string after property type 'oprop'
 248 * at node 'node' .  Returns empty string if no more
 249 * property types for this node.
 250 */
 251char * prom_nextprop(int node, char *oprop, char *buffer)
 252{
 253        if (node == 0 || node == -1)
 254                return "";
 255
 256        return __prom_nextprop(node, oprop);
 257}
 258
 259int prom_finddevice(char *name)
 260{
 261        char nbuf[128];
 262        char *s = name, *d;
 263        int node = prom_root_node, node2;
 264        unsigned int which_io, phys_addr;
 265        struct linux_prom_registers reg[PROMREG_MAX];
 266
 267        while (*s++) {
 268                if (!*s) return node; /* path '.../' is legal */
 269                node = prom_getchild(node);
 270
 271                for (d = nbuf; *s != 0 && *s != '@' && *s != '/';)
 272                        *d++ = *s++;
 273                *d = 0;
 274                
 275                node = prom_searchsiblings(node, nbuf);
 276                if (!node)
 277                        return 0;
 278
 279                if (*s == '@') {
 280                        if (isxdigit(s[1]) && s[2] == ',') {
 281                                which_io = simple_strtoul(s+1, NULL, 16);
 282                                phys_addr = simple_strtoul(s+3, &d, 16);
 283                                if (d != s + 3 && (!*d || *d == '/')
 284                                    && d <= s + 3 + 8) {
 285                                        node2 = node;
 286                                        while (node2 && node2 != -1) {
 287                                                if (prom_getproperty (node2, "reg", (char *)reg, sizeof (reg)) > 0) {
 288                                                        if (which_io == reg[0].which_io && phys_addr == reg[0].phys_addr) {
 289                                                                node = node2;
 290                                                                break;
 291                                                        }
 292                                                }
 293                                                node2 = prom_getsibling(node2);
 294                                                if (!node2 || node2 == -1)
 295                                                        break;
 296                                                node2 = prom_searchsiblings(prom_getsibling(node2), nbuf);
 297                                        }
 298                                }
 299                        }
 300                        while (*s != 0 && *s != '/') s++;
 301                }
 302        }
 303        return node;
 304}
 305
 306int prom_node_has_property(int node, char *prop)
 307{
 308        char *current_property = "";
 309
 310        do {
 311                current_property = prom_nextprop(node, current_property, NULL);
 312                if(!strcmp(current_property, prop))
 313                   return 1;
 314        } while (*current_property);
 315        return 0;
 316}
 317
 318/* Set property 'pname' at node 'node' to value 'value' which has a length
 319 * of 'size' bytes.  Return the number of bytes the prom accepted.
 320 */
 321int prom_setprop(int node, char *pname, char *value, int size)
 322{
 323        unsigned long flags;
 324        int ret;
 325
 326        if(size == 0) return 0;
 327        if((pname == 0) || (value == 0)) return 0;
 328        spin_lock_irqsave(&prom_lock, flags);
 329        ret = prom_nodeops->no_setprop(node, pname, value, size);
 330        restore_current();
 331        spin_unlock_irqrestore(&prom_lock, flags);
 332        return ret;
 333}
 334
 335int prom_inst2pkg(int inst)
 336{
 337        int node;
 338        unsigned long flags;
 339        
 340        spin_lock_irqsave(&prom_lock, flags);
 341        node = (*romvec->pv_v2devops.v2_inst2pkg)(inst);
 342        restore_current();
 343        spin_unlock_irqrestore(&prom_lock, flags);
 344        if (node == -1) return 0;
 345        return node;
 346}
 347
 348/* Return 'node' assigned to a particular prom 'path'
 349 * FIXME: Should work for v0 as well
 350 */
 351int prom_pathtoinode(char *path)
 352{
 353        int node, inst;
 354        
 355        inst = prom_devopen (path);
 356        if (inst == -1) return 0;
 357        node = prom_inst2pkg (inst);
 358        prom_devclose (inst);
 359        if (node == -1) return 0;
 360        return node;
 361}
 362
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.