0001
0002
0003
0004
0005
0006 #include "libfdt_env.h"
0007
0008 #include <fdt.h>
0009 #include <libfdt.h>
0010
0011 #include "libfdt_internal.h"
0012
0013 static int fdt_nodename_eq_(const void *fdt, int offset,
0014 const char *s, int len)
0015 {
0016 int olen;
0017 const char *p = fdt_get_name(fdt, offset, &olen);
0018
0019 if (!p || olen < len)
0020
0021 return 0;
0022
0023 if (memcmp(p, s, len) != 0)
0024 return 0;
0025
0026 if (p[len] == '\0')
0027 return 1;
0028 else if (!memchr(s, '@', len) && (p[len] == '@'))
0029 return 1;
0030 else
0031 return 0;
0032 }
0033
0034 const char *fdt_get_string(const void *fdt, int stroffset, int *lenp)
0035 {
0036 int32_t totalsize;
0037 uint32_t absoffset;
0038 size_t len;
0039 int err;
0040 const char *s, *n;
0041
0042 if (can_assume(VALID_INPUT)) {
0043 s = (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset;
0044
0045 if (lenp)
0046 *lenp = strlen(s);
0047 return s;
0048 }
0049 totalsize = fdt_ro_probe_(fdt);
0050 err = totalsize;
0051 if (totalsize < 0)
0052 goto fail;
0053
0054 err = -FDT_ERR_BADOFFSET;
0055 absoffset = stroffset + fdt_off_dt_strings(fdt);
0056 if (absoffset >= (unsigned)totalsize)
0057 goto fail;
0058 len = totalsize - absoffset;
0059
0060 if (fdt_magic(fdt) == FDT_MAGIC) {
0061 if (stroffset < 0)
0062 goto fail;
0063 if (can_assume(LATEST) || fdt_version(fdt) >= 17) {
0064 if ((unsigned)stroffset >= fdt_size_dt_strings(fdt))
0065 goto fail;
0066 if ((fdt_size_dt_strings(fdt) - stroffset) < len)
0067 len = fdt_size_dt_strings(fdt) - stroffset;
0068 }
0069 } else if (fdt_magic(fdt) == FDT_SW_MAGIC) {
0070 unsigned int sw_stroffset = -stroffset;
0071
0072 if ((stroffset >= 0) ||
0073 (sw_stroffset > fdt_size_dt_strings(fdt)))
0074 goto fail;
0075 if (sw_stroffset < len)
0076 len = sw_stroffset;
0077 } else {
0078 err = -FDT_ERR_INTERNAL;
0079 goto fail;
0080 }
0081
0082 s = (const char *)fdt + absoffset;
0083 n = memchr(s, '\0', len);
0084 if (!n) {
0085
0086 err = -FDT_ERR_TRUNCATED;
0087 goto fail;
0088 }
0089
0090 if (lenp)
0091 *lenp = n - s;
0092 return s;
0093
0094 fail:
0095 if (lenp)
0096 *lenp = err;
0097 return NULL;
0098 }
0099
0100 const char *fdt_string(const void *fdt, int stroffset)
0101 {
0102 return fdt_get_string(fdt, stroffset, NULL);
0103 }
0104
0105 static int fdt_string_eq_(const void *fdt, int stroffset,
0106 const char *s, int len)
0107 {
0108 int slen;
0109 const char *p = fdt_get_string(fdt, stroffset, &slen);
0110
0111 return p && (slen == len) && (memcmp(p, s, len) == 0);
0112 }
0113
0114 int fdt_find_max_phandle(const void *fdt, uint32_t *phandle)
0115 {
0116 uint32_t max = 0;
0117 int offset = -1;
0118
0119 while (true) {
0120 uint32_t value;
0121
0122 offset = fdt_next_node(fdt, offset, NULL);
0123 if (offset < 0) {
0124 if (offset == -FDT_ERR_NOTFOUND)
0125 break;
0126
0127 return offset;
0128 }
0129
0130 value = fdt_get_phandle(fdt, offset);
0131
0132 if (value > max)
0133 max = value;
0134 }
0135
0136 if (phandle)
0137 *phandle = max;
0138
0139 return 0;
0140 }
0141
0142 int fdt_generate_phandle(const void *fdt, uint32_t *phandle)
0143 {
0144 uint32_t max;
0145 int err;
0146
0147 err = fdt_find_max_phandle(fdt, &max);
0148 if (err < 0)
0149 return err;
0150
0151 if (max == FDT_MAX_PHANDLE)
0152 return -FDT_ERR_NOPHANDLES;
0153
0154 if (phandle)
0155 *phandle = max + 1;
0156
0157 return 0;
0158 }
0159
0160 static const struct fdt_reserve_entry *fdt_mem_rsv(const void *fdt, int n)
0161 {
0162 unsigned int offset = n * sizeof(struct fdt_reserve_entry);
0163 unsigned int absoffset = fdt_off_mem_rsvmap(fdt) + offset;
0164
0165 if (!can_assume(VALID_INPUT)) {
0166 if (absoffset < fdt_off_mem_rsvmap(fdt))
0167 return NULL;
0168 if (absoffset > fdt_totalsize(fdt) -
0169 sizeof(struct fdt_reserve_entry))
0170 return NULL;
0171 }
0172 return fdt_mem_rsv_(fdt, n);
0173 }
0174
0175 int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
0176 {
0177 const struct fdt_reserve_entry *re;
0178
0179 FDT_RO_PROBE(fdt);
0180 re = fdt_mem_rsv(fdt, n);
0181 if (!can_assume(VALID_INPUT) && !re)
0182 return -FDT_ERR_BADOFFSET;
0183
0184 *address = fdt64_ld_(&re->address);
0185 *size = fdt64_ld_(&re->size);
0186 return 0;
0187 }
0188
0189 int fdt_num_mem_rsv(const void *fdt)
0190 {
0191 int i;
0192 const struct fdt_reserve_entry *re;
0193
0194 for (i = 0; (re = fdt_mem_rsv(fdt, i)) != NULL; i++) {
0195 if (fdt64_ld_(&re->size) == 0)
0196 return i;
0197 }
0198 return -FDT_ERR_TRUNCATED;
0199 }
0200
0201 static int nextprop_(const void *fdt, int offset)
0202 {
0203 uint32_t tag;
0204 int nextoffset;
0205
0206 do {
0207 tag = fdt_next_tag(fdt, offset, &nextoffset);
0208
0209 switch (tag) {
0210 case FDT_END:
0211 if (nextoffset >= 0)
0212 return -FDT_ERR_BADSTRUCTURE;
0213 else
0214 return nextoffset;
0215
0216 case FDT_PROP:
0217 return offset;
0218 }
0219 offset = nextoffset;
0220 } while (tag == FDT_NOP);
0221
0222 return -FDT_ERR_NOTFOUND;
0223 }
0224
0225 int fdt_subnode_offset_namelen(const void *fdt, int offset,
0226 const char *name, int namelen)
0227 {
0228 int depth;
0229
0230 FDT_RO_PROBE(fdt);
0231
0232 for (depth = 0;
0233 (offset >= 0) && (depth >= 0);
0234 offset = fdt_next_node(fdt, offset, &depth))
0235 if ((depth == 1)
0236 && fdt_nodename_eq_(fdt, offset, name, namelen))
0237 return offset;
0238
0239 if (depth < 0)
0240 return -FDT_ERR_NOTFOUND;
0241 return offset;
0242 }
0243
0244 int fdt_subnode_offset(const void *fdt, int parentoffset,
0245 const char *name)
0246 {
0247 return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name));
0248 }
0249
0250 int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen)
0251 {
0252 const char *end = path + namelen;
0253 const char *p = path;
0254 int offset = 0;
0255
0256 FDT_RO_PROBE(fdt);
0257
0258
0259 if (*path != '/') {
0260 const char *q = memchr(path, '/', end - p);
0261
0262 if (!q)
0263 q = end;
0264
0265 p = fdt_get_alias_namelen(fdt, p, q - p);
0266 if (!p)
0267 return -FDT_ERR_BADPATH;
0268 offset = fdt_path_offset(fdt, p);
0269
0270 p = q;
0271 }
0272
0273 while (p < end) {
0274 const char *q;
0275
0276 while (*p == '/') {
0277 p++;
0278 if (p == end)
0279 return offset;
0280 }
0281 q = memchr(p, '/', end - p);
0282 if (! q)
0283 q = end;
0284
0285 offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p);
0286 if (offset < 0)
0287 return offset;
0288
0289 p = q;
0290 }
0291
0292 return offset;
0293 }
0294
0295 int fdt_path_offset(const void *fdt, const char *path)
0296 {
0297 return fdt_path_offset_namelen(fdt, path, strlen(path));
0298 }
0299
0300 const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
0301 {
0302 const struct fdt_node_header *nh = fdt_offset_ptr_(fdt, nodeoffset);
0303 const char *nameptr;
0304 int err;
0305
0306 if (((err = fdt_ro_probe_(fdt)) < 0)
0307 || ((err = fdt_check_node_offset_(fdt, nodeoffset)) < 0))
0308 goto fail;
0309
0310 nameptr = nh->name;
0311
0312 if (!can_assume(LATEST) && fdt_version(fdt) < 0x10) {
0313
0314
0315
0316
0317
0318 const char *leaf;
0319 leaf = strrchr(nameptr, '/');
0320 if (leaf == NULL) {
0321 err = -FDT_ERR_BADSTRUCTURE;
0322 goto fail;
0323 }
0324 nameptr = leaf+1;
0325 }
0326
0327 if (len)
0328 *len = strlen(nameptr);
0329
0330 return nameptr;
0331
0332 fail:
0333 if (len)
0334 *len = err;
0335 return NULL;
0336 }
0337
0338 int fdt_first_property_offset(const void *fdt, int nodeoffset)
0339 {
0340 int offset;
0341
0342 if ((offset = fdt_check_node_offset_(fdt, nodeoffset)) < 0)
0343 return offset;
0344
0345 return nextprop_(fdt, offset);
0346 }
0347
0348 int fdt_next_property_offset(const void *fdt, int offset)
0349 {
0350 if ((offset = fdt_check_prop_offset_(fdt, offset)) < 0)
0351 return offset;
0352
0353 return nextprop_(fdt, offset);
0354 }
0355
0356 static const struct fdt_property *fdt_get_property_by_offset_(const void *fdt,
0357 int offset,
0358 int *lenp)
0359 {
0360 int err;
0361 const struct fdt_property *prop;
0362
0363 if (!can_assume(VALID_INPUT) &&
0364 (err = fdt_check_prop_offset_(fdt, offset)) < 0) {
0365 if (lenp)
0366 *lenp = err;
0367 return NULL;
0368 }
0369
0370 prop = fdt_offset_ptr_(fdt, offset);
0371
0372 if (lenp)
0373 *lenp = fdt32_ld_(&prop->len);
0374
0375 return prop;
0376 }
0377
0378 const struct fdt_property *fdt_get_property_by_offset(const void *fdt,
0379 int offset,
0380 int *lenp)
0381 {
0382
0383
0384
0385 if (!can_assume(LATEST) && fdt_version(fdt) < 0x10) {
0386 if (lenp)
0387 *lenp = -FDT_ERR_BADVERSION;
0388 return NULL;
0389 }
0390
0391 return fdt_get_property_by_offset_(fdt, offset, lenp);
0392 }
0393
0394 static const struct fdt_property *fdt_get_property_namelen_(const void *fdt,
0395 int offset,
0396 const char *name,
0397 int namelen,
0398 int *lenp,
0399 int *poffset)
0400 {
0401 for (offset = fdt_first_property_offset(fdt, offset);
0402 (offset >= 0);
0403 (offset = fdt_next_property_offset(fdt, offset))) {
0404 const struct fdt_property *prop;
0405
0406 prop = fdt_get_property_by_offset_(fdt, offset, lenp);
0407 if (!can_assume(LIBFDT_FLAWLESS) && !prop) {
0408 offset = -FDT_ERR_INTERNAL;
0409 break;
0410 }
0411 if (fdt_string_eq_(fdt, fdt32_ld_(&prop->nameoff),
0412 name, namelen)) {
0413 if (poffset)
0414 *poffset = offset;
0415 return prop;
0416 }
0417 }
0418
0419 if (lenp)
0420 *lenp = offset;
0421 return NULL;
0422 }
0423
0424
0425 const struct fdt_property *fdt_get_property_namelen(const void *fdt,
0426 int offset,
0427 const char *name,
0428 int namelen, int *lenp)
0429 {
0430
0431
0432 if (!can_assume(LATEST) && fdt_version(fdt) < 0x10) {
0433 if (lenp)
0434 *lenp = -FDT_ERR_BADVERSION;
0435 return NULL;
0436 }
0437
0438 return fdt_get_property_namelen_(fdt, offset, name, namelen, lenp,
0439 NULL);
0440 }
0441
0442
0443 const struct fdt_property *fdt_get_property(const void *fdt,
0444 int nodeoffset,
0445 const char *name, int *lenp)
0446 {
0447 return fdt_get_property_namelen(fdt, nodeoffset, name,
0448 strlen(name), lenp);
0449 }
0450
0451 const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
0452 const char *name, int namelen, int *lenp)
0453 {
0454 int poffset;
0455 const struct fdt_property *prop;
0456
0457 prop = fdt_get_property_namelen_(fdt, nodeoffset, name, namelen, lenp,
0458 &poffset);
0459 if (!prop)
0460 return NULL;
0461
0462
0463 if (!can_assume(LATEST) && fdt_version(fdt) < 0x10 &&
0464 (poffset + sizeof(*prop)) % 8 && fdt32_ld_(&prop->len) >= 8)
0465 return prop->data + 4;
0466 return prop->data;
0467 }
0468
0469 const void *fdt_getprop_by_offset(const void *fdt, int offset,
0470 const char **namep, int *lenp)
0471 {
0472 const struct fdt_property *prop;
0473
0474 prop = fdt_get_property_by_offset_(fdt, offset, lenp);
0475 if (!prop)
0476 return NULL;
0477 if (namep) {
0478 const char *name;
0479 int namelen;
0480
0481 if (!can_assume(VALID_INPUT)) {
0482 name = fdt_get_string(fdt, fdt32_ld_(&prop->nameoff),
0483 &namelen);
0484 if (!name) {
0485 if (lenp)
0486 *lenp = namelen;
0487 return NULL;
0488 }
0489 *namep = name;
0490 } else {
0491 *namep = fdt_string(fdt, fdt32_ld_(&prop->nameoff));
0492 }
0493 }
0494
0495
0496 if (!can_assume(LATEST) && fdt_version(fdt) < 0x10 &&
0497 (offset + sizeof(*prop)) % 8 && fdt32_ld_(&prop->len) >= 8)
0498 return prop->data + 4;
0499 return prop->data;
0500 }
0501
0502 const void *fdt_getprop(const void *fdt, int nodeoffset,
0503 const char *name, int *lenp)
0504 {
0505 return fdt_getprop_namelen(fdt, nodeoffset, name, strlen(name), lenp);
0506 }
0507
0508 uint32_t fdt_get_phandle(const void *fdt, int nodeoffset)
0509 {
0510 const fdt32_t *php;
0511 int len;
0512
0513
0514
0515 php = fdt_getprop(fdt, nodeoffset, "phandle", &len);
0516 if (!php || (len != sizeof(*php))) {
0517 php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len);
0518 if (!php || (len != sizeof(*php)))
0519 return 0;
0520 }
0521
0522 return fdt32_ld_(php);
0523 }
0524
0525 const char *fdt_get_alias_namelen(const void *fdt,
0526 const char *name, int namelen)
0527 {
0528 int aliasoffset;
0529
0530 aliasoffset = fdt_path_offset(fdt, "/aliases");
0531 if (aliasoffset < 0)
0532 return NULL;
0533
0534 return fdt_getprop_namelen(fdt, aliasoffset, name, namelen, NULL);
0535 }
0536
0537 const char *fdt_get_alias(const void *fdt, const char *name)
0538 {
0539 return fdt_get_alias_namelen(fdt, name, strlen(name));
0540 }
0541
0542 int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)
0543 {
0544 int pdepth = 0, p = 0;
0545 int offset, depth, namelen;
0546 const char *name;
0547
0548 FDT_RO_PROBE(fdt);
0549
0550 if (buflen < 2)
0551 return -FDT_ERR_NOSPACE;
0552
0553 for (offset = 0, depth = 0;
0554 (offset >= 0) && (offset <= nodeoffset);
0555 offset = fdt_next_node(fdt, offset, &depth)) {
0556 while (pdepth > depth) {
0557 do {
0558 p--;
0559 } while (buf[p-1] != '/');
0560 pdepth--;
0561 }
0562
0563 if (pdepth >= depth) {
0564 name = fdt_get_name(fdt, offset, &namelen);
0565 if (!name)
0566 return namelen;
0567 if ((p + namelen + 1) <= buflen) {
0568 memcpy(buf + p, name, namelen);
0569 p += namelen;
0570 buf[p++] = '/';
0571 pdepth++;
0572 }
0573 }
0574
0575 if (offset == nodeoffset) {
0576 if (pdepth < (depth + 1))
0577 return -FDT_ERR_NOSPACE;
0578
0579 if (p > 1)
0580 p--;
0581 buf[p] = '\0';
0582 return 0;
0583 }
0584 }
0585
0586 if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
0587 return -FDT_ERR_BADOFFSET;
0588 else if (offset == -FDT_ERR_BADOFFSET)
0589 return -FDT_ERR_BADSTRUCTURE;
0590
0591 return offset;
0592 }
0593
0594 int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
0595 int supernodedepth, int *nodedepth)
0596 {
0597 int offset, depth;
0598 int supernodeoffset = -FDT_ERR_INTERNAL;
0599
0600 FDT_RO_PROBE(fdt);
0601
0602 if (supernodedepth < 0)
0603 return -FDT_ERR_NOTFOUND;
0604
0605 for (offset = 0, depth = 0;
0606 (offset >= 0) && (offset <= nodeoffset);
0607 offset = fdt_next_node(fdt, offset, &depth)) {
0608 if (depth == supernodedepth)
0609 supernodeoffset = offset;
0610
0611 if (offset == nodeoffset) {
0612 if (nodedepth)
0613 *nodedepth = depth;
0614
0615 if (supernodedepth > depth)
0616 return -FDT_ERR_NOTFOUND;
0617 else
0618 return supernodeoffset;
0619 }
0620 }
0621
0622 if (!can_assume(VALID_INPUT)) {
0623 if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
0624 return -FDT_ERR_BADOFFSET;
0625 else if (offset == -FDT_ERR_BADOFFSET)
0626 return -FDT_ERR_BADSTRUCTURE;
0627 }
0628
0629 return offset;
0630 }
0631
0632 int fdt_node_depth(const void *fdt, int nodeoffset)
0633 {
0634 int nodedepth;
0635 int err;
0636
0637 err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth);
0638 if (err)
0639 return (can_assume(LIBFDT_FLAWLESS) || err < 0) ? err :
0640 -FDT_ERR_INTERNAL;
0641 return nodedepth;
0642 }
0643
0644 int fdt_parent_offset(const void *fdt, int nodeoffset)
0645 {
0646 int nodedepth = fdt_node_depth(fdt, nodeoffset);
0647
0648 if (nodedepth < 0)
0649 return nodedepth;
0650 return fdt_supernode_atdepth_offset(fdt, nodeoffset,
0651 nodedepth - 1, NULL);
0652 }
0653
0654 int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
0655 const char *propname,
0656 const void *propval, int proplen)
0657 {
0658 int offset;
0659 const void *val;
0660 int len;
0661
0662 FDT_RO_PROBE(fdt);
0663
0664
0665
0666
0667
0668
0669 for (offset = fdt_next_node(fdt, startoffset, NULL);
0670 offset >= 0;
0671 offset = fdt_next_node(fdt, offset, NULL)) {
0672 val = fdt_getprop(fdt, offset, propname, &len);
0673 if (val && (len == proplen)
0674 && (memcmp(val, propval, len) == 0))
0675 return offset;
0676 }
0677
0678 return offset;
0679 }
0680
0681 int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle)
0682 {
0683 int offset;
0684
0685 if ((phandle == 0) || (phandle == ~0U))
0686 return -FDT_ERR_BADPHANDLE;
0687
0688 FDT_RO_PROBE(fdt);
0689
0690
0691
0692
0693
0694
0695
0696 for (offset = fdt_next_node(fdt, -1, NULL);
0697 offset >= 0;
0698 offset = fdt_next_node(fdt, offset, NULL)) {
0699 if (fdt_get_phandle(fdt, offset) == phandle)
0700 return offset;
0701 }
0702
0703 return offset;
0704 }
0705
0706 int fdt_stringlist_contains(const char *strlist, int listlen, const char *str)
0707 {
0708 int len = strlen(str);
0709 const char *p;
0710
0711 while (listlen >= len) {
0712 if (memcmp(str, strlist, len+1) == 0)
0713 return 1;
0714 p = memchr(strlist, '\0', listlen);
0715 if (!p)
0716 return 0;
0717 listlen -= (p-strlist) + 1;
0718 strlist = p + 1;
0719 }
0720 return 0;
0721 }
0722
0723 int fdt_stringlist_count(const void *fdt, int nodeoffset, const char *property)
0724 {
0725 const char *list, *end;
0726 int length, count = 0;
0727
0728 list = fdt_getprop(fdt, nodeoffset, property, &length);
0729 if (!list)
0730 return length;
0731
0732 end = list + length;
0733
0734 while (list < end) {
0735 length = strnlen(list, end - list) + 1;
0736
0737
0738 if (list + length > end)
0739 return -FDT_ERR_BADVALUE;
0740
0741 list += length;
0742 count++;
0743 }
0744
0745 return count;
0746 }
0747
0748 int fdt_stringlist_search(const void *fdt, int nodeoffset, const char *property,
0749 const char *string)
0750 {
0751 int length, len, idx = 0;
0752 const char *list, *end;
0753
0754 list = fdt_getprop(fdt, nodeoffset, property, &length);
0755 if (!list)
0756 return length;
0757
0758 len = strlen(string) + 1;
0759 end = list + length;
0760
0761 while (list < end) {
0762 length = strnlen(list, end - list) + 1;
0763
0764
0765 if (list + length > end)
0766 return -FDT_ERR_BADVALUE;
0767
0768 if (length == len && memcmp(list, string, length) == 0)
0769 return idx;
0770
0771 list += length;
0772 idx++;
0773 }
0774
0775 return -FDT_ERR_NOTFOUND;
0776 }
0777
0778 const char *fdt_stringlist_get(const void *fdt, int nodeoffset,
0779 const char *property, int idx,
0780 int *lenp)
0781 {
0782 const char *list, *end;
0783 int length;
0784
0785 list = fdt_getprop(fdt, nodeoffset, property, &length);
0786 if (!list) {
0787 if (lenp)
0788 *lenp = length;
0789
0790 return NULL;
0791 }
0792
0793 end = list + length;
0794
0795 while (list < end) {
0796 length = strnlen(list, end - list) + 1;
0797
0798
0799 if (list + length > end) {
0800 if (lenp)
0801 *lenp = -FDT_ERR_BADVALUE;
0802
0803 return NULL;
0804 }
0805
0806 if (idx == 0) {
0807 if (lenp)
0808 *lenp = length - 1;
0809
0810 return list;
0811 }
0812
0813 list += length;
0814 idx--;
0815 }
0816
0817 if (lenp)
0818 *lenp = -FDT_ERR_NOTFOUND;
0819
0820 return NULL;
0821 }
0822
0823 int fdt_node_check_compatible(const void *fdt, int nodeoffset,
0824 const char *compatible)
0825 {
0826 const void *prop;
0827 int len;
0828
0829 prop = fdt_getprop(fdt, nodeoffset, "compatible", &len);
0830 if (!prop)
0831 return len;
0832
0833 return !fdt_stringlist_contains(prop, len, compatible);
0834 }
0835
0836 int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
0837 const char *compatible)
0838 {
0839 int offset, err;
0840
0841 FDT_RO_PROBE(fdt);
0842
0843
0844
0845
0846
0847
0848 for (offset = fdt_next_node(fdt, startoffset, NULL);
0849 offset >= 0;
0850 offset = fdt_next_node(fdt, offset, NULL)) {
0851 err = fdt_node_check_compatible(fdt, offset, compatible);
0852 if ((err < 0) && (err != -FDT_ERR_NOTFOUND))
0853 return err;
0854 else if (err == 0)
0855 return offset;
0856 }
0857
0858 return offset;
0859 }