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