xref: /openbmc/linux/scripts/dtc/libfdt/fdt_ro.c (revision ea3723a5)
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