112869ecdSRob Herring // SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
29fffb55fSDavid Gibson /*
39fffb55fSDavid Gibson * libfdt - Flat Device Tree manipulation
49fffb55fSDavid Gibson * Copyright (C) 2006 David Gibson, IBM Corporation.
59fffb55fSDavid Gibson */
69fffb55fSDavid Gibson #include "libfdt_env.h"
79fffb55fSDavid Gibson
89fffb55fSDavid Gibson #include <fdt.h>
99fffb55fSDavid Gibson #include <libfdt.h>
109fffb55fSDavid Gibson
119fffb55fSDavid Gibson #include "libfdt_internal.h"
129fffb55fSDavid Gibson
fdt_nodename_eq_(const void * fdt,int offset,const char * s,int len)139130ba88SRob Herring static int fdt_nodename_eq_(const void *fdt, int offset,
149fffb55fSDavid Gibson const char *s, int len)
159fffb55fSDavid Gibson {
169130ba88SRob Herring int olen;
179130ba88SRob Herring const char *p = fdt_get_name(fdt, offset, &olen);
189fffb55fSDavid Gibson
199130ba88SRob Herring if (!p || olen < len)
209fffb55fSDavid Gibson /* short match */
219fffb55fSDavid Gibson return 0;
229fffb55fSDavid Gibson
239fffb55fSDavid Gibson if (memcmp(p, s, len) != 0)
249fffb55fSDavid Gibson return 0;
259fffb55fSDavid Gibson
269fffb55fSDavid Gibson if (p[len] == '\0')
279fffb55fSDavid Gibson return 1;
289fffb55fSDavid Gibson else if (!memchr(s, '@', len) && (p[len] == '@'))
299fffb55fSDavid Gibson return 1;
309fffb55fSDavid Gibson else
319fffb55fSDavid Gibson return 0;
329fffb55fSDavid Gibson }
339fffb55fSDavid Gibson
fdt_get_string(const void * fdt,int stroffset,int * lenp)34f858927fSRob Herring const char *fdt_get_string(const void *fdt, int stroffset, int *lenp)
35f858927fSRob Herring {
36d047cd8aSRob Herring int32_t totalsize;
37d047cd8aSRob Herring uint32_t absoffset;
38f858927fSRob Herring size_t len;
39f858927fSRob Herring int err;
40f858927fSRob Herring const char *s, *n;
41f858927fSRob Herring
42d047cd8aSRob Herring if (can_assume(VALID_INPUT)) {
43d047cd8aSRob Herring s = (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset;
44d047cd8aSRob Herring
45d047cd8aSRob Herring if (lenp)
46d047cd8aSRob Herring *lenp = strlen(s);
47d047cd8aSRob Herring return s;
48d047cd8aSRob Herring }
49d047cd8aSRob Herring totalsize = fdt_ro_probe_(fdt);
500cec114eSRob Herring err = totalsize;
510cec114eSRob Herring if (totalsize < 0)
52f858927fSRob Herring goto fail;
53f858927fSRob Herring
54f858927fSRob Herring err = -FDT_ERR_BADOFFSET;
55d047cd8aSRob Herring absoffset = stroffset + fdt_off_dt_strings(fdt);
566e9c9686SRob Herring if (absoffset >= (unsigned)totalsize)
57f858927fSRob Herring goto fail;
580cec114eSRob Herring len = totalsize - absoffset;
59f858927fSRob Herring
60f858927fSRob Herring if (fdt_magic(fdt) == FDT_MAGIC) {
61f858927fSRob Herring if (stroffset < 0)
62f858927fSRob Herring goto fail;
63d047cd8aSRob Herring if (can_assume(LATEST) || fdt_version(fdt) >= 17) {
646e9c9686SRob Herring if ((unsigned)stroffset >= fdt_size_dt_strings(fdt))
65f858927fSRob Herring goto fail;
66f858927fSRob Herring if ((fdt_size_dt_strings(fdt) - stroffset) < len)
67f858927fSRob Herring len = fdt_size_dt_strings(fdt) - stroffset;
68f858927fSRob Herring }
69f858927fSRob Herring } else if (fdt_magic(fdt) == FDT_SW_MAGIC) {
706e9c9686SRob Herring unsigned int sw_stroffset = -stroffset;
716e9c9686SRob Herring
726e9c9686SRob Herring if ((stroffset >= 0) ||
736e9c9686SRob Herring (sw_stroffset > fdt_size_dt_strings(fdt)))
74f858927fSRob Herring goto fail;
756e9c9686SRob Herring if (sw_stroffset < len)
766e9c9686SRob Herring len = sw_stroffset;
77f858927fSRob Herring } else {
78f858927fSRob Herring err = -FDT_ERR_INTERNAL;
79f858927fSRob Herring goto fail;
80f858927fSRob Herring }
81f858927fSRob Herring
82f858927fSRob Herring s = (const char *)fdt + absoffset;
83f858927fSRob Herring n = memchr(s, '\0', len);
84f858927fSRob Herring if (!n) {
85f858927fSRob Herring /* missing terminating NULL */
86f858927fSRob Herring err = -FDT_ERR_TRUNCATED;
87f858927fSRob Herring goto fail;
88f858927fSRob Herring }
89f858927fSRob Herring
90f858927fSRob Herring if (lenp)
91f858927fSRob Herring *lenp = n - s;
92f858927fSRob Herring return s;
93f858927fSRob Herring
94f858927fSRob Herring fail:
95f858927fSRob Herring if (lenp)
96f858927fSRob Herring *lenp = err;
97f858927fSRob Herring return NULL;
98f858927fSRob Herring }
99f858927fSRob Herring
fdt_string(const void * fdt,int stroffset)1009fffb55fSDavid Gibson const char *fdt_string(const void *fdt, int stroffset)
1019fffb55fSDavid Gibson {
102f858927fSRob Herring return fdt_get_string(fdt, stroffset, NULL);
1039fffb55fSDavid Gibson }
1049fffb55fSDavid Gibson
fdt_string_eq_(const void * fdt,int stroffset,const char * s,int len)1059130ba88SRob Herring static int fdt_string_eq_(const void *fdt, int stroffset,
106cd296721SStephen Warren const char *s, int len)
107cd296721SStephen Warren {
108f858927fSRob Herring int slen;
109f858927fSRob Herring const char *p = fdt_get_string(fdt, stroffset, &slen);
110cd296721SStephen Warren
111f858927fSRob Herring return p && (slen == len) && (memcmp(p, s, len) == 0);
112cd296721SStephen Warren }
113cd296721SStephen Warren
fdt_find_max_phandle(const void * fdt,uint32_t * phandle)1149bb9c6a1SRob Herring int fdt_find_max_phandle(const void *fdt, uint32_t *phandle)
1156f05afcbSRob Herring {
1169bb9c6a1SRob Herring uint32_t max = 0;
1179bb9c6a1SRob Herring int offset = -1;
1186f05afcbSRob Herring
1199bb9c6a1SRob Herring while (true) {
1209bb9c6a1SRob Herring uint32_t value;
1216f05afcbSRob Herring
1229bb9c6a1SRob Herring offset = fdt_next_node(fdt, offset, NULL);
1239bb9c6a1SRob Herring if (offset < 0) {
1246f05afcbSRob Herring if (offset == -FDT_ERR_NOTFOUND)
1259bb9c6a1SRob Herring break;
1266f05afcbSRob Herring
1279bb9c6a1SRob Herring return offset;
1286f05afcbSRob Herring }
1296f05afcbSRob Herring
1309bb9c6a1SRob Herring value = fdt_get_phandle(fdt, offset);
1319bb9c6a1SRob Herring
1329bb9c6a1SRob Herring if (value > max)
1339bb9c6a1SRob Herring max = value;
1349bb9c6a1SRob Herring }
1359bb9c6a1SRob Herring
1369bb9c6a1SRob Herring if (phandle)
1379bb9c6a1SRob Herring *phandle = max;
1389bb9c6a1SRob Herring
1399bb9c6a1SRob Herring return 0;
1409bb9c6a1SRob Herring }
1419bb9c6a1SRob Herring
fdt_generate_phandle(const void * fdt,uint32_t * phandle)1429bb9c6a1SRob Herring int fdt_generate_phandle(const void *fdt, uint32_t *phandle)
1439bb9c6a1SRob Herring {
1449bb9c6a1SRob Herring uint32_t max;
1459bb9c6a1SRob Herring int err;
1469bb9c6a1SRob Herring
1479bb9c6a1SRob Herring err = fdt_find_max_phandle(fdt, &max);
1489bb9c6a1SRob Herring if (err < 0)
1499bb9c6a1SRob Herring return err;
1509bb9c6a1SRob Herring
1519bb9c6a1SRob Herring if (max == FDT_MAX_PHANDLE)
1529bb9c6a1SRob Herring return -FDT_ERR_NOPHANDLES;
1539bb9c6a1SRob Herring
1549bb9c6a1SRob Herring if (phandle)
1559bb9c6a1SRob Herring *phandle = max + 1;
1569bb9c6a1SRob Herring
1576f05afcbSRob Herring return 0;
1586f05afcbSRob Herring }
1596f05afcbSRob Herring
fdt_mem_rsv(const void * fdt,int n)160f858927fSRob Herring static const struct fdt_reserve_entry *fdt_mem_rsv(const void *fdt, int n)
161f858927fSRob Herring {
1626e9c9686SRob Herring unsigned int offset = n * sizeof(struct fdt_reserve_entry);
1636e9c9686SRob Herring unsigned int absoffset = fdt_off_mem_rsvmap(fdt) + offset;
164f858927fSRob Herring
165d047cd8aSRob Herring if (!can_assume(VALID_INPUT)) {
166f858927fSRob Herring if (absoffset < fdt_off_mem_rsvmap(fdt))
167f858927fSRob Herring return NULL;
168d047cd8aSRob Herring if (absoffset > fdt_totalsize(fdt) -
169d047cd8aSRob Herring sizeof(struct fdt_reserve_entry))
170f858927fSRob Herring return NULL;
171d047cd8aSRob Herring }
172f858927fSRob Herring return fdt_mem_rsv_(fdt, n);
173f858927fSRob Herring }
174f858927fSRob Herring
fdt_get_mem_rsv(const void * fdt,int n,uint64_t * address,uint64_t * size)1759fffb55fSDavid Gibson int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
1769fffb55fSDavid Gibson {
177f858927fSRob Herring const struct fdt_reserve_entry *re;
178f858927fSRob Herring
179f858927fSRob Herring FDT_RO_PROBE(fdt);
180f858927fSRob Herring re = fdt_mem_rsv(fdt, n);
181d047cd8aSRob Herring if (!can_assume(VALID_INPUT) && !re)
182f858927fSRob Herring return -FDT_ERR_BADOFFSET;
183f858927fSRob Herring
18479edff12SRob Herring *address = fdt64_ld_(&re->address);
18579edff12SRob Herring *size = fdt64_ld_(&re->size);
1869fffb55fSDavid Gibson return 0;
1879fffb55fSDavid Gibson }
1889fffb55fSDavid Gibson
fdt_num_mem_rsv(const void * fdt)1899fffb55fSDavid Gibson int fdt_num_mem_rsv(const void *fdt)
1909fffb55fSDavid Gibson {
191f858927fSRob Herring int i;
192f858927fSRob Herring const struct fdt_reserve_entry *re;
1939fffb55fSDavid Gibson
194f858927fSRob Herring for (i = 0; (re = fdt_mem_rsv(fdt, i)) != NULL; i++) {
19579edff12SRob Herring if (fdt64_ld_(&re->size) == 0)
1969fffb55fSDavid Gibson return i;
1979fffb55fSDavid Gibson }
198f858927fSRob Herring return -FDT_ERR_TRUNCATED;
199f858927fSRob Herring }
2009fffb55fSDavid Gibson
nextprop_(const void * fdt,int offset)2019130ba88SRob Herring static int nextprop_(const void *fdt, int offset)
202cd296721SStephen Warren {
203cd296721SStephen Warren uint32_t tag;
204cd296721SStephen Warren int nextoffset;
205cd296721SStephen Warren
206cd296721SStephen Warren do {
207cd296721SStephen Warren tag = fdt_next_tag(fdt, offset, &nextoffset);
208cd296721SStephen Warren
209cd296721SStephen Warren switch (tag) {
210cd296721SStephen Warren case FDT_END:
211cd296721SStephen Warren if (nextoffset >= 0)
212cd296721SStephen Warren return -FDT_ERR_BADSTRUCTURE;
213cd296721SStephen Warren else
214cd296721SStephen Warren return nextoffset;
215cd296721SStephen Warren
216cd296721SStephen Warren case FDT_PROP:
217cd296721SStephen Warren return offset;
218cd296721SStephen Warren }
219cd296721SStephen Warren offset = nextoffset;
220cd296721SStephen Warren } while (tag == FDT_NOP);
221cd296721SStephen Warren
222cd296721SStephen Warren return -FDT_ERR_NOTFOUND;
223cd296721SStephen Warren }
224cd296721SStephen Warren
fdt_subnode_offset_namelen(const void * fdt,int offset,const char * name,int namelen)2259fffb55fSDavid Gibson int fdt_subnode_offset_namelen(const void *fdt, int offset,
2269fffb55fSDavid Gibson const char *name, int namelen)
2279fffb55fSDavid Gibson {
2289fffb55fSDavid Gibson int depth;
2299fffb55fSDavid Gibson
230f858927fSRob Herring FDT_RO_PROBE(fdt);
2319fffb55fSDavid Gibson
232cd296721SStephen Warren for (depth = 0;
233cd296721SStephen Warren (offset >= 0) && (depth >= 0);
234cd296721SStephen Warren offset = fdt_next_node(fdt, offset, &depth))
235cd296721SStephen Warren if ((depth == 1)
2369130ba88SRob Herring && fdt_nodename_eq_(fdt, offset, name, namelen))
2379fffb55fSDavid Gibson return offset;
2389fffb55fSDavid Gibson
239cd296721SStephen Warren if (depth < 0)
2409fffb55fSDavid Gibson return -FDT_ERR_NOTFOUND;
241cd296721SStephen Warren return offset; /* error */
2429fffb55fSDavid Gibson }
2439fffb55fSDavid Gibson
fdt_subnode_offset(const void * fdt,int parentoffset,const char * name)2449fffb55fSDavid Gibson int fdt_subnode_offset(const void *fdt, int parentoffset,
2459fffb55fSDavid Gibson const char *name)
2469fffb55fSDavid Gibson {
2479fffb55fSDavid Gibson return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name));
2489fffb55fSDavid Gibson }
2499fffb55fSDavid Gibson
fdt_path_offset_namelen(const void * fdt,const char * path,int namelen)25047605971SRob Herring int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen)
2519fffb55fSDavid Gibson {
25247605971SRob Herring const char *end = path + namelen;
2539fffb55fSDavid Gibson const char *p = path;
2549fffb55fSDavid Gibson int offset = 0;
2559fffb55fSDavid Gibson
256f858927fSRob Herring FDT_RO_PROBE(fdt);
2579fffb55fSDavid Gibson
258cd296721SStephen Warren /* see if we have an alias */
259cd296721SStephen Warren if (*path != '/') {
26047605971SRob Herring const char *q = memchr(path, '/', end - p);
261cd296721SStephen Warren
262cd296721SStephen Warren if (!q)
263cd296721SStephen Warren q = end;
264cd296721SStephen Warren
265cd296721SStephen Warren p = fdt_get_alias_namelen(fdt, p, q - p);
266cd296721SStephen Warren if (!p)
2679fffb55fSDavid Gibson return -FDT_ERR_BADPATH;
268cd296721SStephen Warren offset = fdt_path_offset(fdt, p);
269cd296721SStephen Warren
270cd296721SStephen Warren p = q;
271cd296721SStephen Warren }
2729fffb55fSDavid Gibson
27347605971SRob Herring while (p < end) {
2749fffb55fSDavid Gibson const char *q;
2759fffb55fSDavid Gibson
27647605971SRob Herring while (*p == '/') {
2779fffb55fSDavid Gibson p++;
27847605971SRob Herring if (p == end)
2799fffb55fSDavid Gibson return offset;
28047605971SRob Herring }
28147605971SRob Herring q = memchr(p, '/', end - p);
2829fffb55fSDavid Gibson if (! q)
2839fffb55fSDavid Gibson q = end;
2849fffb55fSDavid Gibson
2859fffb55fSDavid Gibson offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p);
2869fffb55fSDavid Gibson if (offset < 0)
2879fffb55fSDavid Gibson return offset;
2889fffb55fSDavid Gibson
2899fffb55fSDavid Gibson p = q;
2909fffb55fSDavid Gibson }
2919fffb55fSDavid Gibson
2929fffb55fSDavid Gibson return offset;
2939fffb55fSDavid Gibson }
2949fffb55fSDavid Gibson
fdt_path_offset(const void * fdt,const char * path)29547605971SRob Herring int fdt_path_offset(const void *fdt, const char *path)
29647605971SRob Herring {
29747605971SRob Herring return fdt_path_offset_namelen(fdt, path, strlen(path));
29847605971SRob Herring }
29947605971SRob Herring
fdt_get_name(const void * fdt,int nodeoffset,int * len)3009fffb55fSDavid Gibson const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
3019fffb55fSDavid Gibson {
3029130ba88SRob Herring const struct fdt_node_header *nh = fdt_offset_ptr_(fdt, nodeoffset);
3039130ba88SRob Herring const char *nameptr;
3049fffb55fSDavid Gibson int err;
3059fffb55fSDavid Gibson
3060cec114eSRob Herring if (((err = fdt_ro_probe_(fdt)) < 0)
3079130ba88SRob Herring || ((err = fdt_check_node_offset_(fdt, nodeoffset)) < 0))
3089fffb55fSDavid Gibson goto fail;
3099fffb55fSDavid Gibson
3109130ba88SRob Herring nameptr = nh->name;
3119fffb55fSDavid Gibson
312d047cd8aSRob Herring if (!can_assume(LATEST) && fdt_version(fdt) < 0x10) {
3139130ba88SRob Herring /*
3149130ba88SRob Herring * For old FDT versions, match the naming conventions of V16:
3159130ba88SRob Herring * give only the leaf name (after all /). The actual tree
3169130ba88SRob Herring * contents are loosely checked.
3179130ba88SRob Herring */
3189130ba88SRob Herring const char *leaf;
3199130ba88SRob Herring leaf = strrchr(nameptr, '/');
3209130ba88SRob Herring if (leaf == NULL) {
3219130ba88SRob Herring err = -FDT_ERR_BADSTRUCTURE;
3229130ba88SRob Herring goto fail;
3239130ba88SRob Herring }
3249130ba88SRob Herring nameptr = leaf+1;
3259130ba88SRob Herring }
3269130ba88SRob Herring
3279130ba88SRob Herring if (len)
3289130ba88SRob Herring *len = strlen(nameptr);
3299130ba88SRob Herring
3309130ba88SRob Herring return nameptr;
3319fffb55fSDavid Gibson
3329fffb55fSDavid Gibson fail:
3339fffb55fSDavid Gibson if (len)
3349fffb55fSDavid Gibson *len = err;
3359fffb55fSDavid Gibson return NULL;
3369fffb55fSDavid Gibson }
3379fffb55fSDavid Gibson
fdt_first_property_offset(const void * fdt,int nodeoffset)338cd296721SStephen Warren int fdt_first_property_offset(const void *fdt, int nodeoffset)
3399fffb55fSDavid Gibson {
340cd296721SStephen Warren int offset;
341cd296721SStephen Warren
3429130ba88SRob Herring if ((offset = fdt_check_node_offset_(fdt, nodeoffset)) < 0)
343cd296721SStephen Warren return offset;
344cd296721SStephen Warren
3459130ba88SRob Herring return nextprop_(fdt, offset);
346cd296721SStephen Warren }
347cd296721SStephen Warren
fdt_next_property_offset(const void * fdt,int offset)348cd296721SStephen Warren int fdt_next_property_offset(const void *fdt, int offset)
349cd296721SStephen Warren {
3509130ba88SRob Herring if ((offset = fdt_check_prop_offset_(fdt, offset)) < 0)
351cd296721SStephen Warren return offset;
352cd296721SStephen Warren
3539130ba88SRob Herring return nextprop_(fdt, offset);
354cd296721SStephen Warren }
355cd296721SStephen Warren
fdt_get_property_by_offset_(const void * fdt,int offset,int * lenp)3569130ba88SRob Herring static const struct fdt_property *fdt_get_property_by_offset_(const void *fdt,
357cd296721SStephen Warren int offset,
358cd296721SStephen Warren int *lenp)
359cd296721SStephen Warren {
3609fffb55fSDavid Gibson int err;
361cd296721SStephen Warren const struct fdt_property *prop;
3629fffb55fSDavid Gibson
363d047cd8aSRob Herring if (!can_assume(VALID_INPUT) &&
364d047cd8aSRob Herring (err = fdt_check_prop_offset_(fdt, offset)) < 0) {
3659fffb55fSDavid Gibson if (lenp)
3669fffb55fSDavid Gibson *lenp = err;
3679fffb55fSDavid Gibson return NULL;
3689fffb55fSDavid Gibson }
3699fffb55fSDavid Gibson
3709130ba88SRob Herring prop = fdt_offset_ptr_(fdt, offset);
371cd296721SStephen Warren
372cd296721SStephen Warren if (lenp)
37379edff12SRob Herring *lenp = fdt32_ld_(&prop->len);
374cd296721SStephen Warren
375cd296721SStephen Warren return prop;
376cd296721SStephen Warren }
377cd296721SStephen Warren
fdt_get_property_by_offset(const void * fdt,int offset,int * lenp)3789130ba88SRob Herring const struct fdt_property *fdt_get_property_by_offset(const void *fdt,
3799130ba88SRob Herring int offset,
3809130ba88SRob Herring int *lenp)
3819130ba88SRob Herring {
3829130ba88SRob Herring /* Prior to version 16, properties may need realignment
3839130ba88SRob Herring * and this API does not work. fdt_getprop_*() will, however. */
3849130ba88SRob Herring
385d047cd8aSRob Herring if (!can_assume(LATEST) && fdt_version(fdt) < 0x10) {
3869130ba88SRob Herring if (lenp)
3879130ba88SRob Herring *lenp = -FDT_ERR_BADVERSION;
3889130ba88SRob Herring return NULL;
3899130ba88SRob Herring }
3909130ba88SRob Herring
3919130ba88SRob Herring return fdt_get_property_by_offset_(fdt, offset, lenp);
3929130ba88SRob Herring }
3939130ba88SRob Herring
fdt_get_property_namelen_(const void * fdt,int offset,const char * name,int namelen,int * lenp,int * poffset)3949130ba88SRob Herring static const struct fdt_property *fdt_get_property_namelen_(const void *fdt,
395cd296721SStephen Warren int offset,
396cd296721SStephen Warren const char *name,
3979130ba88SRob Herring int namelen,
3989130ba88SRob Herring int *lenp,
3999130ba88SRob Herring int *poffset)
400cd296721SStephen Warren {
401cd296721SStephen Warren for (offset = fdt_first_property_offset(fdt, offset);
402cd296721SStephen Warren (offset >= 0);
403cd296721SStephen Warren (offset = fdt_next_property_offset(fdt, offset))) {
404cd296721SStephen Warren const struct fdt_property *prop;
405cd296721SStephen Warren
406d047cd8aSRob Herring prop = fdt_get_property_by_offset_(fdt, offset, lenp);
407d047cd8aSRob Herring if (!can_assume(LIBFDT_FLAWLESS) && !prop) {
408cd296721SStephen Warren offset = -FDT_ERR_INTERNAL;
409cd296721SStephen Warren break;
410cd296721SStephen Warren }
41179edff12SRob Herring if (fdt_string_eq_(fdt, fdt32_ld_(&prop->nameoff),
4129130ba88SRob Herring name, namelen)) {
4139130ba88SRob Herring if (poffset)
4149130ba88SRob Herring *poffset = offset;
415cd296721SStephen Warren return prop;
416cd296721SStephen Warren }
4179130ba88SRob Herring }
418cd296721SStephen Warren
419cd296721SStephen Warren if (lenp)
420cd296721SStephen Warren *lenp = offset;
421cd296721SStephen Warren return NULL;
422cd296721SStephen Warren }
423cd296721SStephen Warren
4249130ba88SRob Herring
fdt_get_property_namelen(const void * fdt,int offset,const char * name,int namelen,int * lenp)4259130ba88SRob Herring const struct fdt_property *fdt_get_property_namelen(const void *fdt,
4269130ba88SRob Herring int offset,
4279130ba88SRob Herring const char *name,
4289130ba88SRob Herring int namelen, int *lenp)
4299130ba88SRob Herring {
4309130ba88SRob Herring /* Prior to version 16, properties may need realignment
4319130ba88SRob Herring * and this API does not work. fdt_getprop_*() will, however. */
432d047cd8aSRob Herring if (!can_assume(LATEST) && fdt_version(fdt) < 0x10) {
4339130ba88SRob Herring if (lenp)
4349130ba88SRob Herring *lenp = -FDT_ERR_BADVERSION;
4359130ba88SRob Herring return NULL;
4369130ba88SRob Herring }
4379130ba88SRob Herring
4389130ba88SRob Herring return fdt_get_property_namelen_(fdt, offset, name, namelen, lenp,
4399130ba88SRob Herring NULL);
4409130ba88SRob Herring }
4419130ba88SRob Herring
4429130ba88SRob Herring
fdt_get_property(const void * fdt,int nodeoffset,const char * name,int * lenp)443cd296721SStephen Warren const struct fdt_property *fdt_get_property(const void *fdt,
444cd296721SStephen Warren int nodeoffset,
4459fffb55fSDavid Gibson const char *name, int *lenp)
4469fffb55fSDavid Gibson {
447cd296721SStephen Warren return fdt_get_property_namelen(fdt, nodeoffset, name,
448cd296721SStephen Warren strlen(name), lenp);
449cd296721SStephen Warren }
450cd296721SStephen Warren
fdt_getprop_namelen(const void * fdt,int nodeoffset,const char * name,int namelen,int * lenp)451cd296721SStephen Warren const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
452cd296721SStephen Warren const char *name, int namelen, int *lenp)
453cd296721SStephen Warren {
4549130ba88SRob Herring int poffset;
4559fffb55fSDavid Gibson const struct fdt_property *prop;
4569fffb55fSDavid Gibson
4579130ba88SRob Herring prop = fdt_get_property_namelen_(fdt, nodeoffset, name, namelen, lenp,
4589130ba88SRob Herring &poffset);
4599fffb55fSDavid Gibson if (!prop)
4609fffb55fSDavid Gibson return NULL;
4619fffb55fSDavid Gibson
4629130ba88SRob Herring /* Handle realignment */
463d047cd8aSRob Herring if (!can_assume(LATEST) && fdt_version(fdt) < 0x10 &&
46479edff12SRob Herring (poffset + sizeof(*prop)) % 8 && fdt32_ld_(&prop->len) >= 8)
4659130ba88SRob Herring return prop->data + 4;
4669fffb55fSDavid Gibson return prop->data;
4679fffb55fSDavid Gibson }
4689fffb55fSDavid Gibson
fdt_getprop_by_offset(const void * fdt,int offset,const char ** namep,int * lenp)469cd296721SStephen Warren const void *fdt_getprop_by_offset(const void *fdt, int offset,
470cd296721SStephen Warren const char **namep, int *lenp)
471cd296721SStephen Warren {
472cd296721SStephen Warren const struct fdt_property *prop;
473cd296721SStephen Warren
4749130ba88SRob Herring prop = fdt_get_property_by_offset_(fdt, offset, lenp);
475cd296721SStephen Warren if (!prop)
476cd296721SStephen Warren return NULL;
477f858927fSRob Herring if (namep) {
478f858927fSRob Herring const char *name;
479f858927fSRob Herring int namelen;
480d047cd8aSRob Herring
481d047cd8aSRob Herring if (!can_assume(VALID_INPUT)) {
48279edff12SRob Herring name = fdt_get_string(fdt, fdt32_ld_(&prop->nameoff),
483f858927fSRob Herring &namelen);
484*ea3723a5SRob Herring *namep = name;
485f858927fSRob Herring if (!name) {
486f858927fSRob Herring if (lenp)
487f858927fSRob Herring *lenp = namelen;
488f858927fSRob Herring return NULL;
489f858927fSRob Herring }
490d047cd8aSRob Herring } else {
49179edff12SRob Herring *namep = fdt_string(fdt, fdt32_ld_(&prop->nameoff));
492d047cd8aSRob Herring }
493f858927fSRob Herring }
4949130ba88SRob Herring
4959130ba88SRob Herring /* Handle realignment */
496d047cd8aSRob Herring if (!can_assume(LATEST) && fdt_version(fdt) < 0x10 &&
49779edff12SRob Herring (offset + sizeof(*prop)) % 8 && fdt32_ld_(&prop->len) >= 8)
4989130ba88SRob Herring return prop->data + 4;
499cd296721SStephen Warren return prop->data;
500cd296721SStephen Warren }
501cd296721SStephen Warren
fdt_getprop(const void * fdt,int nodeoffset,const char * name,int * lenp)502cd296721SStephen Warren const void *fdt_getprop(const void *fdt, int nodeoffset,
503cd296721SStephen Warren const char *name, int *lenp)
504cd296721SStephen Warren {
505cd296721SStephen Warren return fdt_getprop_namelen(fdt, nodeoffset, name, strlen(name), lenp);
506cd296721SStephen Warren }
507cd296721SStephen Warren
fdt_get_phandle(const void * fdt,int nodeoffset)5089fffb55fSDavid Gibson uint32_t fdt_get_phandle(const void *fdt, int nodeoffset)
5099fffb55fSDavid Gibson {
51047605971SRob Herring const fdt32_t *php;
5119fffb55fSDavid Gibson int len;
5129fffb55fSDavid Gibson
513cd296721SStephen Warren /* FIXME: This is a bit sub-optimal, since we potentially scan
514cd296721SStephen Warren * over all the properties twice. */
515cd296721SStephen Warren php = fdt_getprop(fdt, nodeoffset, "phandle", &len);
516cd296721SStephen Warren if (!php || (len != sizeof(*php))) {
5179fffb55fSDavid Gibson php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len);
5189fffb55fSDavid Gibson if (!php || (len != sizeof(*php)))
5199fffb55fSDavid Gibson return 0;
520cd296721SStephen Warren }
5219fffb55fSDavid Gibson
52279edff12SRob Herring return fdt32_ld_(php);
5239fffb55fSDavid Gibson }
5249fffb55fSDavid Gibson
fdt_get_alias_namelen(const void * fdt,const char * name,int namelen)525cd296721SStephen Warren const char *fdt_get_alias_namelen(const void *fdt,
526cd296721SStephen Warren const char *name, int namelen)
527cd296721SStephen Warren {
528cd296721SStephen Warren int aliasoffset;
529cd296721SStephen Warren
530cd296721SStephen Warren aliasoffset = fdt_path_offset(fdt, "/aliases");
531cd296721SStephen Warren if (aliasoffset < 0)
532cd296721SStephen Warren return NULL;
533cd296721SStephen Warren
534cd296721SStephen Warren return fdt_getprop_namelen(fdt, aliasoffset, name, namelen, NULL);
535cd296721SStephen Warren }
536cd296721SStephen Warren
fdt_get_alias(const void * fdt,const char * name)537cd296721SStephen Warren const char *fdt_get_alias(const void *fdt, const char *name)
538cd296721SStephen Warren {
539cd296721SStephen Warren return fdt_get_alias_namelen(fdt, name, strlen(name));
540cd296721SStephen Warren }
541cd296721SStephen Warren
fdt_get_path(const void * fdt,int nodeoffset,char * buf,int buflen)5429fffb55fSDavid Gibson int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)
5439fffb55fSDavid Gibson {
5449fffb55fSDavid Gibson int pdepth = 0, p = 0;
5459fffb55fSDavid Gibson int offset, depth, namelen;
5469fffb55fSDavid Gibson const char *name;
5479fffb55fSDavid Gibson
548f858927fSRob Herring FDT_RO_PROBE(fdt);
5499fffb55fSDavid Gibson
5509fffb55fSDavid Gibson if (buflen < 2)
5519fffb55fSDavid Gibson return -FDT_ERR_NOSPACE;
5529fffb55fSDavid Gibson
5539fffb55fSDavid Gibson for (offset = 0, depth = 0;
5549fffb55fSDavid Gibson (offset >= 0) && (offset <= nodeoffset);
5559fffb55fSDavid Gibson offset = fdt_next_node(fdt, offset, &depth)) {
5569fffb55fSDavid Gibson while (pdepth > depth) {
5579fffb55fSDavid Gibson do {
5589fffb55fSDavid Gibson p--;
5599fffb55fSDavid Gibson } while (buf[p-1] != '/');
5609fffb55fSDavid Gibson pdepth--;
5619fffb55fSDavid Gibson }
5629fffb55fSDavid Gibson
563cd296721SStephen Warren if (pdepth >= depth) {
5649fffb55fSDavid Gibson name = fdt_get_name(fdt, offset, &namelen);
5659fffb55fSDavid Gibson if (!name)
5669fffb55fSDavid Gibson return namelen;
5679fffb55fSDavid Gibson if ((p + namelen + 1) <= buflen) {
5689fffb55fSDavid Gibson memcpy(buf + p, name, namelen);
5699fffb55fSDavid Gibson p += namelen;
5709fffb55fSDavid Gibson buf[p++] = '/';
5719fffb55fSDavid Gibson pdepth++;
5729fffb55fSDavid Gibson }
573cd296721SStephen Warren }
5749fffb55fSDavid Gibson
5759fffb55fSDavid Gibson if (offset == nodeoffset) {
5769fffb55fSDavid Gibson if (pdepth < (depth + 1))
5779fffb55fSDavid Gibson return -FDT_ERR_NOSPACE;
5789fffb55fSDavid Gibson
5799fffb55fSDavid Gibson if (p > 1) /* special case so that root path is "/", not "" */
5809fffb55fSDavid Gibson p--;
5819fffb55fSDavid Gibson buf[p] = '\0';
582cd296721SStephen Warren return 0;
5839fffb55fSDavid Gibson }
5849fffb55fSDavid Gibson }
5859fffb55fSDavid Gibson
5869fffb55fSDavid Gibson if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
5879fffb55fSDavid Gibson return -FDT_ERR_BADOFFSET;
5889fffb55fSDavid Gibson else if (offset == -FDT_ERR_BADOFFSET)
5899fffb55fSDavid Gibson return -FDT_ERR_BADSTRUCTURE;
5909fffb55fSDavid Gibson
5919fffb55fSDavid Gibson return offset; /* error from fdt_next_node() */
5929fffb55fSDavid Gibson }
5939fffb55fSDavid Gibson
fdt_supernode_atdepth_offset(const void * fdt,int nodeoffset,int supernodedepth,int * nodedepth)5949fffb55fSDavid Gibson int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
5959fffb55fSDavid Gibson int supernodedepth, int *nodedepth)
5969fffb55fSDavid Gibson {
5979fffb55fSDavid Gibson int offset, depth;
5989fffb55fSDavid Gibson int supernodeoffset = -FDT_ERR_INTERNAL;
5999fffb55fSDavid Gibson
600f858927fSRob Herring FDT_RO_PROBE(fdt);
6019fffb55fSDavid Gibson
6029fffb55fSDavid Gibson if (supernodedepth < 0)
6039fffb55fSDavid Gibson return -FDT_ERR_NOTFOUND;
6049fffb55fSDavid Gibson
6059fffb55fSDavid Gibson for (offset = 0, depth = 0;
6069fffb55fSDavid Gibson (offset >= 0) && (offset <= nodeoffset);
6079fffb55fSDavid Gibson offset = fdt_next_node(fdt, offset, &depth)) {
6089fffb55fSDavid Gibson if (depth == supernodedepth)
6099fffb55fSDavid Gibson supernodeoffset = offset;
6109fffb55fSDavid Gibson
6119fffb55fSDavid Gibson if (offset == nodeoffset) {
6129fffb55fSDavid Gibson if (nodedepth)
6139fffb55fSDavid Gibson *nodedepth = depth;
6149fffb55fSDavid Gibson
6159fffb55fSDavid Gibson if (supernodedepth > depth)
6169fffb55fSDavid Gibson return -FDT_ERR_NOTFOUND;
6179fffb55fSDavid Gibson else
6189fffb55fSDavid Gibson return supernodeoffset;
6199fffb55fSDavid Gibson }
6209fffb55fSDavid Gibson }
6219fffb55fSDavid Gibson
622d047cd8aSRob Herring if (!can_assume(VALID_INPUT)) {
6239fffb55fSDavid Gibson if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
6249fffb55fSDavid Gibson return -FDT_ERR_BADOFFSET;
6259fffb55fSDavid Gibson else if (offset == -FDT_ERR_BADOFFSET)
6269fffb55fSDavid Gibson return -FDT_ERR_BADSTRUCTURE;
627d047cd8aSRob Herring }
6289fffb55fSDavid Gibson
6299fffb55fSDavid Gibson return offset; /* error from fdt_next_node() */
6309fffb55fSDavid Gibson }
6319fffb55fSDavid Gibson
fdt_node_depth(const void * fdt,int nodeoffset)6329fffb55fSDavid Gibson int fdt_node_depth(const void *fdt, int nodeoffset)
6339fffb55fSDavid Gibson {
6349fffb55fSDavid Gibson int nodedepth;
6359fffb55fSDavid Gibson int err;
6369fffb55fSDavid Gibson
6379fffb55fSDavid Gibson err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth);
6389fffb55fSDavid Gibson if (err)
639d047cd8aSRob Herring return (can_assume(LIBFDT_FLAWLESS) || err < 0) ? err :
640d047cd8aSRob Herring -FDT_ERR_INTERNAL;
6419fffb55fSDavid Gibson return nodedepth;
6429fffb55fSDavid Gibson }
6439fffb55fSDavid Gibson
fdt_parent_offset(const void * fdt,int nodeoffset)6449fffb55fSDavid Gibson int fdt_parent_offset(const void *fdt, int nodeoffset)
6459fffb55fSDavid Gibson {
6469fffb55fSDavid Gibson int nodedepth = fdt_node_depth(fdt, nodeoffset);
6479fffb55fSDavid Gibson
6489fffb55fSDavid Gibson if (nodedepth < 0)
6499fffb55fSDavid Gibson return nodedepth;
6509fffb55fSDavid Gibson return fdt_supernode_atdepth_offset(fdt, nodeoffset,
6519fffb55fSDavid Gibson nodedepth - 1, NULL);
6529fffb55fSDavid Gibson }
6539fffb55fSDavid Gibson
fdt_node_offset_by_prop_value(const void * fdt,int startoffset,const char * propname,const void * propval,int proplen)6549fffb55fSDavid Gibson int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
6559fffb55fSDavid Gibson const char *propname,
6569fffb55fSDavid Gibson const void *propval, int proplen)
6579fffb55fSDavid Gibson {
6589fffb55fSDavid Gibson int offset;
6599fffb55fSDavid Gibson const void *val;
6609fffb55fSDavid Gibson int len;
6619fffb55fSDavid Gibson
662f858927fSRob Herring FDT_RO_PROBE(fdt);
6639fffb55fSDavid Gibson
6649fffb55fSDavid Gibson /* FIXME: The algorithm here is pretty horrible: we scan each
6659fffb55fSDavid Gibson * property of a node in fdt_getprop(), then if that didn't
6669fffb55fSDavid Gibson * find what we want, we scan over them again making our way
6679fffb55fSDavid Gibson * to the next node. Still it's the easiest to implement
6689fffb55fSDavid Gibson * approach; performance can come later. */
6699fffb55fSDavid Gibson for (offset = fdt_next_node(fdt, startoffset, NULL);
6709fffb55fSDavid Gibson offset >= 0;
6719fffb55fSDavid Gibson offset = fdt_next_node(fdt, offset, NULL)) {
6729fffb55fSDavid Gibson val = fdt_getprop(fdt, offset, propname, &len);
6739fffb55fSDavid Gibson if (val && (len == proplen)
6749fffb55fSDavid Gibson && (memcmp(val, propval, len) == 0))
6759fffb55fSDavid Gibson return offset;
6769fffb55fSDavid Gibson }
6779fffb55fSDavid Gibson
6789fffb55fSDavid Gibson return offset; /* error from fdt_next_node() */
6799fffb55fSDavid Gibson }
6809fffb55fSDavid Gibson
fdt_node_offset_by_phandle(const void * fdt,uint32_t phandle)6819fffb55fSDavid Gibson int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle)
6829fffb55fSDavid Gibson {
683cd296721SStephen Warren int offset;
684cd296721SStephen Warren
6856e9c9686SRob Herring if ((phandle == 0) || (phandle == ~0U))
6869fffb55fSDavid Gibson return -FDT_ERR_BADPHANDLE;
687cd296721SStephen Warren
688f858927fSRob Herring FDT_RO_PROBE(fdt);
689cd296721SStephen Warren
690cd296721SStephen Warren /* FIXME: The algorithm here is pretty horrible: we
691cd296721SStephen Warren * potentially scan each property of a node in
692cd296721SStephen Warren * fdt_get_phandle(), then if that didn't find what
693cd296721SStephen Warren * we want, we scan over them again making our way to the next
694cd296721SStephen Warren * node. Still it's the easiest to implement approach;
695cd296721SStephen Warren * performance can come later. */
696cd296721SStephen Warren for (offset = fdt_next_node(fdt, -1, NULL);
697cd296721SStephen Warren offset >= 0;
698cd296721SStephen Warren offset = fdt_next_node(fdt, offset, NULL)) {
699cd296721SStephen Warren if (fdt_get_phandle(fdt, offset) == phandle)
700cd296721SStephen Warren return offset;
7019fffb55fSDavid Gibson }
7029fffb55fSDavid Gibson
703cd296721SStephen Warren return offset; /* error from fdt_next_node() */
704cd296721SStephen Warren }
705cd296721SStephen Warren
fdt_stringlist_contains(const char * strlist,int listlen,const char * str)70647605971SRob Herring int fdt_stringlist_contains(const char *strlist, int listlen, const char *str)
7079fffb55fSDavid Gibson {
7089fffb55fSDavid Gibson int len = strlen(str);
7099fffb55fSDavid Gibson const char *p;
7109fffb55fSDavid Gibson
7119fffb55fSDavid Gibson while (listlen >= len) {
7129fffb55fSDavid Gibson if (memcmp(str, strlist, len+1) == 0)
7139fffb55fSDavid Gibson return 1;
7149fffb55fSDavid Gibson p = memchr(strlist, '\0', listlen);
7159fffb55fSDavid Gibson if (!p)
7169fffb55fSDavid Gibson return 0; /* malformed strlist.. */
7179fffb55fSDavid Gibson listlen -= (p-strlist) + 1;
7189fffb55fSDavid Gibson strlist = p + 1;
7199fffb55fSDavid Gibson }
7209fffb55fSDavid Gibson return 0;
7219fffb55fSDavid Gibson }
7229fffb55fSDavid Gibson
fdt_stringlist_count(const void * fdt,int nodeoffset,const char * property)72391feabc2SRob Herring int fdt_stringlist_count(const void *fdt, int nodeoffset, const char *property)
72491feabc2SRob Herring {
72591feabc2SRob Herring const char *list, *end;
72691feabc2SRob Herring int length, count = 0;
72791feabc2SRob Herring
72891feabc2SRob Herring list = fdt_getprop(fdt, nodeoffset, property, &length);
72991feabc2SRob Herring if (!list)
7306f05afcbSRob Herring return length;
73191feabc2SRob Herring
73291feabc2SRob Herring end = list + length;
73391feabc2SRob Herring
73491feabc2SRob Herring while (list < end) {
73591feabc2SRob Herring length = strnlen(list, end - list) + 1;
73691feabc2SRob Herring
73791feabc2SRob Herring /* Abort if the last string isn't properly NUL-terminated. */
73891feabc2SRob Herring if (list + length > end)
73991feabc2SRob Herring return -FDT_ERR_BADVALUE;
74091feabc2SRob Herring
74191feabc2SRob Herring list += length;
74291feabc2SRob Herring count++;
74391feabc2SRob Herring }
74491feabc2SRob Herring
74591feabc2SRob Herring return count;
74691feabc2SRob Herring }
74791feabc2SRob Herring
fdt_stringlist_search(const void * fdt,int nodeoffset,const char * property,const char * string)74891feabc2SRob Herring int fdt_stringlist_search(const void *fdt, int nodeoffset, const char *property,
74991feabc2SRob Herring const char *string)
75091feabc2SRob Herring {
75191feabc2SRob Herring int length, len, idx = 0;
75291feabc2SRob Herring const char *list, *end;
75391feabc2SRob Herring
75491feabc2SRob Herring list = fdt_getprop(fdt, nodeoffset, property, &length);
75591feabc2SRob Herring if (!list)
7566f05afcbSRob Herring return length;
75791feabc2SRob Herring
75891feabc2SRob Herring len = strlen(string) + 1;
75991feabc2SRob Herring end = list + length;
76091feabc2SRob Herring
76191feabc2SRob Herring while (list < end) {
76291feabc2SRob Herring length = strnlen(list, end - list) + 1;
76391feabc2SRob Herring
76491feabc2SRob Herring /* Abort if the last string isn't properly NUL-terminated. */
76591feabc2SRob Herring if (list + length > end)
76691feabc2SRob Herring return -FDT_ERR_BADVALUE;
76791feabc2SRob Herring
76891feabc2SRob Herring if (length == len && memcmp(list, string, length) == 0)
76991feabc2SRob Herring return idx;
77091feabc2SRob Herring
77191feabc2SRob Herring list += length;
77291feabc2SRob Herring idx++;
77391feabc2SRob Herring }
77491feabc2SRob Herring
77591feabc2SRob Herring return -FDT_ERR_NOTFOUND;
77691feabc2SRob Herring }
77791feabc2SRob Herring
fdt_stringlist_get(const void * fdt,int nodeoffset,const char * property,int idx,int * lenp)77891feabc2SRob Herring const char *fdt_stringlist_get(const void *fdt, int nodeoffset,
77991feabc2SRob Herring const char *property, int idx,
78091feabc2SRob Herring int *lenp)
78191feabc2SRob Herring {
78291feabc2SRob Herring const char *list, *end;
78391feabc2SRob Herring int length;
78491feabc2SRob Herring
78591feabc2SRob Herring list = fdt_getprop(fdt, nodeoffset, property, &length);
78691feabc2SRob Herring if (!list) {
78791feabc2SRob Herring if (lenp)
78891feabc2SRob Herring *lenp = length;
78991feabc2SRob Herring
79091feabc2SRob Herring return NULL;
79191feabc2SRob Herring }
79291feabc2SRob Herring
79391feabc2SRob Herring end = list + length;
79491feabc2SRob Herring
79591feabc2SRob Herring while (list < end) {
79691feabc2SRob Herring length = strnlen(list, end - list) + 1;
79791feabc2SRob Herring
79891feabc2SRob Herring /* Abort if the last string isn't properly NUL-terminated. */
79991feabc2SRob Herring if (list + length > end) {
80091feabc2SRob Herring if (lenp)
80191feabc2SRob Herring *lenp = -FDT_ERR_BADVALUE;
80291feabc2SRob Herring
80391feabc2SRob Herring return NULL;
80491feabc2SRob Herring }
80591feabc2SRob Herring
80691feabc2SRob Herring if (idx == 0) {
80791feabc2SRob Herring if (lenp)
80891feabc2SRob Herring *lenp = length - 1;
80991feabc2SRob Herring
81091feabc2SRob Herring return list;
81191feabc2SRob Herring }
81291feabc2SRob Herring
81391feabc2SRob Herring list += length;
81491feabc2SRob Herring idx--;
81591feabc2SRob Herring }
81691feabc2SRob Herring
81791feabc2SRob Herring if (lenp)
81891feabc2SRob Herring *lenp = -FDT_ERR_NOTFOUND;
81991feabc2SRob Herring
82091feabc2SRob Herring return NULL;
82191feabc2SRob Herring }
82291feabc2SRob Herring
fdt_node_check_compatible(const void * fdt,int nodeoffset,const char * compatible)8239fffb55fSDavid Gibson int fdt_node_check_compatible(const void *fdt, int nodeoffset,
8249fffb55fSDavid Gibson const char *compatible)
8259fffb55fSDavid Gibson {
8269fffb55fSDavid Gibson const void *prop;
8279fffb55fSDavid Gibson int len;
8289fffb55fSDavid Gibson
8299fffb55fSDavid Gibson prop = fdt_getprop(fdt, nodeoffset, "compatible", &len);
8309fffb55fSDavid Gibson if (!prop)
8319fffb55fSDavid Gibson return len;
832b9937347SRob Herring
833b9937347SRob Herring return !fdt_stringlist_contains(prop, len, compatible);
8349fffb55fSDavid Gibson }
8359fffb55fSDavid Gibson
fdt_node_offset_by_compatible(const void * fdt,int startoffset,const char * compatible)8369fffb55fSDavid Gibson int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
8379fffb55fSDavid Gibson const char *compatible)
8389fffb55fSDavid Gibson {
8399fffb55fSDavid Gibson int offset, err;
8409fffb55fSDavid Gibson
841f858927fSRob Herring FDT_RO_PROBE(fdt);
8429fffb55fSDavid Gibson
8439fffb55fSDavid Gibson /* FIXME: The algorithm here is pretty horrible: we scan each
8449fffb55fSDavid Gibson * property of a node in fdt_node_check_compatible(), then if
8459fffb55fSDavid Gibson * that didn't find what we want, we scan over them again
8469fffb55fSDavid Gibson * making our way to the next node. Still it's the easiest to
8479fffb55fSDavid Gibson * implement approach; performance can come later. */
8489fffb55fSDavid Gibson for (offset = fdt_next_node(fdt, startoffset, NULL);
8499fffb55fSDavid Gibson offset >= 0;
8509fffb55fSDavid Gibson offset = fdt_next_node(fdt, offset, NULL)) {
8519fffb55fSDavid Gibson err = fdt_node_check_compatible(fdt, offset, compatible);
8529fffb55fSDavid Gibson if ((err < 0) && (err != -FDT_ERR_NOTFOUND))
8539fffb55fSDavid Gibson return err;
8549fffb55fSDavid Gibson else if (err == 0)
8559fffb55fSDavid Gibson return offset;
8569fffb55fSDavid Gibson }
8579fffb55fSDavid Gibson
8589fffb55fSDavid Gibson return offset; /* error from fdt_next_node() */
8599fffb55fSDavid Gibson }
860