19537Satgutier@umich.edu/*
29537Satgutier@umich.edu * libfdt - Flat Device Tree manipulation
39537Satgutier@umich.edu * Copyright (C) 2006 David Gibson, IBM Corporation.
49537Satgutier@umich.edu *
59537Satgutier@umich.edu *     Redistribution and use in source and binary forms, with or
69537Satgutier@umich.edu *     without modification, are permitted provided that the following
79537Satgutier@umich.edu *     conditions are met:
89537Satgutier@umich.edu *
99537Satgutier@umich.edu *     1. Redistributions of source code must retain the above
109537Satgutier@umich.edu *        copyright notice, this list of conditions and the following
119537Satgutier@umich.edu *        disclaimer.
129537Satgutier@umich.edu *     2. Redistributions in binary form must reproduce the above
139537Satgutier@umich.edu *        copyright notice, this list of conditions and the following
149537Satgutier@umich.edu *        disclaimer in the documentation and/or other materials
159537Satgutier@umich.edu *        provided with the distribution.
169537Satgutier@umich.edu *
179537Satgutier@umich.edu *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
189537Satgutier@umich.edu *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
199537Satgutier@umich.edu *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
209537Satgutier@umich.edu *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
219537Satgutier@umich.edu *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
229537Satgutier@umich.edu *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
239537Satgutier@umich.edu *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
249537Satgutier@umich.edu *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
259537Satgutier@umich.edu *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
269537Satgutier@umich.edu *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
279537Satgutier@umich.edu *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
289537Satgutier@umich.edu *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
299537Satgutier@umich.edu *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
309537Satgutier@umich.edu */
319537Satgutier@umich.edu#include <fdt.h>
329537Satgutier@umich.edu#include <libfdt.h>
339537Satgutier@umich.edu
349537Satgutier@umich.edu#include "libfdt_env.h"
359537Satgutier@umich.edu#include "libfdt_internal.h"
369537Satgutier@umich.edu
379537Satgutier@umich.edustatic int _fdt_nodename_eq(const void *fdt, int offset,
389537Satgutier@umich.edu                            const char *s, int len)
399537Satgutier@umich.edu{
409537Satgutier@umich.edu        const char *p = fdt_offset_ptr(fdt, offset + FDT_TAGSIZE, len+1);
419537Satgutier@umich.edu
429537Satgutier@umich.edu        if (! p)
439537Satgutier@umich.edu                /* short match */
449537Satgutier@umich.edu                return 0;
459537Satgutier@umich.edu
469537Satgutier@umich.edu        if (memcmp(p, s, len) != 0)
479537Satgutier@umich.edu                return 0;
489537Satgutier@umich.edu
499537Satgutier@umich.edu        if (p[len] == '\0')
509537Satgutier@umich.edu                return 1;
519537Satgutier@umich.edu        else if (!memchr(s, '@', len) && (p[len] == '@'))
529537Satgutier@umich.edu                return 1;
539537Satgutier@umich.edu        else
549537Satgutier@umich.edu                return 0;
559537Satgutier@umich.edu}
569537Satgutier@umich.edu
579537Satgutier@umich.educonst char *fdt_string(const void *fdt, int stroffset)
589537Satgutier@umich.edu{
599537Satgutier@umich.edu        return (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset;
609537Satgutier@umich.edu}
619537Satgutier@umich.edu
629537Satgutier@umich.edustatic int _fdt_string_eq(const void *fdt, int stroffset,
639537Satgutier@umich.edu                          const char *s, int len)
649537Satgutier@umich.edu{
659537Satgutier@umich.edu        const char *p = fdt_string(fdt, stroffset);
669537Satgutier@umich.edu
679537Satgutier@umich.edu        return (strlen(p) == len) && (memcmp(p, s, len) == 0);
689537Satgutier@umich.edu}
699537Satgutier@umich.edu
709537Satgutier@umich.eduint fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
719537Satgutier@umich.edu{
729537Satgutier@umich.edu        FDT_CHECK_HEADER(fdt);
739537Satgutier@umich.edu        *address = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->address);
749537Satgutier@umich.edu        *size = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->size);
759537Satgutier@umich.edu        return 0;
769537Satgutier@umich.edu}
779537Satgutier@umich.edu
789537Satgutier@umich.eduint fdt_num_mem_rsv(const void *fdt)
799537Satgutier@umich.edu{
809537Satgutier@umich.edu        int i = 0;
819537Satgutier@umich.edu
829537Satgutier@umich.edu        while (fdt64_to_cpu(_fdt_mem_rsv(fdt, i)->size) != 0)
839537Satgutier@umich.edu                i++;
849537Satgutier@umich.edu        return i;
859537Satgutier@umich.edu}
869537Satgutier@umich.edu
879537Satgutier@umich.edustatic int _nextprop(const void *fdt, int offset)
889537Satgutier@umich.edu{
899537Satgutier@umich.edu        uint32_t tag;
909537Satgutier@umich.edu        int nextoffset;
919537Satgutier@umich.edu
929537Satgutier@umich.edu        do {
939537Satgutier@umich.edu                tag = fdt_next_tag(fdt, offset, &nextoffset);
949537Satgutier@umich.edu
959537Satgutier@umich.edu                switch (tag) {
969537Satgutier@umich.edu                case FDT_END:
979537Satgutier@umich.edu                        if (nextoffset >= 0)
989537Satgutier@umich.edu                                return -FDT_ERR_BADSTRUCTURE;
999537Satgutier@umich.edu                        else
1009537Satgutier@umich.edu                                return nextoffset;
1019537Satgutier@umich.edu
1029537Satgutier@umich.edu                case FDT_PROP:
1039537Satgutier@umich.edu                        return offset;
1049537Satgutier@umich.edu                }
1059537Satgutier@umich.edu                offset = nextoffset;
1069537Satgutier@umich.edu        } while (tag == FDT_NOP);
1079537Satgutier@umich.edu
1089537Satgutier@umich.edu        return -FDT_ERR_NOTFOUND;
1099537Satgutier@umich.edu}
1109537Satgutier@umich.edu
1119537Satgutier@umich.eduint fdt_subnode_offset_namelen(const void *fdt, int offset,
1129537Satgutier@umich.edu                               const char *name, int namelen)
1139537Satgutier@umich.edu{
1149537Satgutier@umich.edu        int depth;
1159537Satgutier@umich.edu
1169537Satgutier@umich.edu        FDT_CHECK_HEADER(fdt);
1179537Satgutier@umich.edu
1189537Satgutier@umich.edu        for (depth = 0;
1199537Satgutier@umich.edu             (offset >= 0) && (depth >= 0);
1209537Satgutier@umich.edu             offset = fdt_next_node(fdt, offset, &depth))
1219537Satgutier@umich.edu                if ((depth == 1)
1229537Satgutier@umich.edu                    && _fdt_nodename_eq(fdt, offset, name, namelen))
1239537Satgutier@umich.edu                        return offset;
1249537Satgutier@umich.edu
1259537Satgutier@umich.edu        if (depth < 0)
1269537Satgutier@umich.edu                return -FDT_ERR_NOTFOUND;
1279537Satgutier@umich.edu        return offset; /* error */
1289537Satgutier@umich.edu}
1299537Satgutier@umich.edu
1309537Satgutier@umich.eduint fdt_subnode_offset(const void *fdt, int parentoffset,
1319537Satgutier@umich.edu                       const char *name)
1329537Satgutier@umich.edu{
1339537Satgutier@umich.edu        return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name));
1349537Satgutier@umich.edu}
1359537Satgutier@umich.edu
1369537Satgutier@umich.eduint fdt_path_offset(const void *fdt, const char *path)
1379537Satgutier@umich.edu{
1389537Satgutier@umich.edu        const char *end = path + strlen(path);
1399537Satgutier@umich.edu        const char *p = path;
1409537Satgutier@umich.edu        int offset = 0;
1419537Satgutier@umich.edu
1429537Satgutier@umich.edu        FDT_CHECK_HEADER(fdt);
1439537Satgutier@umich.edu
1449537Satgutier@umich.edu        /* see if we have an alias */
1459537Satgutier@umich.edu        if (*path != '/') {
1469537Satgutier@umich.edu                const char *q = strchr(path, '/');
1479537Satgutier@umich.edu
1489537Satgutier@umich.edu                if (!q)
1499537Satgutier@umich.edu                        q = end;
1509537Satgutier@umich.edu
1519537Satgutier@umich.edu                p = fdt_get_alias_namelen(fdt, p, q - p);
1529537Satgutier@umich.edu                if (!p)
1539537Satgutier@umich.edu                        return -FDT_ERR_BADPATH;
1549537Satgutier@umich.edu                offset = fdt_path_offset(fdt, p);
1559537Satgutier@umich.edu
1569537Satgutier@umich.edu                p = q;
1579537Satgutier@umich.edu        }
1589537Satgutier@umich.edu
1599537Satgutier@umich.edu        while (*p) {
1609537Satgutier@umich.edu                const char *q;
1619537Satgutier@umich.edu
1629537Satgutier@umich.edu                while (*p == '/')
1639537Satgutier@umich.edu                        p++;
1649537Satgutier@umich.edu                if (! *p)
1659537Satgutier@umich.edu                        return offset;
1669537Satgutier@umich.edu                q = strchr(p, '/');
1679537Satgutier@umich.edu                if (! q)
1689537Satgutier@umich.edu                        q = end;
1699537Satgutier@umich.edu
1709537Satgutier@umich.edu                offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p);
1719537Satgutier@umich.edu                if (offset < 0)
1729537Satgutier@umich.edu                        return offset;
1739537Satgutier@umich.edu
1749537Satgutier@umich.edu                p = q;
1759537Satgutier@umich.edu        }
1769537Satgutier@umich.edu
1779537Satgutier@umich.edu        return offset;
1789537Satgutier@umich.edu}
1799537Satgutier@umich.edu
1809537Satgutier@umich.educonst char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
1819537Satgutier@umich.edu{
1829537Satgutier@umich.edu        const struct fdt_node_header *nh = _fdt_offset_ptr(fdt, nodeoffset);
1839537Satgutier@umich.edu        int err;
1849537Satgutier@umich.edu
1859537Satgutier@umich.edu        if (((err = fdt_check_header(fdt)) != 0)
1869537Satgutier@umich.edu            || ((err = _fdt_check_node_offset(fdt, nodeoffset)) < 0))
1879537Satgutier@umich.edu                        goto fail;
1889537Satgutier@umich.edu
1899537Satgutier@umich.edu        if (len)
1909537Satgutier@umich.edu                *len = strlen(nh->name);
1919537Satgutier@umich.edu
1929537Satgutier@umich.edu        return nh->name;
1939537Satgutier@umich.edu
1949537Satgutier@umich.edu fail:
1959537Satgutier@umich.edu        if (len)
1969537Satgutier@umich.edu                *len = err;
1979537Satgutier@umich.edu        return NULL;
1989537Satgutier@umich.edu}
1999537Satgutier@umich.edu
2009537Satgutier@umich.eduint fdt_first_property_offset(const void *fdt, int nodeoffset)
2019537Satgutier@umich.edu{
2029537Satgutier@umich.edu        int offset;
2039537Satgutier@umich.edu
2049537Satgutier@umich.edu        if ((offset = _fdt_check_node_offset(fdt, nodeoffset)) < 0)
2059537Satgutier@umich.edu                return offset;
2069537Satgutier@umich.edu
2079537Satgutier@umich.edu        return _nextprop(fdt, offset);
2089537Satgutier@umich.edu}
2099537Satgutier@umich.edu
2109537Satgutier@umich.eduint fdt_next_property_offset(const void *fdt, int offset)
2119537Satgutier@umich.edu{
2129537Satgutier@umich.edu        if ((offset = _fdt_check_prop_offset(fdt, offset)) < 0)
2139537Satgutier@umich.edu                return offset;
2149537Satgutier@umich.edu
2159537Satgutier@umich.edu        return _nextprop(fdt, offset);
2169537Satgutier@umich.edu}
2179537Satgutier@umich.edu
2189537Satgutier@umich.educonst struct fdt_property *fdt_get_property_by_offset(const void *fdt,
2199537Satgutier@umich.edu                                                      int offset,
2209537Satgutier@umich.edu                                                      int *lenp)
2219537Satgutier@umich.edu{
2229537Satgutier@umich.edu        int err;
2239537Satgutier@umich.edu        const struct fdt_property *prop;
2249537Satgutier@umich.edu
2259537Satgutier@umich.edu        if ((err = _fdt_check_prop_offset(fdt, offset)) < 0) {
2269537Satgutier@umich.edu                if (lenp)
2279537Satgutier@umich.edu                        *lenp = err;
2289537Satgutier@umich.edu                return NULL;
2299537Satgutier@umich.edu        }
2309537Satgutier@umich.edu
2319537Satgutier@umich.edu        prop = _fdt_offset_ptr(fdt, offset);
2329537Satgutier@umich.edu
2339537Satgutier@umich.edu        if (lenp)
2349537Satgutier@umich.edu                *lenp = fdt32_to_cpu(prop->len);
2359537Satgutier@umich.edu
2369537Satgutier@umich.edu        return prop;
2379537Satgutier@umich.edu}
2389537Satgutier@umich.edu
2399537Satgutier@umich.educonst struct fdt_property *fdt_get_property_namelen(const void *fdt,
2409537Satgutier@umich.edu                                                    int offset,
2419537Satgutier@umich.edu                                                    const char *name,
2429537Satgutier@umich.edu                                                    int namelen, int *lenp)
2439537Satgutier@umich.edu{
2449537Satgutier@umich.edu        for (offset = fdt_first_property_offset(fdt, offset);
2459537Satgutier@umich.edu             (offset >= 0);
2469537Satgutier@umich.edu             (offset = fdt_next_property_offset(fdt, offset))) {
2479537Satgutier@umich.edu                const struct fdt_property *prop;
2489537Satgutier@umich.edu
2499537Satgutier@umich.edu                if (!(prop = fdt_get_property_by_offset(fdt, offset, lenp))) {
2509537Satgutier@umich.edu                        offset = -FDT_ERR_INTERNAL;
2519537Satgutier@umich.edu                        break;
2529537Satgutier@umich.edu                }
2539537Satgutier@umich.edu                if (_fdt_string_eq(fdt, fdt32_to_cpu(prop->nameoff),
2549537Satgutier@umich.edu                                   name, namelen))
2559537Satgutier@umich.edu                        return prop;
2569537Satgutier@umich.edu        }
2579537Satgutier@umich.edu
2589537Satgutier@umich.edu        if (lenp)
2599537Satgutier@umich.edu                *lenp = offset;
2609537Satgutier@umich.edu        return NULL;
2619537Satgutier@umich.edu}
2629537Satgutier@umich.edu
2639537Satgutier@umich.educonst struct fdt_property *fdt_get_property(const void *fdt,
2649537Satgutier@umich.edu                                            int nodeoffset,
2659537Satgutier@umich.edu                                            const char *name, int *lenp)
2669537Satgutier@umich.edu{
2679537Satgutier@umich.edu        return fdt_get_property_namelen(fdt, nodeoffset, name,
2689537Satgutier@umich.edu                                        strlen(name), lenp);
2699537Satgutier@umich.edu}
2709537Satgutier@umich.edu
2719537Satgutier@umich.educonst void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
2729537Satgutier@umich.edu                                const char *name, int namelen, int *lenp)
2739537Satgutier@umich.edu{
2749537Satgutier@umich.edu        const struct fdt_property *prop;
2759537Satgutier@umich.edu
2769537Satgutier@umich.edu        prop = fdt_get_property_namelen(fdt, nodeoffset, name, namelen, lenp);
2779537Satgutier@umich.edu        if (! prop)
2789537Satgutier@umich.edu                return NULL;
2799537Satgutier@umich.edu
2809537Satgutier@umich.edu        return prop->data;
2819537Satgutier@umich.edu}
2829537Satgutier@umich.edu
2839537Satgutier@umich.educonst void *fdt_getprop_by_offset(const void *fdt, int offset,
2849537Satgutier@umich.edu                                  const char **namep, int *lenp)
2859537Satgutier@umich.edu{
2869537Satgutier@umich.edu        const struct fdt_property *prop;
2879537Satgutier@umich.edu
2889537Satgutier@umich.edu        prop = fdt_get_property_by_offset(fdt, offset, lenp);
2899537Satgutier@umich.edu        if (!prop)
2909537Satgutier@umich.edu                return NULL;
2919537Satgutier@umich.edu        if (namep)
2929537Satgutier@umich.edu                *namep = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
2939537Satgutier@umich.edu        return prop->data;
2949537Satgutier@umich.edu}
2959537Satgutier@umich.edu
2969537Satgutier@umich.educonst void *fdt_getprop(const void *fdt, int nodeoffset,
2979537Satgutier@umich.edu                        const char *name, int *lenp)
2989537Satgutier@umich.edu{
2999537Satgutier@umich.edu        return fdt_getprop_namelen(fdt, nodeoffset, name, strlen(name), lenp);
3009537Satgutier@umich.edu}
3019537Satgutier@umich.edu
3029537Satgutier@umich.eduuint32_t fdt_get_phandle(const void *fdt, int nodeoffset)
3039537Satgutier@umich.edu{
3049537Satgutier@umich.edu        const fdt32_t *php;
3059537Satgutier@umich.edu        int len;
3069537Satgutier@umich.edu
3079537Satgutier@umich.edu        /* FIXME: This is a bit sub-optimal, since we potentially scan
3089537Satgutier@umich.edu         * over all the properties twice. */
3099537Satgutier@umich.edu        php = fdt_getprop(fdt, nodeoffset, "phandle", &len);
3109537Satgutier@umich.edu        if (!php || (len != sizeof(*php))) {
3119537Satgutier@umich.edu                php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len);
3129537Satgutier@umich.edu                if (!php || (len != sizeof(*php)))
3139537Satgutier@umich.edu                        return 0;
3149537Satgutier@umich.edu        }
3159537Satgutier@umich.edu
3169537Satgutier@umich.edu        return fdt32_to_cpu(*php);
3179537Satgutier@umich.edu}
3189537Satgutier@umich.edu
3199537Satgutier@umich.educonst char *fdt_get_alias_namelen(const void *fdt,
3209537Satgutier@umich.edu                                  const char *name, int namelen)
3219537Satgutier@umich.edu{
3229537Satgutier@umich.edu        int aliasoffset;
3239537Satgutier@umich.edu
3249537Satgutier@umich.edu        aliasoffset = fdt_path_offset(fdt, "/aliases");
3259537Satgutier@umich.edu        if (aliasoffset < 0)
3269537Satgutier@umich.edu                return NULL;
3279537Satgutier@umich.edu
3289537Satgutier@umich.edu        return fdt_getprop_namelen(fdt, aliasoffset, name, namelen, NULL);
3299537Satgutier@umich.edu}
3309537Satgutier@umich.edu
3319537Satgutier@umich.educonst char *fdt_get_alias(const void *fdt, const char *name)
3329537Satgutier@umich.edu{
3339537Satgutier@umich.edu        return fdt_get_alias_namelen(fdt, name, strlen(name));
3349537Satgutier@umich.edu}
3359537Satgutier@umich.edu
3369537Satgutier@umich.eduint fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)
3379537Satgutier@umich.edu{
3389537Satgutier@umich.edu        int pdepth = 0, p = 0;
3399537Satgutier@umich.edu        int offset, depth, namelen;
3409537Satgutier@umich.edu        const char *name;
3419537Satgutier@umich.edu
3429537Satgutier@umich.edu        FDT_CHECK_HEADER(fdt);
3439537Satgutier@umich.edu
3449537Satgutier@umich.edu        if (buflen < 2)
3459537Satgutier@umich.edu                return -FDT_ERR_NOSPACE;
3469537Satgutier@umich.edu
3479537Satgutier@umich.edu        for (offset = 0, depth = 0;
3489537Satgutier@umich.edu             (offset >= 0) && (offset <= nodeoffset);
3499537Satgutier@umich.edu             offset = fdt_next_node(fdt, offset, &depth)) {
3509537Satgutier@umich.edu                while (pdepth > depth) {
3519537Satgutier@umich.edu                        do {
3529537Satgutier@umich.edu                                p--;
3539537Satgutier@umich.edu                        } while (buf[p-1] != '/');
3549537Satgutier@umich.edu                        pdepth--;
3559537Satgutier@umich.edu                }
3569537Satgutier@umich.edu
3579537Satgutier@umich.edu                if (pdepth >= depth) {
3589537Satgutier@umich.edu                        name = fdt_get_name(fdt, offset, &namelen);
3599537Satgutier@umich.edu                        if (!name)
3609537Satgutier@umich.edu                                return namelen;
3619537Satgutier@umich.edu                        if ((p + namelen + 1) <= buflen) {
3629537Satgutier@umich.edu                                memcpy(buf + p, name, namelen);
3639537Satgutier@umich.edu                                p += namelen;
3649537Satgutier@umich.edu                                buf[p++] = '/';
3659537Satgutier@umich.edu                                pdepth++;
3669537Satgutier@umich.edu                        }
3679537Satgutier@umich.edu                }
3689537Satgutier@umich.edu
3699537Satgutier@umich.edu                if (offset == nodeoffset) {
3709537Satgutier@umich.edu                        if (pdepth < (depth + 1))
3719537Satgutier@umich.edu                                return -FDT_ERR_NOSPACE;
3729537Satgutier@umich.edu
3739537Satgutier@umich.edu                        if (p > 1) /* special case so that root path is "/", not "" */
3749537Satgutier@umich.edu                                p--;
3759537Satgutier@umich.edu                        buf[p] = '\0';
3769537Satgutier@umich.edu                        return 0;
3779537Satgutier@umich.edu                }
3789537Satgutier@umich.edu        }
3799537Satgutier@umich.edu
3809537Satgutier@umich.edu        if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
3819537Satgutier@umich.edu                return -FDT_ERR_BADOFFSET;
3829537Satgutier@umich.edu        else if (offset == -FDT_ERR_BADOFFSET)
3839537Satgutier@umich.edu                return -FDT_ERR_BADSTRUCTURE;
3849537Satgutier@umich.edu
3859537Satgutier@umich.edu        return offset; /* error from fdt_next_node() */
3869537Satgutier@umich.edu}
3879537Satgutier@umich.edu
3889537Satgutier@umich.eduint fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
3899537Satgutier@umich.edu                                 int supernodedepth, int *nodedepth)
3909537Satgutier@umich.edu{
3919537Satgutier@umich.edu        int offset, depth;
3929537Satgutier@umich.edu        int supernodeoffset = -FDT_ERR_INTERNAL;
3939537Satgutier@umich.edu
3949537Satgutier@umich.edu        FDT_CHECK_HEADER(fdt);
3959537Satgutier@umich.edu
3969537Satgutier@umich.edu        if (supernodedepth < 0)
3979537Satgutier@umich.edu                return -FDT_ERR_NOTFOUND;
3989537Satgutier@umich.edu
3999537Satgutier@umich.edu        for (offset = 0, depth = 0;
4009537Satgutier@umich.edu             (offset >= 0) && (offset <= nodeoffset);
4019537Satgutier@umich.edu             offset = fdt_next_node(fdt, offset, &depth)) {
4029537Satgutier@umich.edu                if (depth == supernodedepth)
4039537Satgutier@umich.edu                        supernodeoffset = offset;
4049537Satgutier@umich.edu
4059537Satgutier@umich.edu                if (offset == nodeoffset) {
4069537Satgutier@umich.edu                        if (nodedepth)
4079537Satgutier@umich.edu                                *nodedepth = depth;
4089537Satgutier@umich.edu
4099537Satgutier@umich.edu                        if (supernodedepth > depth)
4109537Satgutier@umich.edu                                return -FDT_ERR_NOTFOUND;
4119537Satgutier@umich.edu                        else
4129537Satgutier@umich.edu                                return supernodeoffset;
4139537Satgutier@umich.edu                }
4149537Satgutier@umich.edu        }
4159537Satgutier@umich.edu
4169537Satgutier@umich.edu        if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
4179537Satgutier@umich.edu                return -FDT_ERR_BADOFFSET;
4189537Satgutier@umich.edu        else if (offset == -FDT_ERR_BADOFFSET)
4199537Satgutier@umich.edu                return -FDT_ERR_BADSTRUCTURE;
4209537Satgutier@umich.edu
4219537Satgutier@umich.edu        return offset; /* error from fdt_next_node() */
4229537Satgutier@umich.edu}
4239537Satgutier@umich.edu
4249537Satgutier@umich.eduint fdt_node_depth(const void *fdt, int nodeoffset)
4259537Satgutier@umich.edu{
4269537Satgutier@umich.edu        int nodedepth;
4279537Satgutier@umich.edu        int err;
4289537Satgutier@umich.edu
4299537Satgutier@umich.edu        err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth);
4309537Satgutier@umich.edu        if (err)
4319537Satgutier@umich.edu                return (err < 0) ? err : -FDT_ERR_INTERNAL;
4329537Satgutier@umich.edu        return nodedepth;
4339537Satgutier@umich.edu}
4349537Satgutier@umich.edu
4359537Satgutier@umich.eduint fdt_parent_offset(const void *fdt, int nodeoffset)
4369537Satgutier@umich.edu{
4379537Satgutier@umich.edu        int nodedepth = fdt_node_depth(fdt, nodeoffset);
4389537Satgutier@umich.edu
4399537Satgutier@umich.edu        if (nodedepth < 0)
4409537Satgutier@umich.edu                return nodedepth;
4419537Satgutier@umich.edu        return fdt_supernode_atdepth_offset(fdt, nodeoffset,
4429537Satgutier@umich.edu                                            nodedepth - 1, NULL);
4439537Satgutier@umich.edu}
4449537Satgutier@umich.edu
4459537Satgutier@umich.eduint fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
4469537Satgutier@umich.edu                                  const char *propname,
4479537Satgutier@umich.edu                                  const void *propval, int proplen)
4489537Satgutier@umich.edu{
4499537Satgutier@umich.edu        int offset;
4509537Satgutier@umich.edu        const void *val;
4519537Satgutier@umich.edu        int len;
4529537Satgutier@umich.edu
4539537Satgutier@umich.edu        FDT_CHECK_HEADER(fdt);
4549537Satgutier@umich.edu
4559537Satgutier@umich.edu        /* FIXME: The algorithm here is pretty horrible: we scan each
4569537Satgutier@umich.edu         * property of a node in fdt_getprop(), then if that didn't
4579537Satgutier@umich.edu         * find what we want, we scan over them again making our way
4589537Satgutier@umich.edu         * to the next node.  Still it's the easiest to implement
4599537Satgutier@umich.edu         * approach; performance can come later. */
4609537Satgutier@umich.edu        for (offset = fdt_next_node(fdt, startoffset, NULL);
4619537Satgutier@umich.edu             offset >= 0;
4629537Satgutier@umich.edu             offset = fdt_next_node(fdt, offset, NULL)) {
4639537Satgutier@umich.edu                val = fdt_getprop(fdt, offset, propname, &len);
4649537Satgutier@umich.edu                if (val && (len == proplen)
4659537Satgutier@umich.edu                    && (memcmp(val, propval, len) == 0))
4669537Satgutier@umich.edu                        return offset;
4679537Satgutier@umich.edu        }
4689537Satgutier@umich.edu
4699537Satgutier@umich.edu        return offset; /* error from fdt_next_node() */
4709537Satgutier@umich.edu}
4719537Satgutier@umich.edu
4729537Satgutier@umich.eduint fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle)
4739537Satgutier@umich.edu{
4749537Satgutier@umich.edu        int offset;
4759537Satgutier@umich.edu
4769537Satgutier@umich.edu        if ((phandle == 0) || (phandle == -1))
4779537Satgutier@umich.edu                return -FDT_ERR_BADPHANDLE;
4789537Satgutier@umich.edu
4799537Satgutier@umich.edu        FDT_CHECK_HEADER(fdt);
4809537Satgutier@umich.edu
4819537Satgutier@umich.edu        /* FIXME: The algorithm here is pretty horrible: we
4829537Satgutier@umich.edu         * potentially scan each property of a node in
4839537Satgutier@umich.edu         * fdt_get_phandle(), then if that didn't find what
4849537Satgutier@umich.edu         * we want, we scan over them again making our way to the next
4859537Satgutier@umich.edu         * node.  Still it's the easiest to implement approach;
4869537Satgutier@umich.edu         * performance can come later. */
4879537Satgutier@umich.edu        for (offset = fdt_next_node(fdt, -1, NULL);
4889537Satgutier@umich.edu             offset >= 0;
4899537Satgutier@umich.edu             offset = fdt_next_node(fdt, offset, NULL)) {
4909537Satgutier@umich.edu                if (fdt_get_phandle(fdt, offset) == phandle)
4919537Satgutier@umich.edu                        return offset;
4929537Satgutier@umich.edu        }
4939537Satgutier@umich.edu
4949537Satgutier@umich.edu        return offset; /* error from fdt_next_node() */
4959537Satgutier@umich.edu}
4969537Satgutier@umich.edu
4979537Satgutier@umich.edustatic int _fdt_stringlist_contains(const char *strlist, int listlen,
4989537Satgutier@umich.edu                                    const char *str)
4999537Satgutier@umich.edu{
5009537Satgutier@umich.edu        int len = strlen(str);
5019537Satgutier@umich.edu        const char *p;
5029537Satgutier@umich.edu
5039537Satgutier@umich.edu        while (listlen >= len) {
5049537Satgutier@umich.edu                if (memcmp(str, strlist, len+1) == 0)
5059537Satgutier@umich.edu                        return 1;
5069537Satgutier@umich.edu                p = memchr(strlist, '\0', listlen);
5079537Satgutier@umich.edu                if (!p)
5089537Satgutier@umich.edu                        return 0; /* malformed strlist.. */
5099537Satgutier@umich.edu                listlen -= (p-strlist) + 1;
5109537Satgutier@umich.edu                strlist = p + 1;
5119537Satgutier@umich.edu        }
5129537Satgutier@umich.edu        return 0;
5139537Satgutier@umich.edu}
5149537Satgutier@umich.edu
5159537Satgutier@umich.eduint fdt_node_check_compatible(const void *fdt, int nodeoffset,
5169537Satgutier@umich.edu                              const char *compatible)
5179537Satgutier@umich.edu{
5189537Satgutier@umich.edu        const void *prop;
5199537Satgutier@umich.edu        int len;
5209537Satgutier@umich.edu
5219537Satgutier@umich.edu        prop = fdt_getprop(fdt, nodeoffset, "compatible", &len);
5229537Satgutier@umich.edu        if (!prop)
5239537Satgutier@umich.edu                return len;
5249537Satgutier@umich.edu        if (_fdt_stringlist_contains(prop, len, compatible))
5259537Satgutier@umich.edu                return 0;
5269537Satgutier@umich.edu        else
5279537Satgutier@umich.edu                return 1;
5289537Satgutier@umich.edu}
5299537Satgutier@umich.edu
5309537Satgutier@umich.eduint fdt_node_offset_by_compatible(const void *fdt, int startoffset,
5319537Satgutier@umich.edu                                  const char *compatible)
5329537Satgutier@umich.edu{
5339537Satgutier@umich.edu        int offset, err;
5349537Satgutier@umich.edu
5359537Satgutier@umich.edu        FDT_CHECK_HEADER(fdt);
5369537Satgutier@umich.edu
5379537Satgutier@umich.edu        /* FIXME: The algorithm here is pretty horrible: we scan each
5389537Satgutier@umich.edu         * property of a node in fdt_node_check_compatible(), then if
5399537Satgutier@umich.edu         * that didn't find what we want, we scan over them again
5409537Satgutier@umich.edu         * making our way to the next node.  Still it's the easiest to
5419537Satgutier@umich.edu         * implement approach; performance can come later. */
5429537Satgutier@umich.edu        for (offset = fdt_next_node(fdt, startoffset, NULL);
5439537Satgutier@umich.edu             offset >= 0;
5449537Satgutier@umich.edu             offset = fdt_next_node(fdt, offset, NULL)) {
5459537Satgutier@umich.edu                err = fdt_node_check_compatible(fdt, offset, compatible);
5469537Satgutier@umich.edu                if ((err < 0) && (err != -FDT_ERR_NOTFOUND))
5479537Satgutier@umich.edu                        return err;
5489537Satgutier@umich.edu                else if (err == 0)
5499537Satgutier@umich.edu                        return offset;
5509537Satgutier@umich.edu        }
5519537Satgutier@umich.edu
5529537Satgutier@umich.edu        return offset; /* error from fdt_next_node() */
5539537Satgutier@umich.edu}
554