]> git.kernelconcepts.de Git - karo-tx-uboot.git/blobdiff - libfdt/fdt_ro.c
remove MVS1 board
[karo-tx-uboot.git] / libfdt / fdt_ro.c
index 12a37d59f96eba267235cf06962f7ccc7a6c2259..b09a6e9eb7e5976333d6e4626f67102074dabdd8 100644 (file)
  */
 #include "libfdt_env.h"
 
+#ifndef USE_HOSTCC
 #include <fdt.h>
 #include <libfdt.h>
+#else
+#include "fdt_host.h"
+#endif
 
 #include "libfdt_internal.h"
 
-#define CHECK_HEADER(fdt) \
-       { \
-               int err; \
-               if ((err = fdt_check_header(fdt)) != 0) \
-                       return err; \
-       }
-
-static int nodename_eq(const void *fdt, int offset,
-                      const char *s, int len)
+static int _fdt_nodename_eq(const void *fdt, int offset,
+                           const char *s, int len)
 {
-       const char *p = fdt_offset_ptr(fdt, offset, len+1);
+       const char *p = fdt_offset_ptr(fdt, offset + FDT_TAGSIZE, len+1);
 
        if (! p)
                /* short match */
@@ -84,12 +81,20 @@ static int nodename_eq(const void *fdt, int offset,
 
 const char *fdt_string(const void *fdt, int stroffset)
 {
-       return (char *)fdt + fdt_off_dt_strings(fdt) + stroffset;
+       return (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset;
+}
+
+static int _fdt_string_eq(const void *fdt, int stroffset,
+                         const char *s, int len)
+{
+       const char *p = fdt_string(fdt, stroffset);
+
+       return (strlen(p) == len) && (memcmp(p, s, len) == 0);
 }
 
 int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
 {
-       CHECK_HEADER(fdt);
+       FDT_CHECK_HEADER(fdt);
        *address = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->address);
        *size = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->size);
        return 0;
@@ -104,50 +109,24 @@ int fdt_num_mem_rsv(const void *fdt)
        return i;
 }
 
-int fdt_subnode_offset_namelen(const void *fdt, int parentoffset,
+int fdt_subnode_offset_namelen(const void *fdt, int offset,
                               const char *name, int namelen)
 {
-       int level = 0;
-       uint32_t tag;
-       int offset, nextoffset;
-
-       CHECK_HEADER(fdt);
-
-       tag = fdt_next_tag(fdt, parentoffset, &nextoffset);
-       if (tag != FDT_BEGIN_NODE)
-               return -FDT_ERR_BADOFFSET;
-
-       do {
-               offset = nextoffset;
-               tag = fdt_next_tag(fdt, offset, &nextoffset);
+       int depth;
 
-               switch (tag) {
-               case FDT_END:
-                       return -FDT_ERR_TRUNCATED;
+       FDT_CHECK_HEADER(fdt);
 
-               case FDT_BEGIN_NODE:
-                       level++;
-                       if (level != 1)
-                               continue;
-                       if (nodename_eq(fdt, offset+FDT_TAGSIZE, name, namelen))
-                               /* Found it! */
-                               return offset;
-                       break;
-
-               case FDT_END_NODE:
-                       level--;
-                       break;
-
-               case FDT_PROP:
-               case FDT_NOP:
-                       break;
-
-               default:
-                       return -FDT_ERR_BADSTRUCTURE;
-               }
-       } while (level >= 0);
+       for (depth = 0;
+            offset >= 0;
+            offset = fdt_next_node(fdt, offset, &depth)) {
+               if (depth < 0)
+                       return -FDT_ERR_NOTFOUND;
+               else if ((depth == 1)
+                        && _fdt_nodename_eq(fdt, offset, name, namelen))
+                       return offset;
+       }
 
-       return -FDT_ERR_NOTFOUND;
+       return offset; /* error */
 }
 
 int fdt_subnode_offset(const void *fdt, int parentoffset,
@@ -162,10 +141,27 @@ int fdt_path_offset(const void *fdt, const char *path)
        const char *p = path;
        int offset = 0;
 
-       CHECK_HEADER(fdt);
+       FDT_CHECK_HEADER(fdt);
 
-       if (*path != '/')
-               return -FDT_ERR_BADPATH;
+       /* see if we have an alias */
+       if (*path != '/') {
+               const char *q;
+               int aliasoffset = fdt_path_offset(fdt, "/aliases");
+
+               if (aliasoffset < 0)
+                       return -FDT_ERR_BADPATH;
+
+               q = strchr(path, '/');
+               if (!q)
+                       q = end;
+
+               p = fdt_getprop_namelen(fdt, aliasoffset, path, q - p, NULL);
+               if (!p)
+                       return -FDT_ERR_BADPATH;
+               offset = fdt_path_offset(fdt, p);
+
+               p = q;
+       }
 
        while (*p) {
                const char *q;
@@ -190,16 +186,12 @@ int fdt_path_offset(const void *fdt, const char *path)
 
 const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
 {
-       const struct fdt_node_header *nh;
+       const struct fdt_node_header *nh = _fdt_offset_ptr(fdt, nodeoffset);
        int err;
 
-       if ((err = fdt_check_header(fdt)) != 0)
-               goto fail;
-
-       err = -FDT_ERR_BADOFFSET;
-       nh = fdt_offset_ptr(fdt, nodeoffset, sizeof(*nh));
-       if (!nh || (fdt32_to_cpu(nh->tag) != FDT_BEGIN_NODE))
-               goto fail;
+       if (((err = fdt_check_header(fdt)) != 0)
+           || ((err = _fdt_check_node_offset(fdt, nodeoffset)) < 0))
+                       goto fail;
 
        if (len)
                *len = strlen(nh->name);
@@ -212,9 +204,10 @@ const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
        return NULL;
 }
 
-const struct fdt_property *fdt_get_property(const void *fdt,
-                                           int nodeoffset,
-                                           const char *name, int *lenp)
+const struct fdt_property *fdt_get_property_namelen(const void *fdt,
+                                                   int nodeoffset,
+                                                   const char *name,
+                                                   int namelen, int *lenp)
 {
        uint32_t tag;
        const struct fdt_property *prop;
@@ -222,17 +215,11 @@ const struct fdt_property *fdt_get_property(const void *fdt,
        int offset, nextoffset;
        int err;
 
-       if ((err = fdt_check_header(fdt)) != 0)
-               goto fail;
-
-       err = -FDT_ERR_BADOFFSET;
-       if (nodeoffset % FDT_TAGSIZE)
-               goto fail;
-
-       tag = fdt_next_tag(fdt, nodeoffset, &nextoffset);
-       if (tag != FDT_BEGIN_NODE)
-               goto fail;
+       if (((err = fdt_check_header(fdt)) != 0)
+           || ((err = _fdt_check_node_offset(fdt, nodeoffset)) < 0))
+                       goto fail;
 
+       nextoffset = err;
        do {
                offset = nextoffset;
 
@@ -253,7 +240,7 @@ const struct fdt_property *fdt_get_property(const void *fdt,
                        if (! prop)
                                goto fail;
                        namestroff = fdt32_to_cpu(prop->nameoff);
-                       if (streq(fdt_string(fdt, namestroff), name)) {
+                       if (_fdt_string_eq(fdt, namestroff, name, namelen)) {
                                /* Found it! */
                                int len = fdt32_to_cpu(prop->len);
                                prop = fdt_offset_ptr(fdt, offset,
@@ -281,18 +268,32 @@ const struct fdt_property *fdt_get_property(const void *fdt,
        return NULL;
 }
 
-const void *fdt_getprop(const void *fdt, int nodeoffset,
-                 const char *name, int *lenp)
+const struct fdt_property *fdt_get_property(const void *fdt,
+                                           int nodeoffset,
+                                           const char *name, int *lenp)
+{
+       return fdt_get_property_namelen(fdt, nodeoffset, name,
+                                       strlen(name), lenp);
+}
+
+const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
+                               const char *name, int namelen, int *lenp)
 {
        const struct fdt_property *prop;
 
-       prop = fdt_get_property(fdt, nodeoffset, name, lenp);
+       prop = fdt_get_property_namelen(fdt, nodeoffset, name, namelen, lenp);
        if (! prop)
                return NULL;
 
        return prop->data;
 }
 
+const void *fdt_getprop(const void *fdt, int nodeoffset,
+                       const char *name, int *lenp)
+{
+       return fdt_getprop_namelen(fdt, nodeoffset, name, strlen(name), lenp);
+}
+
 uint32_t fdt_get_phandle(const void *fdt, int nodeoffset)
 {
        const uint32_t *php;
@@ -307,115 +308,91 @@ uint32_t fdt_get_phandle(const void *fdt, int nodeoffset)
 
 int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)
 {
-       uint32_t tag;
-       int p = 0, overflow = 0;
-       int offset, nextoffset, namelen;
+       int pdepth = 0, p = 0;
+       int offset, depth, namelen;
        const char *name;
 
-       CHECK_HEADER(fdt);
-
-       tag = fdt_next_tag(fdt, 0, &nextoffset);
-       if (tag != FDT_BEGIN_NODE)
-               return -FDT_ERR_BADSTRUCTURE;
+       FDT_CHECK_HEADER(fdt);
 
        if (buflen < 2)
                return -FDT_ERR_NOSPACE;
-       buf[0] = '/';
-       p = 1;
 
-       while (nextoffset <= nodeoffset) {
-               offset = nextoffset;
-               tag = fdt_next_tag(fdt, offset, &nextoffset);
-               switch (tag) {
-               case FDT_END:
-                       return -FDT_ERR_BADOFFSET;
+       for (offset = 0, depth = 0;
+            (offset >= 0) && (offset <= nodeoffset);
+            offset = fdt_next_node(fdt, offset, &depth)) {
+               if (pdepth < depth)
+                       continue; /* overflowed buffer */
 
-               case FDT_BEGIN_NODE:
-                       name = fdt_get_name(fdt, offset, &namelen);
-                       if (!name)
-                               return namelen;
-                       if (overflow || ((p + namelen + 1) > buflen)) {
-                               overflow++;
-                               break;
-                       }
+               while (pdepth > depth) {
+                       do {
+                               p--;
+                       } while (buf[p-1] != '/');
+                       pdepth--;
+               }
+
+               name = fdt_get_name(fdt, offset, &namelen);
+               if (!name)
+                       return namelen;
+               if ((p + namelen + 1) <= buflen) {
                        memcpy(buf + p, name, namelen);
                        p += namelen;
                        buf[p++] = '/';
-                       break;
-
-               case FDT_END_NODE:
-                       if (overflow) {
-                               overflow--;
-                               break;
-                       }
-                       do {
-                               p--;
-                       } while  (buf[p-1] != '/');
-                       break;
+                       pdepth++;
+               }
 
-               case FDT_PROP:
-               case FDT_NOP:
-                       break;
+               if (offset == nodeoffset) {
+                       if (pdepth < (depth + 1))
+                               return -FDT_ERR_NOSPACE;
 
-               default:
-                       return -FDT_ERR_BADSTRUCTURE;
+                       if (p > 1) /* special case so that root path is "/", not "" */
+                               p--;
+                       buf[p] = '\0';
+                       return p;
                }
        }
 
-       if (overflow)
-               return -FDT_ERR_NOSPACE;
+       if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
+               return -FDT_ERR_BADOFFSET;
+       else if (offset == -FDT_ERR_BADOFFSET)
+               return -FDT_ERR_BADSTRUCTURE;
 
-       if (p > 1) /* special case so that root path is "/", not "" */
-               p--;
-       buf[p] = '\0';
-       return p;
+       return offset; /* error from fdt_next_node() */
 }
 
 int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
                                 int supernodedepth, int *nodedepth)
 {
-       int level = -1;
-       uint32_t tag;
-       int offset, nextoffset = 0;
+       int offset, depth;
        int supernodeoffset = -FDT_ERR_INTERNAL;
 
-       CHECK_HEADER(fdt);
+       FDT_CHECK_HEADER(fdt);
 
        if (supernodedepth < 0)
                return -FDT_ERR_NOTFOUND;
 
-       do {
-               offset = nextoffset;
-               tag = fdt_next_tag(fdt, offset, &nextoffset);
-               switch (tag) {
-               case FDT_END:
-                       return -FDT_ERR_BADOFFSET;
+       for (offset = 0, depth = 0;
+            (offset >= 0) && (offset <= nodeoffset);
+            offset = fdt_next_node(fdt, offset, &depth)) {
+               if (depth == supernodedepth)
+                       supernodeoffset = offset;
 
-               case FDT_BEGIN_NODE:
-                       level++;
-                       if (level == supernodedepth)
-                               supernodeoffset = offset;
-                       break;
+               if (offset == nodeoffset) {
+                       if (nodedepth)
+                               *nodedepth = depth;
 
-               case FDT_END_NODE:
-                       level--;
-                       break;
-
-               case FDT_PROP:
-               case FDT_NOP:
-                       break;
-
-               default:
-                       return -FDT_ERR_BADSTRUCTURE;
+                       if (supernodedepth > depth)
+                               return -FDT_ERR_NOTFOUND;
+                       else
+                               return supernodeoffset;
                }
-       } while (offset < nodeoffset);
+       }
 
-       if (nodedepth)
-               *nodedepth = level;
+       if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
+               return -FDT_ERR_BADOFFSET;
+       else if (offset == -FDT_ERR_BADOFFSET)
+               return -FDT_ERR_BADSTRUCTURE;
 
-       if (supernodedepth > level)
-               return -FDT_ERR_NOTFOUND;
-       return supernodeoffset;
+       return offset; /* error from fdt_next_node() */
 }
 
 int fdt_node_depth(const void *fdt, int nodeoffset)
@@ -443,51 +420,27 @@ int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
                                  const char *propname,
                                  const void *propval, int proplen)
 {
-       uint32_t tag;
-       int offset, nextoffset;
+       int offset;
        const void *val;
        int len;
 
-       CHECK_HEADER(fdt);
-
-       if (startoffset >= 0) {
-               tag = fdt_next_tag(fdt, startoffset, &nextoffset);
-               if (tag != FDT_BEGIN_NODE)
-                       return -FDT_ERR_BADOFFSET;
-       } else {
-               nextoffset = 0;
-       }
+       FDT_CHECK_HEADER(fdt);
 
        /* FIXME: The algorithm here is pretty horrible: we scan each
         * property of a node in fdt_getprop(), then if that didn't
         * find what we want, we scan over them again making our way
         * to the next node.  Still it's the easiest to implement
         * approach; performance can come later. */
-       do {
-               offset = nextoffset;
-               tag = fdt_next_tag(fdt, offset, &nextoffset);
-
-               switch (tag) {
-               case FDT_BEGIN_NODE:
-                       val = fdt_getprop(fdt, offset, propname, &len);
-                       if (val
-                           && (len == proplen)
-                           && (memcmp(val, propval, len) == 0))
-                               return offset;
-                       break;
-
-               case FDT_PROP:
-               case FDT_END:
-               case FDT_END_NODE:
-               case FDT_NOP:
-                       break;
-
-               default:
-                       return -FDT_ERR_BADSTRUCTURE;
-               }
-       } while (tag != FDT_END);
+       for (offset = fdt_next_node(fdt, startoffset, NULL);
+            offset >= 0;
+            offset = fdt_next_node(fdt, offset, NULL)) {
+               val = fdt_getprop(fdt, offset, propname, &len);
+               if (val && (len == proplen)
+                   && (memcmp(val, propval, len) == 0))
+                       return offset;
+       }
 
-       return -FDT_ERR_NOTFOUND;
+       return offset; /* error from fdt_next_node() */
 }
 
 int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle)
@@ -499,10 +452,11 @@ int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle)
                                             &phandle, sizeof(phandle));
 }
 
-int _stringlist_contains(const void *strlist, int listlen, const char *str)
+static int _fdt_stringlist_contains(const char *strlist, int listlen,
+                                   const char *str)
 {
        int len = strlen(str);
-       const void *p;
+       const char *p;
 
        while (listlen >= len) {
                if (memcmp(str, strlist, len+1) == 0)
@@ -525,7 +479,7 @@ int fdt_node_check_compatible(const void *fdt, int nodeoffset,
        prop = fdt_getprop(fdt, nodeoffset, "compatible", &len);
        if (!prop)
                return len;
-       if (_stringlist_contains(prop, len, compatible))
+       if (_fdt_stringlist_contains(prop, len, compatible))
                return 0;
        else
                return 1;
@@ -534,50 +488,24 @@ int fdt_node_check_compatible(const void *fdt, int nodeoffset,
 int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
                                  const char *compatible)
 {
-       uint32_t tag;
-       int offset, nextoffset;
-       int err;
-
-       CHECK_HEADER(fdt);
+       int offset, err;
 
-       if (startoffset >= 0) {
-               tag = fdt_next_tag(fdt, startoffset, &nextoffset);
-               if (tag != FDT_BEGIN_NODE)
-                       return -FDT_ERR_BADOFFSET;
-       } else {
-               nextoffset = 0;
-       }
+       FDT_CHECK_HEADER(fdt);
 
        /* FIXME: The algorithm here is pretty horrible: we scan each
         * property of a node in fdt_node_check_compatible(), then if
         * that didn't find what we want, we scan over them again
         * making our way to the next node.  Still it's the easiest to
         * implement approach; performance can come later. */
-       do {
-               offset = nextoffset;
-               tag = fdt_next_tag(fdt, offset, &nextoffset);
-
-               switch (tag) {
-               case FDT_BEGIN_NODE:
-                       err = fdt_node_check_compatible(fdt, offset,
-                                                       compatible);
-                       if ((err < 0)
-                           && (err != -FDT_ERR_NOTFOUND))
-                               return err;
-                       else if (err == 0)
-                               return offset;
-                       break;
-
-               case FDT_PROP:
-               case FDT_END:
-               case FDT_END_NODE:
-               case FDT_NOP:
-                       break;
-
-               default:
-                       return -FDT_ERR_BADSTRUCTURE;
-               }
-       } while (tag != FDT_END);
+       for (offset = fdt_next_node(fdt, startoffset, NULL);
+            offset >= 0;
+            offset = fdt_next_node(fdt, offset, NULL)) {
+               err = fdt_node_check_compatible(fdt, offset, compatible);
+               if ((err < 0) && (err != -FDT_ERR_NOTFOUND))
+                       return err;
+               else if (err == 0)
+                       return offset;
+       }
 
-       return -FDT_ERR_NOTFOUND;
+       return offset; /* error from fdt_next_node() */
 }