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