Annotation of elwix/tools/uboot_mkimage/lib/libfdt/fdt_ro.c, revision 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>