]> git.proxmox.com Git - mirror_edk2.git/blobdiff - EmbeddedPkg/Library/FdtLib/fdt_ro.c
ARM Packages: Fixed line endings
[mirror_edk2.git] / EmbeddedPkg / Library / FdtLib / fdt_ro.c
index 95fdbeadd4c3017ed1fa15dc50e4eda2b70b4f23..9ae6b5ecc55626c943f9e12a61810e05cfdf5a3b 100644 (file)
-/*
- * libfdt - Flat Device Tree manipulation
- * Copyright (C) 2006 David Gibson, IBM Corporation.
- *
- * libfdt is dual licensed: you can use it either under the terms of
- * the GPL, or the BSD license, at your option.
- *
- *  a) This library is free software; you can redistribute it and/or
- *     modify it under the terms of the GNU General Public License as
- *     published by the Free Software Foundation; either version 2 of the
- *     License, or (at your option) any later version.
- *
- *     This library is distributed in the hope that it will be useful,
- *     but WITHOUT ANY WARRANTY; without even the implied warranty of
- *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *     GNU General Public License for more details.
- *
- *     You should have received a copy of the GNU General Public
- *     License along with this library; if not, write to the Free
- *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
- *     MA 02110-1301 USA
- *
- * Alternatively,
- *
- *  b) Redistribution and use in source and binary forms, with or
- *     without modification, are permitted provided that the following
- *     conditions are met:
- *
- *     1. Redistributions of source code must retain the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer.
- *     2. Redistributions in binary form must reproduce the above
- *        copyright notice, this list of conditions and the following
- *        disclaimer in the documentation and/or other materials
- *        provided with the distribution.
- *
- *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
- *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
- *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
- *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-#include "libfdt_env.h"
-
-#include <fdt.h>
-#include <libfdt.h>
-
-#include "libfdt_internal.h"
-
-static int _fdt_nodename_eq(const void *fdt, int offset,
-                           const char *s, int len)
-{
-       const char *p = fdt_offset_ptr(fdt, offset + FDT_TAGSIZE, len+1);
-
-       if (! p)
-               /* short match */
-               return 0;
-
-       if (memcmp(p, s, len) != 0)
-               return 0;
-
-       if (p[len] == '\0')
-               return 1;
-       else if (!memchr(s, '@', len) && (p[len] == '@'))
-               return 1;
-       else
-               return 0;
-}
-
-const char *fdt_string(const void *fdt, int 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)
-{
-       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;
-}
-
-int fdt_num_mem_rsv(const void *fdt)
-{
-       int i = 0;
-
-       while (fdt64_to_cpu(_fdt_mem_rsv(fdt, i)->size) != 0)
-               i++;
-       return i;
-}
-
-static int _nextprop(const void *fdt, int offset)
-{
-       uint32_t tag;
-       int nextoffset;
-
-       do {
-               tag = fdt_next_tag(fdt, offset, &nextoffset);
-
-               switch (tag) {
-               case FDT_END:
-                       if (nextoffset >= 0)
-                               return -FDT_ERR_BADSTRUCTURE;
-                       else
-                               return nextoffset;
-
-               case FDT_PROP:
-                       return offset;
-               }
-               offset = nextoffset;
-       } while (tag == FDT_NOP);
-
-       return -FDT_ERR_NOTFOUND;
-}
-
-int fdt_subnode_offset_namelen(const void *fdt, int offset,
-                              const char *name, int namelen)
-{
-       int depth;
-
-       FDT_CHECK_HEADER(fdt);
-
-       for (depth = 0;
-            (offset >= 0) && (depth >= 0);
-            offset = fdt_next_node(fdt, offset, &depth))
-               if ((depth == 1)
-                   && _fdt_nodename_eq(fdt, offset, name, namelen))
-                       return offset;
-
-       if (depth < 0)
-               return -FDT_ERR_NOTFOUND;
-       return offset; /* error */
-}
-
-int fdt_subnode_offset(const void *fdt, int parentoffset,
-                      const char *name)
-{
-       return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name));
-}
-
-int fdt_path_offset(const void *fdt, const char *path)
-{
-       const char *end = path + strlen(path);
-       const char *p = path;
-       int offset = 0;
-
-       FDT_CHECK_HEADER(fdt);
-
-       /* see if we have an alias */
-       if (*path != '/') {
-               const char *q = strchr(path, '/');
-
-               if (!q)
-                       q = end;
-
-               p = fdt_get_alias_namelen(fdt, p, q - p);
-               if (!p)
-                       return -FDT_ERR_BADPATH;
-               offset = fdt_path_offset(fdt, p);
-
-               p = q;
-       }
-
-       while (*p) {
-               const char *q;
-
-               while (*p == '/')
-                       p++;
-               if (! *p)
-                       return offset;
-               q = strchr(p, '/');
-               if (! q)
-                       q = end;
-
-               offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p);
-               if (offset < 0)
-                       return offset;
-
-               p = q;
-       }
-
-       return offset;
-}
-
-const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
-{
-       const struct fdt_node_header *nh = _fdt_offset_ptr(fdt, nodeoffset);
-       int err;
-
-       if (((err = fdt_check_header(fdt)) != 0)
-           || ((err = _fdt_check_node_offset(fdt, nodeoffset)) < 0))
-                       goto fail;
-
-       if (len)
-               *len = strlen(nh->name);
-
-       return nh->name;
-
- fail:
-       if (len)
-               *len = err;
-       return NULL;
-}
-
-int fdt_first_property_offset(const void *fdt, int nodeoffset)
-{
-       int offset;
-
-       if ((offset = _fdt_check_node_offset(fdt, nodeoffset)) < 0)
-               return offset;
-
-       return _nextprop(fdt, offset);
-}
-
-int fdt_next_property_offset(const void *fdt, int offset)
-{
-       if ((offset = _fdt_check_prop_offset(fdt, offset)) < 0)
-               return offset;
-
-       return _nextprop(fdt, offset);
-}
-
-const struct fdt_property *fdt_get_property_by_offset(const void *fdt,
-                                                     int offset,
-                                                     int *lenp)
-{
-       int err;
-       const struct fdt_property *prop;
-
-       if ((err = _fdt_check_prop_offset(fdt, offset)) < 0) {
-               if (lenp)
-                       *lenp = err;
-               return NULL;
-       }
-
-       prop = _fdt_offset_ptr(fdt, offset);
-
-       if (lenp)
-               *lenp = fdt32_to_cpu(prop->len);
-
-       return prop;
-}
-
-const struct fdt_property *fdt_get_property_namelen(const void *fdt,
-                                                   int offset,
-                                                   const char *name,
-                                                   int namelen, int *lenp)
-{
-       for (offset = fdt_first_property_offset(fdt, offset);
-            (offset >= 0);
-            (offset = fdt_next_property_offset(fdt, offset))) {
-               const struct fdt_property *prop;
-
-               prop = fdt_get_property_by_offset(fdt, offset, lenp);
-               if (!prop) {
-                       offset = -FDT_ERR_INTERNAL;
-                       break;
-               }
-               if (_fdt_string_eq(fdt, fdt32_to_cpu(prop->nameoff),
-                                  name, namelen))
-                       return prop;
-       }
-
-       if (lenp)
-               *lenp = offset;
-       return NULL;
-}
-
-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_namelen(fdt, nodeoffset, name, namelen, lenp);
-       if (! prop)
-               return NULL;
-
-       return prop->data;
-}
-
-const void *fdt_getprop_by_offset(const void *fdt, int offset,
-                                 const char **namep, int *lenp)
-{
-       const struct fdt_property *prop;
-
-       prop = fdt_get_property_by_offset(fdt, offset, lenp);
-       if (!prop)
-               return NULL;
-       if (namep)
-               *namep = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
-       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;
-       int len;
-
-       /* FIXME: This is a bit sub-optimal, since we potentially scan
-        * over all the properties twice. */
-       php = fdt_getprop(fdt, nodeoffset, "phandle", &len);
-       if (!php || (len != sizeof(*php))) {
-               php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len);
-               if (!php || (len != sizeof(*php)))
-                       return 0;
-       }
-
-       return fdt32_to_cpu(*php);
-}
-
-const char *fdt_get_alias_namelen(const void *fdt,
-                                 const char *name, int namelen)
-{
-       int aliasoffset;
-
-       aliasoffset = fdt_path_offset(fdt, "/aliases");
-       if (aliasoffset < 0)
-               return NULL;
-
-       return fdt_getprop_namelen(fdt, aliasoffset, name, namelen, NULL);
-}
-
-const char *fdt_get_alias(const void *fdt, const char *name)
-{
-       return fdt_get_alias_namelen(fdt, name, strlen(name));
-}
-
-int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)
-{
-       int pdepth = 0, p = 0;
-       int offset, depth, namelen;
-       const char *name;
-
-       FDT_CHECK_HEADER(fdt);
-
-       if (buflen < 2)
-               return -FDT_ERR_NOSPACE;
-
-       for (offset = 0, depth = 0;
-            (offset >= 0) && (offset <= nodeoffset);
-            offset = fdt_next_node(fdt, offset, &depth)) {
-               while (pdepth > depth) {
-                       do {
-                               p--;
-                       } while (buf[p-1] != '/');
-                       pdepth--;
-               }
-
-               if (pdepth >= depth) {
-                       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++] = '/';
-                               pdepth++;
-                       }
-               }
-
-               if (offset == nodeoffset) {
-                       if (pdepth < (depth + 1))
-                               return -FDT_ERR_NOSPACE;
-
-                       if (p > 1) /* special case so that root path is "/", not "" */
-                               p--;
-                       buf[p] = '\0';
-                       return 0;
-               }
-       }
-
-       if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
-               return -FDT_ERR_BADOFFSET;
-       else if (offset == -FDT_ERR_BADOFFSET)
-               return -FDT_ERR_BADSTRUCTURE;
-
-       return offset; /* error from fdt_next_node() */
-}
-
-int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
-                                int supernodedepth, int *nodedepth)
-{
-       int offset, depth;
-       int supernodeoffset = -FDT_ERR_INTERNAL;
-
-       FDT_CHECK_HEADER(fdt);
-
-       if (supernodedepth < 0)
-               return -FDT_ERR_NOTFOUND;
-
-       for (offset = 0, depth = 0;
-            (offset >= 0) && (offset <= nodeoffset);
-            offset = fdt_next_node(fdt, offset, &depth)) {
-               if (depth == supernodedepth)
-                       supernodeoffset = offset;
-
-               if (offset == nodeoffset) {
-                       if (nodedepth)
-                               *nodedepth = depth;
-
-                       if (supernodedepth > depth)
-                               return -FDT_ERR_NOTFOUND;
-                       else
-                               return supernodeoffset;
-               }
-       }
-
-       if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
-               return -FDT_ERR_BADOFFSET;
-       else if (offset == -FDT_ERR_BADOFFSET)
-               return -FDT_ERR_BADSTRUCTURE;
-
-       return offset; /* error from fdt_next_node() */
-}
-
-int fdt_node_depth(const void *fdt, int nodeoffset)
-{
-       int nodedepth;
-       int err;
-
-       err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth);
-       if (err)
-               return (err < 0) ? err : -FDT_ERR_INTERNAL;
-       return nodedepth;
-}
-
-int fdt_parent_offset(const void *fdt, int nodeoffset)
-{
-       int nodedepth = fdt_node_depth(fdt, nodeoffset);
-
-       if (nodedepth < 0)
-               return nodedepth;
-       return fdt_supernode_atdepth_offset(fdt, nodeoffset,
-                                           nodedepth - 1, NULL);
-}
-
-int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
-                                 const char *propname,
-                                 const void *propval, int proplen)
-{
-       int offset;
-       const void *val;
-       int len;
-
-       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. */
-       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 offset; /* error from fdt_next_node() */
-}
-
-int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle)
-{
-       int offset;
-
-       if ((phandle == 0) || (phandle == (uint32_t)-1))
-               return -FDT_ERR_BADPHANDLE;
-
-       FDT_CHECK_HEADER(fdt);
-
-       /* FIXME: The algorithm here is pretty horrible: we
-        * potentially scan each property of a node in
-        * fdt_get_phandle(), 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. */
-       for (offset = fdt_next_node(fdt, -1, NULL);
-            offset >= 0;
-            offset = fdt_next_node(fdt, offset, NULL)) {
-               if (fdt_get_phandle(fdt, offset) == phandle)
-                       return offset;
-       }
-
-       return offset; /* error from fdt_next_node() */
-}
-
-static int _fdt_stringlist_contains(const char *strlist, int listlen,
-                                   const char *str)
-{
-       int len = strlen(str);
-       const char *p;
-
-       while (listlen >= len) {
-               if (memcmp(str, strlist, len+1) == 0)
-                       return 1;
-               p = memchr(strlist, '\0', listlen);
-               if (!p)
-                       return 0; /* malformed strlist.. */
-               listlen -= (p-strlist) + 1;
-               strlist = p + 1;
-       }
-       return 0;
-}
-
-int fdt_node_check_compatible(const void *fdt, int nodeoffset,
-                             const char *compatible)
-{
-       const void *prop;
-       int len;
-
-       prop = fdt_getprop(fdt, nodeoffset, "compatible", &len);
-       if (!prop)
-               return len;
-       if (_fdt_stringlist_contains(prop, len, compatible))
-               return 0;
-       else
-               return 1;
-}
-
-int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
-                                 const char *compatible)
-{
-       int offset, err;
-
-       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. */
-       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 offset; /* error from fdt_next_node() */
-}
+/*\r
+ * libfdt - Flat Device Tree manipulation\r
+ * Copyright (C) 2006 David Gibson, IBM Corporation.\r
+ *\r
+ * libfdt is dual licensed: you can use it either under the terms of\r
+ * the GPL, or the BSD license, at your option.\r
+ *\r
+ *  a) This library is free software; you can redistribute it and/or\r
+ *     modify it under the terms of the GNU General Public License as\r
+ *     published by the Free Software Foundation; either version 2 of the\r
+ *     License, or (at your option) any later version.\r
+ *\r
+ *     This library is distributed in the hope that it will be useful,\r
+ *     but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ *     GNU General Public License for more details.\r
+ *\r
+ *     You should have received a copy of the GNU General Public\r
+ *     License along with this library; if not, write to the Free\r
+ *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,\r
+ *     MA 02110-1301 USA\r
+ *\r
+ * Alternatively,\r
+ *\r
+ *  b) Redistribution and use in source and binary forms, with or\r
+ *     without modification, are permitted provided that the following\r
+ *     conditions are met:\r
+ *\r
+ *     1. Redistributions of source code must retain the above\r
+ *        copyright notice, this list of conditions and the following\r
+ *        disclaimer.\r
+ *     2. Redistributions in binary form must reproduce the above\r
+ *        copyright notice, this list of conditions and the following\r
+ *        disclaimer in the documentation and/or other materials\r
+ *        provided with the distribution.\r
+ *\r
+ *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND\r
+ *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,\r
+ *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r
+ *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\r
+ *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\r
+ *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r
+ *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\r
+ *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\r
+ *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR\r
+ *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,\r
+ *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ */\r
+#include "libfdt_env.h"\r
+\r
+#include <fdt.h>\r
+#include <libfdt.h>\r
+\r
+#include "libfdt_internal.h"\r
+\r
+static int _fdt_nodename_eq(const void *fdt, int offset,\r
+                           const char *s, int len)\r
+{\r
+       const char *p = fdt_offset_ptr(fdt, offset + FDT_TAGSIZE, len+1);\r
+\r
+       if (! p)\r
+               /* short match */\r
+               return 0;\r
+\r
+       if (memcmp(p, s, len) != 0)\r
+               return 0;\r
+\r
+       if (p[len] == '\0')\r
+               return 1;\r
+       else if (!memchr(s, '@', len) && (p[len] == '@'))\r
+               return 1;\r
+       else\r
+               return 0;\r
+}\r
+\r
+const char *fdt_string(const void *fdt, int stroffset)\r
+{\r
+       return (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset;\r
+}\r
+\r
+static int _fdt_string_eq(const void *fdt, int stroffset,\r
+                         const char *s, int len)\r
+{\r
+       const char *p = fdt_string(fdt, stroffset);\r
+\r
+       return (strlen(p) == len) && (memcmp(p, s, len) == 0);\r
+}\r
+\r
+int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)\r
+{\r
+       FDT_CHECK_HEADER(fdt);\r
+       *address = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->address);\r
+       *size = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->size);\r
+       return 0;\r
+}\r
+\r
+int fdt_num_mem_rsv(const void *fdt)\r
+{\r
+       int i = 0;\r
+\r
+       while (fdt64_to_cpu(_fdt_mem_rsv(fdt, i)->size) != 0)\r
+               i++;\r
+       return i;\r
+}\r
+\r
+static int _nextprop(const void *fdt, int offset)\r
+{\r
+       uint32_t tag;\r
+       int nextoffset;\r
+\r
+       do {\r
+               tag = fdt_next_tag(fdt, offset, &nextoffset);\r
+\r
+               switch (tag) {\r
+               case FDT_END:\r
+                       if (nextoffset >= 0)\r
+                               return -FDT_ERR_BADSTRUCTURE;\r
+                       else\r
+                               return nextoffset;\r
+\r
+               case FDT_PROP:\r
+                       return offset;\r
+               }\r
+               offset = nextoffset;\r
+       } while (tag == FDT_NOP);\r
+\r
+       return -FDT_ERR_NOTFOUND;\r
+}\r
+\r
+int fdt_subnode_offset_namelen(const void *fdt, int offset,\r
+                              const char *name, int namelen)\r
+{\r
+       int depth;\r
+\r
+       FDT_CHECK_HEADER(fdt);\r
+\r
+       for (depth = 0;\r
+            (offset >= 0) && (depth >= 0);\r
+            offset = fdt_next_node(fdt, offset, &depth))\r
+               if ((depth == 1)\r
+                   && _fdt_nodename_eq(fdt, offset, name, namelen))\r
+                       return offset;\r
+\r
+       if (depth < 0)\r
+               return -FDT_ERR_NOTFOUND;\r
+       return offset; /* error */\r
+}\r
+\r
+int fdt_subnode_offset(const void *fdt, int parentoffset,\r
+                      const char *name)\r
+{\r
+       return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name));\r
+}\r
+\r
+int fdt_path_offset(const void *fdt, const char *path)\r
+{\r
+       const char *end = path + strlen(path);\r
+       const char *p = path;\r
+       int offset = 0;\r
+\r
+       FDT_CHECK_HEADER(fdt);\r
+\r
+       /* see if we have an alias */\r
+       if (*path != '/') {\r
+               const char *q = strchr(path, '/');\r
+\r
+               if (!q)\r
+                       q = end;\r
+\r
+               p = fdt_get_alias_namelen(fdt, p, q - p);\r
+               if (!p)\r
+                       return -FDT_ERR_BADPATH;\r
+               offset = fdt_path_offset(fdt, p);\r
+\r
+               p = q;\r
+       }\r
+\r
+       while (*p) {\r
+               const char *q;\r
+\r
+               while (*p == '/')\r
+                       p++;\r
+               if (! *p)\r
+                       return offset;\r
+               q = strchr(p, '/');\r
+               if (! q)\r
+                       q = end;\r
+\r
+               offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p);\r
+               if (offset < 0)\r
+                       return offset;\r
+\r
+               p = q;\r
+       }\r
+\r
+       return offset;\r
+}\r
+\r
+const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)\r
+{\r
+       const struct fdt_node_header *nh = _fdt_offset_ptr(fdt, nodeoffset);\r
+       int err;\r
+\r
+       if (((err = fdt_check_header(fdt)) != 0)\r
+           || ((err = _fdt_check_node_offset(fdt, nodeoffset)) < 0))\r
+                       goto fail;\r
+\r
+       if (len)\r
+               *len = strlen(nh->name);\r
+\r
+       return nh->name;\r
+\r
+ fail:\r
+       if (len)\r
+               *len = err;\r
+       return NULL;\r
+}\r
+\r
+int fdt_first_property_offset(const void *fdt, int nodeoffset)\r
+{\r
+       int offset;\r
+\r
+       if ((offset = _fdt_check_node_offset(fdt, nodeoffset)) < 0)\r
+               return offset;\r
+\r
+       return _nextprop(fdt, offset);\r
+}\r
+\r
+int fdt_next_property_offset(const void *fdt, int offset)\r
+{\r
+       if ((offset = _fdt_check_prop_offset(fdt, offset)) < 0)\r
+               return offset;\r
+\r
+       return _nextprop(fdt, offset);\r
+}\r
+\r
+const struct fdt_property *fdt_get_property_by_offset(const void *fdt,\r
+                                                     int offset,\r
+                                                     int *lenp)\r
+{\r
+       int err;\r
+       const struct fdt_property *prop;\r
+\r
+       if ((err = _fdt_check_prop_offset(fdt, offset)) < 0) {\r
+               if (lenp)\r
+                       *lenp = err;\r
+               return NULL;\r
+       }\r
+\r
+       prop = _fdt_offset_ptr(fdt, offset);\r
+\r
+       if (lenp)\r
+               *lenp = fdt32_to_cpu(prop->len);\r
+\r
+       return prop;\r
+}\r
+\r
+const struct fdt_property *fdt_get_property_namelen(const void *fdt,\r
+                                                   int offset,\r
+                                                   const char *name,\r
+                                                   int namelen, int *lenp)\r
+{\r
+       for (offset = fdt_first_property_offset(fdt, offset);\r
+            (offset >= 0);\r
+            (offset = fdt_next_property_offset(fdt, offset))) {\r
+               const struct fdt_property *prop;\r
+\r
+               prop = fdt_get_property_by_offset(fdt, offset, lenp);\r
+               if (!prop) {\r
+                       offset = -FDT_ERR_INTERNAL;\r
+                       break;\r
+               }\r
+               if (_fdt_string_eq(fdt, fdt32_to_cpu(prop->nameoff),\r
+                                  name, namelen))\r
+                       return prop;\r
+       }\r
+\r
+       if (lenp)\r
+               *lenp = offset;\r
+       return NULL;\r
+}\r
+\r
+const struct fdt_property *fdt_get_property(const void *fdt,\r
+                                           int nodeoffset,\r
+                                           const char *name, int *lenp)\r
+{\r
+       return fdt_get_property_namelen(fdt, nodeoffset, name,\r
+                                       strlen(name), lenp);\r
+}\r
+\r
+const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,\r
+                               const char *name, int namelen, int *lenp)\r
+{\r
+       const struct fdt_property *prop;\r
+\r
+       prop = fdt_get_property_namelen(fdt, nodeoffset, name, namelen, lenp);\r
+       if (! prop)\r
+               return NULL;\r
+\r
+       return prop->data;\r
+}\r
+\r
+const void *fdt_getprop_by_offset(const void *fdt, int offset,\r
+                                 const char **namep, int *lenp)\r
+{\r
+       const struct fdt_property *prop;\r
+\r
+       prop = fdt_get_property_by_offset(fdt, offset, lenp);\r
+       if (!prop)\r
+               return NULL;\r
+       if (namep)\r
+               *namep = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));\r
+       return prop->data;\r
+}\r
+\r
+const void *fdt_getprop(const void *fdt, int nodeoffset,\r
+                       const char *name, int *lenp)\r
+{\r
+       return fdt_getprop_namelen(fdt, nodeoffset, name, strlen(name), lenp);\r
+}\r
+\r
+uint32_t fdt_get_phandle(const void *fdt, int nodeoffset)\r
+{\r
+       const uint32_t *php;\r
+       int len;\r
+\r
+       /* FIXME: This is a bit sub-optimal, since we potentially scan\r
+        * over all the properties twice. */\r
+       php = fdt_getprop(fdt, nodeoffset, "phandle", &len);\r
+       if (!php || (len != sizeof(*php))) {\r
+               php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len);\r
+               if (!php || (len != sizeof(*php)))\r
+                       return 0;\r
+       }\r
+\r
+       return fdt32_to_cpu(*php);\r
+}\r
+\r
+const char *fdt_get_alias_namelen(const void *fdt,\r
+                                 const char *name, int namelen)\r
+{\r
+       int aliasoffset;\r
+\r
+       aliasoffset = fdt_path_offset(fdt, "/aliases");\r
+       if (aliasoffset < 0)\r
+               return NULL;\r
+\r
+       return fdt_getprop_namelen(fdt, aliasoffset, name, namelen, NULL);\r
+}\r
+\r
+const char *fdt_get_alias(const void *fdt, const char *name)\r
+{\r
+       return fdt_get_alias_namelen(fdt, name, strlen(name));\r
+}\r
+\r
+int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)\r
+{\r
+       int pdepth = 0, p = 0;\r
+       int offset, depth, namelen;\r
+       const char *name;\r
+\r
+       FDT_CHECK_HEADER(fdt);\r
+\r
+       if (buflen < 2)\r
+               return -FDT_ERR_NOSPACE;\r
+\r
+       for (offset = 0, depth = 0;\r
+            (offset >= 0) && (offset <= nodeoffset);\r
+            offset = fdt_next_node(fdt, offset, &depth)) {\r
+               while (pdepth > depth) {\r
+                       do {\r
+                               p--;\r
+                       } while (buf[p-1] != '/');\r
+                       pdepth--;\r
+               }\r
+\r
+               if (pdepth >= depth) {\r
+                       name = fdt_get_name(fdt, offset, &namelen);\r
+                       if (!name)\r
+                               return namelen;\r
+                       if ((p + namelen + 1) <= buflen) {\r
+                               memcpy(buf + p, name, namelen);\r
+                               p += namelen;\r
+                               buf[p++] = '/';\r
+                               pdepth++;\r
+                       }\r
+               }\r
+\r
+               if (offset == nodeoffset) {\r
+                       if (pdepth < (depth + 1))\r
+                               return -FDT_ERR_NOSPACE;\r
+\r
+                       if (p > 1) /* special case so that root path is "/", not "" */\r
+                               p--;\r
+                       buf[p] = '\0';\r
+                       return 0;\r
+               }\r
+       }\r
+\r
+       if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))\r
+               return -FDT_ERR_BADOFFSET;\r
+       else if (offset == -FDT_ERR_BADOFFSET)\r
+               return -FDT_ERR_BADSTRUCTURE;\r
+\r
+       return offset; /* error from fdt_next_node() */\r
+}\r
+\r
+int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,\r
+                                int supernodedepth, int *nodedepth)\r
+{\r
+       int offset, depth;\r
+       int supernodeoffset = -FDT_ERR_INTERNAL;\r
+\r
+       FDT_CHECK_HEADER(fdt);\r
+\r
+       if (supernodedepth < 0)\r
+               return -FDT_ERR_NOTFOUND;\r
+\r
+       for (offset = 0, depth = 0;\r
+            (offset >= 0) && (offset <= nodeoffset);\r
+            offset = fdt_next_node(fdt, offset, &depth)) {\r
+               if (depth == supernodedepth)\r
+                       supernodeoffset = offset;\r
+\r
+               if (offset == nodeoffset) {\r
+                       if (nodedepth)\r
+                               *nodedepth = depth;\r
+\r
+                       if (supernodedepth > depth)\r
+                               return -FDT_ERR_NOTFOUND;\r
+                       else\r
+                               return supernodeoffset;\r
+               }\r
+       }\r
+\r
+       if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))\r
+               return -FDT_ERR_BADOFFSET;\r
+       else if (offset == -FDT_ERR_BADOFFSET)\r
+               return -FDT_ERR_BADSTRUCTURE;\r
+\r
+       return offset; /* error from fdt_next_node() */\r
+}\r
+\r
+int fdt_node_depth(const void *fdt, int nodeoffset)\r
+{\r
+       int nodedepth;\r
+       int err;\r
+\r
+       err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth);\r
+       if (err)\r
+               return (err < 0) ? err : -FDT_ERR_INTERNAL;\r
+       return nodedepth;\r
+}\r
+\r
+int fdt_parent_offset(const void *fdt, int nodeoffset)\r
+{\r
+       int nodedepth = fdt_node_depth(fdt, nodeoffset);\r
+\r
+       if (nodedepth < 0)\r
+               return nodedepth;\r
+       return fdt_supernode_atdepth_offset(fdt, nodeoffset,\r
+                                           nodedepth - 1, NULL);\r
+}\r
+\r
+int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,\r
+                                 const char *propname,\r
+                                 const void *propval, int proplen)\r
+{\r
+       int offset;\r
+       const void *val;\r
+       int len;\r
+\r
+       FDT_CHECK_HEADER(fdt);\r
+\r
+       /* FIXME: The algorithm here is pretty horrible: we scan each\r
+        * property of a node in fdt_getprop(), then if that didn't\r
+        * find what we want, we scan over them again making our way\r
+        * to the next node.  Still it's the easiest to implement\r
+        * approach; performance can come later. */\r
+       for (offset = fdt_next_node(fdt, startoffset, NULL);\r
+            offset >= 0;\r
+            offset = fdt_next_node(fdt, offset, NULL)) {\r
+               val = fdt_getprop(fdt, offset, propname, &len);\r
+               if (val && (len == proplen)\r
+                   && (memcmp(val, propval, len) == 0))\r
+                       return offset;\r
+       }\r
+\r
+       return offset; /* error from fdt_next_node() */\r
+}\r
+\r
+int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle)\r
+{\r
+       int offset;\r
+\r
+       if ((phandle == 0) || (phandle == (uint32_t)-1))\r
+               return -FDT_ERR_BADPHANDLE;\r
+\r
+       FDT_CHECK_HEADER(fdt);\r
+\r
+       /* FIXME: The algorithm here is pretty horrible: we\r
+        * potentially scan each property of a node in\r
+        * fdt_get_phandle(), then if that didn't find what\r
+        * we want, we scan over them again making our way to the next\r
+        * node.  Still it's the easiest to implement approach;\r
+        * performance can come later. */\r
+       for (offset = fdt_next_node(fdt, -1, NULL);\r
+            offset >= 0;\r
+            offset = fdt_next_node(fdt, offset, NULL)) {\r
+               if (fdt_get_phandle(fdt, offset) == phandle)\r
+                       return offset;\r
+       }\r
+\r
+       return offset; /* error from fdt_next_node() */\r
+}\r
+\r
+static int _fdt_stringlist_contains(const char *strlist, int listlen,\r
+                                   const char *str)\r
+{\r
+       int len = strlen(str);\r
+       const char *p;\r
+\r
+       while (listlen >= len) {\r
+               if (memcmp(str, strlist, len+1) == 0)\r
+                       return 1;\r
+               p = memchr(strlist, '\0', listlen);\r
+               if (!p)\r
+                       return 0; /* malformed strlist.. */\r
+               listlen -= (p-strlist) + 1;\r
+               strlist = p + 1;\r
+       }\r
+       return 0;\r
+}\r
+\r
+int fdt_node_check_compatible(const void *fdt, int nodeoffset,\r
+                             const char *compatible)\r
+{\r
+       const void *prop;\r
+       int len;\r
+\r
+       prop = fdt_getprop(fdt, nodeoffset, "compatible", &len);\r
+       if (!prop)\r
+               return len;\r
+       if (_fdt_stringlist_contains(prop, len, compatible))\r
+               return 0;\r
+       else\r
+               return 1;\r
+}\r
+\r
+int fdt_node_offset_by_compatible(const void *fdt, int startoffset,\r
+                                 const char *compatible)\r
+{\r
+       int offset, err;\r
+\r
+       FDT_CHECK_HEADER(fdt);\r
+\r
+       /* FIXME: The algorithm here is pretty horrible: we scan each\r
+        * property of a node in fdt_node_check_compatible(), then if\r
+        * that didn't find what we want, we scan over them again\r
+        * making our way to the next node.  Still it's the easiest to\r
+        * implement approach; performance can come later. */\r
+       for (offset = fdt_next_node(fdt, startoffset, NULL);\r
+            offset >= 0;\r
+            offset = fdt_next_node(fdt, offset, NULL)) {\r
+               err = fdt_node_check_compatible(fdt, offset, compatible);\r
+               if ((err < 0) && (err != -FDT_ERR_NOTFOUND))\r
+                       return err;\r
+               else if (err == 0)\r
+                       return offset;\r
+       }\r
+\r
+       return offset; /* error from fdt_next_node() */\r
+}\r