fdt_ro.c revision 261215
1204431Sraj/* 2204431Sraj * libfdt - Flat Device Tree manipulation 3204431Sraj * Copyright (C) 2006 David Gibson, IBM Corporation. 4204431Sraj * 5204431Sraj * libfdt is dual licensed: you can use it either under the terms of 6204431Sraj * the GPL, or the BSD license, at your option. 7204431Sraj * 8204431Sraj * a) This library is free software; you can redistribute it and/or 9204431Sraj * modify it under the terms of the GNU General Public License as 10204431Sraj * published by the Free Software Foundation; either version 2 of the 11204431Sraj * License, or (at your option) any later version. 12204431Sraj * 13204431Sraj * This library is distributed in the hope that it will be useful, 14204431Sraj * but WITHOUT ANY WARRANTY; without even the implied warranty of 15204431Sraj * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16204431Sraj * GNU General Public License for more details. 17204431Sraj * 18204431Sraj * You should have received a copy of the GNU General Public 19204431Sraj * License along with this library; if not, write to the Free 20204431Sraj * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, 21204431Sraj * MA 02110-1301 USA 22204431Sraj * 23204431Sraj * Alternatively, 24204431Sraj * 25204431Sraj * b) Redistribution and use in source and binary forms, with or 26204431Sraj * without modification, are permitted provided that the following 27204431Sraj * conditions are met: 28204431Sraj * 29204431Sraj * 1. Redistributions of source code must retain the above 30204431Sraj * copyright notice, this list of conditions and the following 31204431Sraj * disclaimer. 32204431Sraj * 2. Redistributions in binary form must reproduce the above 33204431Sraj * copyright notice, this list of conditions and the following 34204431Sraj * disclaimer in the documentation and/or other materials 35204431Sraj * provided with the distribution. 36204431Sraj * 37204431Sraj * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 38204431Sraj * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 39204431Sraj * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 40204431Sraj * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 41204431Sraj * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 42204431Sraj * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 43204431Sraj * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 44204431Sraj * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 45204431Sraj * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 46204431Sraj * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 47204431Sraj * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 48204431Sraj * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 49204431Sraj * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 50204431Sraj */ 51204431Sraj#include "libfdt_env.h" 52204431Sraj 53204431Sraj#include <fdt.h> 54204431Sraj#include <libfdt.h> 55204431Sraj 56204431Sraj#include "libfdt_internal.h" 57204431Sraj 58204431Srajstatic int _fdt_nodename_eq(const void *fdt, int offset, 59204431Sraj const char *s, int len) 60204431Sraj{ 61204431Sraj const char *p = fdt_offset_ptr(fdt, offset + FDT_TAGSIZE, len+1); 62204431Sraj 63204431Sraj if (! p) 64204431Sraj /* short match */ 65204431Sraj return 0; 66204431Sraj 67204431Sraj if (memcmp(p, s, len) != 0) 68204431Sraj return 0; 69204431Sraj 70204431Sraj if (p[len] == '\0') 71204431Sraj return 1; 72204431Sraj else if (!memchr(s, '@', len) && (p[len] == '@')) 73204431Sraj return 1; 74204431Sraj else 75204431Sraj return 0; 76204431Sraj} 77204431Sraj 78204431Srajconst char *fdt_string(const void *fdt, int stroffset) 79204431Sraj{ 80204431Sraj return (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset; 81204431Sraj} 82204431Sraj 83204433Srajstatic int _fdt_string_eq(const void *fdt, int stroffset, 84204433Sraj const char *s, int len) 85204433Sraj{ 86204433Sraj const char *p = fdt_string(fdt, stroffset); 87204433Sraj 88204433Sraj return (strlen(p) == len) && (memcmp(p, s, len) == 0); 89204433Sraj} 90204433Sraj 91204431Srajint fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size) 92204431Sraj{ 93204431Sraj FDT_CHECK_HEADER(fdt); 94204431Sraj *address = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->address); 95204431Sraj *size = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->size); 96204431Sraj return 0; 97204431Sraj} 98204431Sraj 99204431Srajint fdt_num_mem_rsv(const void *fdt) 100204431Sraj{ 101204431Sraj int i = 0; 102204431Sraj 103204431Sraj while (fdt64_to_cpu(_fdt_mem_rsv(fdt, i)->size) != 0) 104204431Sraj i++; 105204431Sraj return i; 106204431Sraj} 107204431Sraj 108238742Simpstatic int _nextprop(const void *fdt, int offset) 109238742Simp{ 110238742Simp uint32_t tag; 111238742Simp int nextoffset; 112238742Simp 113238742Simp do { 114238742Simp tag = fdt_next_tag(fdt, offset, &nextoffset); 115238742Simp 116238742Simp switch (tag) { 117238742Simp case FDT_END: 118238742Simp if (nextoffset >= 0) 119238742Simp return -FDT_ERR_BADSTRUCTURE; 120238742Simp else 121238742Simp return nextoffset; 122238742Simp 123238742Simp case FDT_PROP: 124238742Simp return offset; 125238742Simp } 126238742Simp offset = nextoffset; 127238742Simp } while (tag == FDT_NOP); 128238742Simp 129238742Simp return -FDT_ERR_NOTFOUND; 130238742Simp} 131238742Simp 132204431Srajint fdt_subnode_offset_namelen(const void *fdt, int offset, 133204431Sraj const char *name, int namelen) 134204431Sraj{ 135204431Sraj int depth; 136204431Sraj 137204431Sraj FDT_CHECK_HEADER(fdt); 138204431Sraj 139204431Sraj for (depth = 0; 140204433Sraj (offset >= 0) && (depth >= 0); 141204433Sraj offset = fdt_next_node(fdt, offset, &depth)) 142204433Sraj if ((depth == 1) 143204433Sraj && _fdt_nodename_eq(fdt, offset, name, namelen)) 144204431Sraj return offset; 145204431Sraj 146204433Sraj if (depth < 0) 147204433Sraj return -FDT_ERR_NOTFOUND; 148204431Sraj return offset; /* error */ 149204431Sraj} 150204431Sraj 151204431Srajint fdt_subnode_offset(const void *fdt, int parentoffset, 152204431Sraj const char *name) 153204431Sraj{ 154204431Sraj return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name)); 155204431Sraj} 156204431Sraj 157204431Srajint fdt_path_offset(const void *fdt, const char *path) 158204431Sraj{ 159204431Sraj const char *end = path + strlen(path); 160204431Sraj const char *p = path; 161204431Sraj int offset = 0; 162204431Sraj 163204431Sraj FDT_CHECK_HEADER(fdt); 164204431Sraj 165204433Sraj /* see if we have an alias */ 166204433Sraj if (*path != '/') { 167204433Sraj const char *q = strchr(path, '/'); 168204431Sraj 169204433Sraj if (!q) 170204433Sraj q = end; 171204433Sraj 172204433Sraj p = fdt_get_alias_namelen(fdt, p, q - p); 173204433Sraj if (!p) 174204433Sraj return -FDT_ERR_BADPATH; 175204433Sraj offset = fdt_path_offset(fdt, p); 176204433Sraj 177204433Sraj p = q; 178204433Sraj } 179204433Sraj 180204431Sraj while (*p) { 181204431Sraj const char *q; 182204431Sraj 183204431Sraj while (*p == '/') 184204431Sraj p++; 185204431Sraj if (! *p) 186204431Sraj return offset; 187204431Sraj q = strchr(p, '/'); 188204431Sraj if (! q) 189204431Sraj q = end; 190204431Sraj 191204431Sraj offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p); 192204431Sraj if (offset < 0) 193204431Sraj return offset; 194204431Sraj 195204431Sraj p = q; 196204431Sraj } 197204431Sraj 198204431Sraj return offset; 199204431Sraj} 200204431Sraj 201204431Srajconst char *fdt_get_name(const void *fdt, int nodeoffset, int *len) 202204431Sraj{ 203204431Sraj const struct fdt_node_header *nh = _fdt_offset_ptr(fdt, nodeoffset); 204204431Sraj int err; 205204431Sraj 206204431Sraj if (((err = fdt_check_header(fdt)) != 0) 207204431Sraj || ((err = _fdt_check_node_offset(fdt, nodeoffset)) < 0)) 208204431Sraj goto fail; 209204431Sraj 210204431Sraj if (len) 211204431Sraj *len = strlen(nh->name); 212204431Sraj 213204431Sraj return nh->name; 214204431Sraj 215204431Sraj fail: 216204431Sraj if (len) 217204431Sraj *len = err; 218204431Sraj return NULL; 219204431Sraj} 220204431Sraj 221238742Simpint fdt_first_property_offset(const void *fdt, int nodeoffset) 222204431Sraj{ 223238742Simp int offset; 224238742Simp 225238742Simp if ((offset = _fdt_check_node_offset(fdt, nodeoffset)) < 0) 226238742Simp return offset; 227238742Simp 228238742Simp return _nextprop(fdt, offset); 229238742Simp} 230238742Simp 231238742Simpint fdt_next_property_offset(const void *fdt, int offset) 232238742Simp{ 233238742Simp if ((offset = _fdt_check_prop_offset(fdt, offset)) < 0) 234238742Simp return offset; 235238742Simp 236238742Simp return _nextprop(fdt, offset); 237238742Simp} 238238742Simp 239238742Simpconst struct fdt_property *fdt_get_property_by_offset(const void *fdt, 240238742Simp int offset, 241238742Simp int *lenp) 242238742Simp{ 243238742Simp int err; 244204431Sraj const struct fdt_property *prop; 245204431Sraj 246238742Simp if ((err = _fdt_check_prop_offset(fdt, offset)) < 0) { 247238742Simp if (lenp) 248238742Simp *lenp = err; 249238742Simp return NULL; 250238742Simp } 251204431Sraj 252238742Simp prop = _fdt_offset_ptr(fdt, offset); 253204431Sraj 254238742Simp if (lenp) 255238742Simp *lenp = fdt32_to_cpu(prop->len); 256204431Sraj 257238742Simp return prop; 258238742Simp} 259204431Sraj 260238742Simpconst struct fdt_property *fdt_get_property_namelen(const void *fdt, 261238742Simp int offset, 262238742Simp const char *name, 263238742Simp int namelen, int *lenp) 264238742Simp{ 265238742Simp for (offset = fdt_first_property_offset(fdt, offset); 266238742Simp (offset >= 0); 267238742Simp (offset = fdt_next_property_offset(fdt, offset))) { 268238742Simp const struct fdt_property *prop; 269238742Simp 270238742Simp if (!(prop = fdt_get_property_by_offset(fdt, offset, lenp))) { 271238742Simp offset = -FDT_ERR_INTERNAL; 272204431Sraj break; 273204431Sraj } 274238742Simp if (_fdt_string_eq(fdt, fdt32_to_cpu(prop->nameoff), 275238742Simp name, namelen)) 276238742Simp return prop; 277238742Simp } 278204431Sraj 279204431Sraj if (lenp) 280238742Simp *lenp = offset; 281204431Sraj return NULL; 282204431Sraj} 283204431Sraj 284204433Srajconst struct fdt_property *fdt_get_property(const void *fdt, 285204433Sraj int nodeoffset, 286204433Sraj const char *name, int *lenp) 287204431Sraj{ 288204433Sraj return fdt_get_property_namelen(fdt, nodeoffset, name, 289204433Sraj strlen(name), lenp); 290204433Sraj} 291204433Sraj 292204433Srajconst void *fdt_getprop_namelen(const void *fdt, int nodeoffset, 293204433Sraj const char *name, int namelen, int *lenp) 294204433Sraj{ 295204431Sraj const struct fdt_property *prop; 296204431Sraj 297204433Sraj prop = fdt_get_property_namelen(fdt, nodeoffset, name, namelen, lenp); 298204431Sraj if (! prop) 299204431Sraj return NULL; 300204431Sraj 301204431Sraj return prop->data; 302204431Sraj} 303204431Sraj 304238742Simpconst void *fdt_getprop_by_offset(const void *fdt, int offset, 305238742Simp const char **namep, int *lenp) 306238742Simp{ 307238742Simp const struct fdt_property *prop; 308238742Simp 309238742Simp prop = fdt_get_property_by_offset(fdt, offset, lenp); 310238742Simp if (!prop) 311238742Simp return NULL; 312238742Simp if (namep) 313238742Simp *namep = fdt_string(fdt, fdt32_to_cpu(prop->nameoff)); 314238742Simp return prop->data; 315238742Simp} 316238742Simp 317204433Srajconst void *fdt_getprop(const void *fdt, int nodeoffset, 318204433Sraj const char *name, int *lenp) 319204433Sraj{ 320204433Sraj return fdt_getprop_namelen(fdt, nodeoffset, name, strlen(name), lenp); 321204433Sraj} 322204433Sraj 323204431Srajuint32_t fdt_get_phandle(const void *fdt, int nodeoffset) 324204431Sraj{ 325261215Simp const fdt32_t *php; 326204431Sraj int len; 327204431Sraj 328204433Sraj /* FIXME: This is a bit sub-optimal, since we potentially scan 329204433Sraj * over all the properties twice. */ 330204433Sraj php = fdt_getprop(fdt, nodeoffset, "phandle", &len); 331204433Sraj if (!php || (len != sizeof(*php))) { 332204433Sraj php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len); 333204433Sraj if (!php || (len != sizeof(*php))) 334204433Sraj return 0; 335204433Sraj } 336204431Sraj 337204431Sraj return fdt32_to_cpu(*php); 338204431Sraj} 339204431Sraj 340204433Srajconst char *fdt_get_alias_namelen(const void *fdt, 341204433Sraj const char *name, int namelen) 342204433Sraj{ 343204433Sraj int aliasoffset; 344204433Sraj 345204433Sraj aliasoffset = fdt_path_offset(fdt, "/aliases"); 346204433Sraj if (aliasoffset < 0) 347204433Sraj return NULL; 348204433Sraj 349204433Sraj return fdt_getprop_namelen(fdt, aliasoffset, name, namelen, NULL); 350204433Sraj} 351204433Sraj 352204433Srajconst char *fdt_get_alias(const void *fdt, const char *name) 353204433Sraj{ 354204433Sraj return fdt_get_alias_namelen(fdt, name, strlen(name)); 355204433Sraj} 356204433Sraj 357204431Srajint fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen) 358204431Sraj{ 359204431Sraj int pdepth = 0, p = 0; 360204431Sraj int offset, depth, namelen; 361204431Sraj const char *name; 362204431Sraj 363204431Sraj FDT_CHECK_HEADER(fdt); 364204431Sraj 365204431Sraj if (buflen < 2) 366204431Sraj return -FDT_ERR_NOSPACE; 367204431Sraj 368204431Sraj for (offset = 0, depth = 0; 369204431Sraj (offset >= 0) && (offset <= nodeoffset); 370204431Sraj offset = fdt_next_node(fdt, offset, &depth)) { 371204431Sraj while (pdepth > depth) { 372204431Sraj do { 373204431Sraj p--; 374204431Sraj } while (buf[p-1] != '/'); 375204431Sraj pdepth--; 376204431Sraj } 377204431Sraj 378204433Sraj if (pdepth >= depth) { 379204433Sraj name = fdt_get_name(fdt, offset, &namelen); 380204433Sraj if (!name) 381204433Sraj return namelen; 382204433Sraj if ((p + namelen + 1) <= buflen) { 383204433Sraj memcpy(buf + p, name, namelen); 384204433Sraj p += namelen; 385204433Sraj buf[p++] = '/'; 386204433Sraj pdepth++; 387204433Sraj } 388204431Sraj } 389204431Sraj 390204431Sraj if (offset == nodeoffset) { 391204431Sraj if (pdepth < (depth + 1)) 392204431Sraj return -FDT_ERR_NOSPACE; 393204431Sraj 394204431Sraj if (p > 1) /* special case so that root path is "/", not "" */ 395204431Sraj p--; 396204431Sraj buf[p] = '\0'; 397204433Sraj return 0; 398204431Sraj } 399204431Sraj } 400204431Sraj 401204431Sraj if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0)) 402204431Sraj return -FDT_ERR_BADOFFSET; 403204431Sraj else if (offset == -FDT_ERR_BADOFFSET) 404204431Sraj return -FDT_ERR_BADSTRUCTURE; 405204431Sraj 406204431Sraj return offset; /* error from fdt_next_node() */ 407204431Sraj} 408204431Sraj 409204431Srajint fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset, 410204431Sraj int supernodedepth, int *nodedepth) 411204431Sraj{ 412204431Sraj int offset, depth; 413204431Sraj int supernodeoffset = -FDT_ERR_INTERNAL; 414204431Sraj 415204431Sraj FDT_CHECK_HEADER(fdt); 416204431Sraj 417204431Sraj if (supernodedepth < 0) 418204431Sraj return -FDT_ERR_NOTFOUND; 419204431Sraj 420204431Sraj for (offset = 0, depth = 0; 421204431Sraj (offset >= 0) && (offset <= nodeoffset); 422204431Sraj offset = fdt_next_node(fdt, offset, &depth)) { 423204431Sraj if (depth == supernodedepth) 424204431Sraj supernodeoffset = offset; 425204431Sraj 426204431Sraj if (offset == nodeoffset) { 427204431Sraj if (nodedepth) 428204431Sraj *nodedepth = depth; 429204431Sraj 430204431Sraj if (supernodedepth > depth) 431204431Sraj return -FDT_ERR_NOTFOUND; 432204431Sraj else 433204431Sraj return supernodeoffset; 434204431Sraj } 435204431Sraj } 436204431Sraj 437204431Sraj if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0)) 438204431Sraj return -FDT_ERR_BADOFFSET; 439204431Sraj else if (offset == -FDT_ERR_BADOFFSET) 440204431Sraj return -FDT_ERR_BADSTRUCTURE; 441204431Sraj 442204431Sraj return offset; /* error from fdt_next_node() */ 443204431Sraj} 444204431Sraj 445204431Srajint fdt_node_depth(const void *fdt, int nodeoffset) 446204431Sraj{ 447204431Sraj int nodedepth; 448204431Sraj int err; 449204431Sraj 450204431Sraj err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth); 451204431Sraj if (err) 452204431Sraj return (err < 0) ? err : -FDT_ERR_INTERNAL; 453204431Sraj return nodedepth; 454204431Sraj} 455204431Sraj 456204431Srajint fdt_parent_offset(const void *fdt, int nodeoffset) 457204431Sraj{ 458204431Sraj int nodedepth = fdt_node_depth(fdt, nodeoffset); 459204431Sraj 460204431Sraj if (nodedepth < 0) 461204431Sraj return nodedepth; 462204431Sraj return fdt_supernode_atdepth_offset(fdt, nodeoffset, 463204431Sraj nodedepth - 1, NULL); 464204431Sraj} 465204431Sraj 466204431Srajint fdt_node_offset_by_prop_value(const void *fdt, int startoffset, 467204431Sraj const char *propname, 468204431Sraj const void *propval, int proplen) 469204431Sraj{ 470204431Sraj int offset; 471204431Sraj const void *val; 472204431Sraj int len; 473204431Sraj 474204431Sraj FDT_CHECK_HEADER(fdt); 475204431Sraj 476204431Sraj /* FIXME: The algorithm here is pretty horrible: we scan each 477204431Sraj * property of a node in fdt_getprop(), then if that didn't 478204431Sraj * find what we want, we scan over them again making our way 479204431Sraj * to the next node. Still it's the easiest to implement 480204431Sraj * approach; performance can come later. */ 481204431Sraj for (offset = fdt_next_node(fdt, startoffset, NULL); 482204431Sraj offset >= 0; 483204431Sraj offset = fdt_next_node(fdt, offset, NULL)) { 484204431Sraj val = fdt_getprop(fdt, offset, propname, &len); 485204431Sraj if (val && (len == proplen) 486204431Sraj && (memcmp(val, propval, len) == 0)) 487204431Sraj return offset; 488204431Sraj } 489204431Sraj 490204431Sraj return offset; /* error from fdt_next_node() */ 491204431Sraj} 492204431Sraj 493204431Srajint fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle) 494204431Sraj{ 495204433Sraj int offset; 496204433Sraj 497204431Sraj if ((phandle == 0) || (phandle == -1)) 498204431Sraj return -FDT_ERR_BADPHANDLE; 499204433Sraj 500204433Sraj FDT_CHECK_HEADER(fdt); 501204433Sraj 502204433Sraj /* FIXME: The algorithm here is pretty horrible: we 503204433Sraj * potentially scan each property of a node in 504204433Sraj * fdt_get_phandle(), then if that didn't find what 505204433Sraj * we want, we scan over them again making our way to the next 506204433Sraj * node. Still it's the easiest to implement approach; 507204433Sraj * performance can come later. */ 508204433Sraj for (offset = fdt_next_node(fdt, -1, NULL); 509204433Sraj offset >= 0; 510204433Sraj offset = fdt_next_node(fdt, offset, NULL)) { 511204433Sraj if (fdt_get_phandle(fdt, offset) == phandle) 512204433Sraj return offset; 513204433Sraj } 514204433Sraj 515204433Sraj return offset; /* error from fdt_next_node() */ 516204431Sraj} 517204431Sraj 518261215Simpint fdt_stringlist_contains(const char *strlist, int listlen, const char *str) 519204431Sraj{ 520204431Sraj int len = strlen(str); 521204431Sraj const char *p; 522204431Sraj 523204431Sraj while (listlen >= len) { 524204431Sraj if (memcmp(str, strlist, len+1) == 0) 525204431Sraj return 1; 526204431Sraj p = memchr(strlist, '\0', listlen); 527204431Sraj if (!p) 528204431Sraj return 0; /* malformed strlist.. */ 529204431Sraj listlen -= (p-strlist) + 1; 530204431Sraj strlist = p + 1; 531204431Sraj } 532204431Sraj return 0; 533204431Sraj} 534204431Sraj 535204431Srajint fdt_node_check_compatible(const void *fdt, int nodeoffset, 536204431Sraj const char *compatible) 537204431Sraj{ 538204431Sraj const void *prop; 539204431Sraj int len; 540204431Sraj 541204431Sraj prop = fdt_getprop(fdt, nodeoffset, "compatible", &len); 542204431Sraj if (!prop) 543204431Sraj return len; 544261215Simp if (fdt_stringlist_contains(prop, len, compatible)) 545204431Sraj return 0; 546204431Sraj else 547204431Sraj return 1; 548204431Sraj} 549204431Sraj 550204431Srajint fdt_node_offset_by_compatible(const void *fdt, int startoffset, 551204431Sraj const char *compatible) 552204431Sraj{ 553204431Sraj int offset, err; 554204431Sraj 555204431Sraj FDT_CHECK_HEADER(fdt); 556204431Sraj 557204431Sraj /* FIXME: The algorithm here is pretty horrible: we scan each 558204431Sraj * property of a node in fdt_node_check_compatible(), then if 559204431Sraj * that didn't find what we want, we scan over them again 560204431Sraj * making our way to the next node. Still it's the easiest to 561204431Sraj * implement approach; performance can come later. */ 562204431Sraj for (offset = fdt_next_node(fdt, startoffset, NULL); 563204431Sraj offset >= 0; 564204431Sraj offset = fdt_next_node(fdt, offset, NULL)) { 565204431Sraj err = fdt_node_check_compatible(fdt, offset, compatible); 566204431Sraj if ((err < 0) && (err != -FDT_ERR_NOTFOUND)) 567204431Sraj return err; 568204431Sraj else if (err == 0) 569204431Sraj return offset; 570204431Sraj } 571204431Sraj 572204431Sraj return offset; /* error from fdt_next_node() */ 573204431Sraj} 574