Annotation of elwix/tools/uboot_mkimage/lib/libfdt/fdt_ro.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * libfdt - Flat Device Tree manipulation
                      3:  * Copyright (C) 2006 David Gibson, IBM Corporation.
                      4:  *
                      5:  * libfdt is dual licensed: you can use it either under the terms of
                      6:  * the GPL, or the BSD license, at your option.
                      7:  *
                      8:  *  a) This library is free software; you can redistribute it and/or
                      9:  *     modify it under the terms of the GNU General Public License as
                     10:  *     published by the Free Software Foundation; either version 2 of the
                     11:  *     License, or (at your option) any later version.
                     12:  *
                     13:  *     This library is distributed in the hope that it will be useful,
                     14:  *     but WITHOUT ANY WARRANTY; without even the implied warranty of
                     15:  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                     16:  *     GNU General Public License for more details.
                     17:  *
                     18:  *     You should have received a copy of the GNU General Public
                     19:  *     License along with this library; if not, write to the Free
                     20:  *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
                     21:  *     MA 02110-1301 USA
                     22:  *
                     23:  * Alternatively,
                     24:  *
                     25:  *  b) Redistribution and use in source and binary forms, with or
                     26:  *     without modification, are permitted provided that the following
                     27:  *     conditions are met:
                     28:  *
                     29:  *     1. Redistributions of source code must retain the above
                     30:  *        copyright notice, this list of conditions and the following
                     31:  *        disclaimer.
                     32:  *     2. Redistributions in binary form must reproduce the above
                     33:  *        copyright notice, this list of conditions and the following
                     34:  *        disclaimer in the documentation and/or other materials
                     35:  *        provided with the distribution.
                     36:  *
                     37:  *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
                     38:  *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
                     39:  *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
                     40:  *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
                     41:  *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
                     42:  *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
                     43:  *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
                     44:  *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
                     45:  *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     46:  *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
                     47:  *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
                     48:  *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
                     49:  *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     50:  */
                     51: #include "libfdt_env.h"
                     52: 
                     53: #ifndef USE_HOSTCC
                     54: #include <fdt.h>
                     55: #include <libfdt.h>
                     56: #else
                     57: #include "fdt_host.h"
                     58: #endif
                     59: 
                     60: #include "libfdt_internal.h"
                     61: 
                     62: static int _fdt_nodename_eq(const void *fdt, int offset,
                     63:                            const char *s, int len)
                     64: {
                     65:        const char *p = fdt_offset_ptr(fdt, offset + FDT_TAGSIZE, len+1);
                     66: 
                     67:        if (! p)
                     68:                /* short match */
                     69:                return 0;
                     70: 
                     71:        if (memcmp(p, s, len) != 0)
                     72:                return 0;
                     73: 
                     74:        if (p[len] == '\0')
                     75:                return 1;
                     76:        else if (!memchr(s, '@', len) && (p[len] == '@'))
                     77:                return 1;
                     78:        else
                     79:                return 0;
                     80: }
                     81: 
                     82: const char *fdt_string(const void *fdt, int stroffset)
                     83: {
                     84:        return (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset;
                     85: }
                     86: 
                     87: static int _fdt_string_eq(const void *fdt, int stroffset,
                     88:                          const char *s, int len)
                     89: {
                     90:        const char *p = fdt_string(fdt, stroffset);
                     91: 
                     92:        return (strlen(p) == len) && (memcmp(p, s, len) == 0);
                     93: }
                     94: 
                     95: int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
                     96: {
                     97:        FDT_CHECK_HEADER(fdt);
                     98:        *address = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->address);
                     99:        *size = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->size);
                    100:        return 0;
                    101: }
                    102: 
                    103: int fdt_num_mem_rsv(const void *fdt)
                    104: {
                    105:        int i = 0;
                    106: 
                    107:        while (fdt64_to_cpu(_fdt_mem_rsv(fdt, i)->size) != 0)
                    108:                i++;
                    109:        return i;
                    110: }
                    111: 
                    112: int fdt_subnode_offset_namelen(const void *fdt, int offset,
                    113:                               const char *name, int namelen)
                    114: {
                    115:        int depth;
                    116: 
                    117:        FDT_CHECK_HEADER(fdt);
                    118: 
                    119:        for (depth = 0;
                    120:             (offset >= 0) && (depth >= 0);
                    121:             offset = fdt_next_node(fdt, offset, &depth))
                    122:                if ((depth == 1)
                    123:                    && _fdt_nodename_eq(fdt, offset, name, namelen))
                    124:                        return offset;
                    125: 
                    126:        if (depth < 0)
                    127:                return -FDT_ERR_NOTFOUND;
                    128:        return offset; /* error */
                    129: }
                    130: 
                    131: int fdt_subnode_offset(const void *fdt, int parentoffset,
                    132:                       const char *name)
                    133: {
                    134:        return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name));
                    135: }
                    136: 
                    137: int fdt_path_offset(const void *fdt, const char *path)
                    138: {
                    139:        const char *end = path + strlen(path);
                    140:        const char *p = path;
                    141:        int offset = 0;
                    142: 
                    143:        FDT_CHECK_HEADER(fdt);
                    144: 
                    145:        /* see if we have an alias */
                    146:        if (*path != '/') {
                    147:                const char *q = strchr(path, '/');
                    148: 
                    149:                if (!q)
                    150:                        q = end;
                    151: 
                    152:                p = fdt_get_alias_namelen(fdt, p, q - p);
                    153:                if (!p)
                    154:                        return -FDT_ERR_BADPATH;
                    155:                offset = fdt_path_offset(fdt, p);
                    156: 
                    157:                p = q;
                    158:        }
                    159: 
                    160:        while (*p) {
                    161:                const char *q;
                    162: 
                    163:                while (*p == '/')
                    164:                        p++;
                    165:                if (! *p)
                    166:                        return offset;
                    167:                q = strchr(p, '/');
                    168:                if (! q)
                    169:                        q = end;
                    170: 
                    171:                offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p);
                    172:                if (offset < 0)
                    173:                        return offset;
                    174: 
                    175:                p = q;
                    176:        }
                    177: 
                    178:        return offset;
                    179: }
                    180: 
                    181: const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
                    182: {
                    183:        const struct fdt_node_header *nh = _fdt_offset_ptr(fdt, nodeoffset);
                    184:        int err;
                    185: 
                    186:        if (((err = fdt_check_header(fdt)) != 0)
                    187:            || ((err = _fdt_check_node_offset(fdt, nodeoffset)) < 0))
                    188:                        goto fail;
                    189: 
                    190:        if (len)
                    191:                *len = strlen(nh->name);
                    192: 
                    193:        return nh->name;
                    194: 
                    195:  fail:
                    196:        if (len)
                    197:                *len = err;
                    198:        return NULL;
                    199: }
                    200: 
                    201: const struct fdt_property *fdt_get_property_namelen(const void *fdt,
                    202:                                                    int nodeoffset,
                    203:                                                    const char *name,
                    204:                                                    int namelen, int *lenp)
                    205: {
                    206:        uint32_t tag;
                    207:        const struct fdt_property *prop;
                    208:        int offset, nextoffset;
                    209:        int err;
                    210: 
                    211:        if (((err = fdt_check_header(fdt)) != 0)
                    212:            || ((err = _fdt_check_node_offset(fdt, nodeoffset)) < 0))
                    213:                        goto fail;
                    214: 
                    215:        nextoffset = err;
                    216:        do {
                    217:                offset = nextoffset;
                    218: 
                    219:                tag = fdt_next_tag(fdt, offset, &nextoffset);
                    220:                switch (tag) {
                    221:                case FDT_END:
                    222:                        if (nextoffset < 0)
                    223:                                err = nextoffset;
                    224:                        else
                    225:                                /* FDT_END tag with unclosed nodes */
                    226:                                err = -FDT_ERR_BADSTRUCTURE;
                    227:                        goto fail;
                    228: 
                    229:                case FDT_PROP:
                    230:                        prop = _fdt_offset_ptr(fdt, offset);
                    231:                        if (_fdt_string_eq(fdt, fdt32_to_cpu(prop->nameoff),
                    232:                                           name, namelen)) {
                    233:                                /* Found it! */
                    234:                                if (lenp)
                    235:                                        *lenp = fdt32_to_cpu(prop->len);
                    236: 
                    237:                                return prop;
                    238:                        }
                    239:                        break;
                    240:                }
                    241:        } while ((tag != FDT_BEGIN_NODE) && (tag != FDT_END_NODE));
                    242: 
                    243:        err = -FDT_ERR_NOTFOUND;
                    244:  fail:
                    245:        if (lenp)
                    246:                *lenp = err;
                    247:        return NULL;
                    248: }
                    249: 
                    250: const struct fdt_property *fdt_get_property(const void *fdt,
                    251:                                            int nodeoffset,
                    252:                                            const char *name, int *lenp)
                    253: {
                    254:        return fdt_get_property_namelen(fdt, nodeoffset, name,
                    255:                                        strlen(name), lenp);
                    256: }
                    257: 
                    258: const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
                    259:                                const char *name, int namelen, int *lenp)
                    260: {
                    261:        const struct fdt_property *prop;
                    262: 
                    263:        prop = fdt_get_property_namelen(fdt, nodeoffset, name, namelen, lenp);
                    264:        if (! prop)
                    265:                return NULL;
                    266: 
                    267:        return prop->data;
                    268: }
                    269: 
                    270: const void *fdt_getprop(const void *fdt, int nodeoffset,
                    271:                        const char *name, int *lenp)
                    272: {
                    273:        return fdt_getprop_namelen(fdt, nodeoffset, name, strlen(name), lenp);
                    274: }
                    275: 
                    276: uint32_t fdt_get_phandle(const void *fdt, int nodeoffset)
                    277: {
                    278:        const uint32_t *php;
                    279:        int len;
                    280: 
                    281:        php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len);
                    282:        if (!php || (len != sizeof(*php)))
                    283:                return 0;
                    284: 
                    285:        return fdt32_to_cpu(*php);
                    286: }
                    287: 
                    288: const char *fdt_get_alias_namelen(const void *fdt,
                    289:                                  const char *name, int namelen)
                    290: {
                    291:        int aliasoffset;
                    292: 
                    293:        aliasoffset = fdt_path_offset(fdt, "/aliases");
                    294:        if (aliasoffset < 0)
                    295:                return NULL;
                    296: 
                    297:        return fdt_getprop_namelen(fdt, aliasoffset, name, namelen, NULL);
                    298: }
                    299: 
                    300: const char *fdt_get_alias(const void *fdt, const char *name)
                    301: {
                    302:        return fdt_get_alias_namelen(fdt, name, strlen(name));
                    303: }
                    304: 
                    305: int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)
                    306: {
                    307:        int pdepth = 0, p = 0;
                    308:        int offset, depth, namelen;
                    309:        const char *name;
                    310: 
                    311:        FDT_CHECK_HEADER(fdt);
                    312: 
                    313:        if (buflen < 2)
                    314:                return -FDT_ERR_NOSPACE;
                    315: 
                    316:        for (offset = 0, depth = 0;
                    317:             (offset >= 0) && (offset <= nodeoffset);
                    318:             offset = fdt_next_node(fdt, offset, &depth)) {
                    319:                while (pdepth > depth) {
                    320:                        do {
                    321:                                p--;
                    322:                        } while (buf[p-1] != '/');
                    323:                        pdepth--;
                    324:                }
                    325: 
                    326:                if (pdepth >= depth) {
                    327:                        name = fdt_get_name(fdt, offset, &namelen);
                    328:                        if (!name)
                    329:                                return namelen;
                    330:                        if ((p + namelen + 1) <= buflen) {
                    331:                                memcpy(buf + p, name, namelen);
                    332:                                p += namelen;
                    333:                                buf[p++] = '/';
                    334:                                pdepth++;
                    335:                        }
                    336:                }
                    337: 
                    338:                if (offset == nodeoffset) {
                    339:                        if (pdepth < (depth + 1))
                    340:                                return -FDT_ERR_NOSPACE;
                    341: 
                    342:                        if (p > 1) /* special case so that root path is "/", not "" */
                    343:                                p--;
                    344:                        buf[p] = '\0';
                    345:                        return 0;
                    346:                }
                    347:        }
                    348: 
                    349:        if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
                    350:                return -FDT_ERR_BADOFFSET;
                    351:        else if (offset == -FDT_ERR_BADOFFSET)
                    352:                return -FDT_ERR_BADSTRUCTURE;
                    353: 
                    354:        return offset; /* error from fdt_next_node() */
                    355: }
                    356: 
                    357: int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
                    358:                                 int supernodedepth, int *nodedepth)
                    359: {
                    360:        int offset, depth;
                    361:        int supernodeoffset = -FDT_ERR_INTERNAL;
                    362: 
                    363:        FDT_CHECK_HEADER(fdt);
                    364: 
                    365:        if (supernodedepth < 0)
                    366:                return -FDT_ERR_NOTFOUND;
                    367: 
                    368:        for (offset = 0, depth = 0;
                    369:             (offset >= 0) && (offset <= nodeoffset);
                    370:             offset = fdt_next_node(fdt, offset, &depth)) {
                    371:                if (depth == supernodedepth)
                    372:                        supernodeoffset = offset;
                    373: 
                    374:                if (offset == nodeoffset) {
                    375:                        if (nodedepth)
                    376:                                *nodedepth = depth;
                    377: 
                    378:                        if (supernodedepth > depth)
                    379:                                return -FDT_ERR_NOTFOUND;
                    380:                        else
                    381:                                return supernodeoffset;
                    382:                }
                    383:        }
                    384: 
                    385:        if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
                    386:                return -FDT_ERR_BADOFFSET;
                    387:        else if (offset == -FDT_ERR_BADOFFSET)
                    388:                return -FDT_ERR_BADSTRUCTURE;
                    389: 
                    390:        return offset; /* error from fdt_next_node() */
                    391: }
                    392: 
                    393: int fdt_node_depth(const void *fdt, int nodeoffset)
                    394: {
                    395:        int nodedepth;
                    396:        int err;
                    397: 
                    398:        err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth);
                    399:        if (err)
                    400:                return (err < 0) ? err : -FDT_ERR_INTERNAL;
                    401:        return nodedepth;
                    402: }
                    403: 
                    404: int fdt_parent_offset(const void *fdt, int nodeoffset)
                    405: {
                    406:        int nodedepth = fdt_node_depth(fdt, nodeoffset);
                    407: 
                    408:        if (nodedepth < 0)
                    409:                return nodedepth;
                    410:        return fdt_supernode_atdepth_offset(fdt, nodeoffset,
                    411:                                            nodedepth - 1, NULL);
                    412: }
                    413: 
                    414: int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
                    415:                                  const char *propname,
                    416:                                  const void *propval, int proplen)
                    417: {
                    418:        int offset;
                    419:        const void *val;
                    420:        int len;
                    421: 
                    422:        FDT_CHECK_HEADER(fdt);
                    423: 
                    424:        /* FIXME: The algorithm here is pretty horrible: we scan each
                    425:         * property of a node in fdt_getprop(), then if that didn't
                    426:         * find what we want, we scan over them again making our way
                    427:         * to the next node.  Still it's the easiest to implement
                    428:         * approach; performance can come later. */
                    429:        for (offset = fdt_next_node(fdt, startoffset, NULL);
                    430:             offset >= 0;
                    431:             offset = fdt_next_node(fdt, offset, NULL)) {
                    432:                val = fdt_getprop(fdt, offset, propname, &len);
                    433:                if (val && (len == proplen)
                    434:                    && (memcmp(val, propval, len) == 0))
                    435:                        return offset;
                    436:        }
                    437: 
                    438:        return offset; /* error from fdt_next_node() */
                    439: }
                    440: 
                    441: int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle)
                    442: {
                    443:        if ((phandle == 0) || (phandle == -1))
                    444:                return -FDT_ERR_BADPHANDLE;
                    445:        phandle = cpu_to_fdt32(phandle);
                    446:        return fdt_node_offset_by_prop_value(fdt, -1, "linux,phandle",
                    447:                                             &phandle, sizeof(phandle));
                    448: }
                    449: 
                    450: static int _fdt_stringlist_contains(const char *strlist, int listlen,
                    451:                                    const char *str)
                    452: {
                    453:        int len = strlen(str);
                    454:        const char *p;
                    455: 
                    456:        while (listlen >= len) {
                    457:                if (memcmp(str, strlist, len+1) == 0)
                    458:                        return 1;
                    459:                p = memchr(strlist, '\0', listlen);
                    460:                if (!p)
                    461:                        return 0; /* malformed strlist.. */
                    462:                listlen -= (p-strlist) + 1;
                    463:                strlist = p + 1;
                    464:        }
                    465:        return 0;
                    466: }
                    467: 
                    468: int fdt_node_check_compatible(const void *fdt, int nodeoffset,
                    469:                              const char *compatible)
                    470: {
                    471:        const void *prop;
                    472:        int len;
                    473: 
                    474:        prop = fdt_getprop(fdt, nodeoffset, "compatible", &len);
                    475:        if (!prop)
                    476:                return len;
                    477:        if (_fdt_stringlist_contains(prop, len, compatible))
                    478:                return 0;
                    479:        else
                    480:                return 1;
                    481: }
                    482: 
                    483: int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
                    484:                                  const char *compatible)
                    485: {
                    486:        int offset, err;
                    487: 
                    488:        FDT_CHECK_HEADER(fdt);
                    489: 
                    490:        /* FIXME: The algorithm here is pretty horrible: we scan each
                    491:         * property of a node in fdt_node_check_compatible(), then if
                    492:         * that didn't find what we want, we scan over them again
                    493:         * making our way to the next node.  Still it's the easiest to
                    494:         * implement approach; performance can come later. */
                    495:        for (offset = fdt_next_node(fdt, startoffset, NULL);
                    496:             offset >= 0;
                    497:             offset = fdt_next_node(fdt, offset, NULL)) {
                    498:                err = fdt_node_check_compatible(fdt, offset, compatible);
                    499:                if ((err < 0) && (err != -FDT_ERR_NOTFOUND))
                    500:                        return err;
                    501:                else if (err == 0)
                    502:                        return offset;
                    503:        }
                    504: 
                    505:        return offset; /* error from fdt_next_node() */
                    506: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>