xref: /aosp_15_r20/external/dtc/libfdt/fdt_ro.c (revision cd60bc56d4bea3af4ec04523e4d71c2b272c8aff)
1*cd60bc56SAndroid Build Coastguard Worker // SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
2*cd60bc56SAndroid Build Coastguard Worker /*
3*cd60bc56SAndroid Build Coastguard Worker  * libfdt - Flat Device Tree manipulation
4*cd60bc56SAndroid Build Coastguard Worker  * Copyright (C) 2006 David Gibson, IBM Corporation.
5*cd60bc56SAndroid Build Coastguard Worker  */
6*cd60bc56SAndroid Build Coastguard Worker #include "libfdt_env.h"
7*cd60bc56SAndroid Build Coastguard Worker 
8*cd60bc56SAndroid Build Coastguard Worker #include <fdt.h>
9*cd60bc56SAndroid Build Coastguard Worker #include <libfdt.h>
10*cd60bc56SAndroid Build Coastguard Worker 
11*cd60bc56SAndroid Build Coastguard Worker #include "libfdt_internal.h"
12*cd60bc56SAndroid Build Coastguard Worker 
fdt_nodename_eq_(const void * fdt,int offset,const char * s,int len)13*cd60bc56SAndroid Build Coastguard Worker static int fdt_nodename_eq_(const void *fdt, int offset,
14*cd60bc56SAndroid Build Coastguard Worker 			    const char *s, int len)
15*cd60bc56SAndroid Build Coastguard Worker {
16*cd60bc56SAndroid Build Coastguard Worker 	int olen;
17*cd60bc56SAndroid Build Coastguard Worker 	const char *p = fdt_get_name(fdt, offset, &olen);
18*cd60bc56SAndroid Build Coastguard Worker 
19*cd60bc56SAndroid Build Coastguard Worker 	if (!p || olen < len)
20*cd60bc56SAndroid Build Coastguard Worker 		/* short match */
21*cd60bc56SAndroid Build Coastguard Worker 		return 0;
22*cd60bc56SAndroid Build Coastguard Worker 
23*cd60bc56SAndroid Build Coastguard Worker 	if (memcmp(p, s, len) != 0)
24*cd60bc56SAndroid Build Coastguard Worker 		return 0;
25*cd60bc56SAndroid Build Coastguard Worker 
26*cd60bc56SAndroid Build Coastguard Worker 	if (p[len] == '\0')
27*cd60bc56SAndroid Build Coastguard Worker 		return 1;
28*cd60bc56SAndroid Build Coastguard Worker 	else if (!memchr(s, '@', len) && (p[len] == '@'))
29*cd60bc56SAndroid Build Coastguard Worker 		return 1;
30*cd60bc56SAndroid Build Coastguard Worker 	else
31*cd60bc56SAndroid Build Coastguard Worker 		return 0;
32*cd60bc56SAndroid Build Coastguard Worker }
33*cd60bc56SAndroid Build Coastguard Worker 
fdt_get_string(const void * fdt,int stroffset,int * lenp)34*cd60bc56SAndroid Build Coastguard Worker const char *fdt_get_string(const void *fdt, int stroffset, int *lenp)
35*cd60bc56SAndroid Build Coastguard Worker {
36*cd60bc56SAndroid Build Coastguard Worker 	int32_t totalsize;
37*cd60bc56SAndroid Build Coastguard Worker 	uint32_t absoffset;
38*cd60bc56SAndroid Build Coastguard Worker 	size_t len;
39*cd60bc56SAndroid Build Coastguard Worker 	int err;
40*cd60bc56SAndroid Build Coastguard Worker 	const char *s, *n;
41*cd60bc56SAndroid Build Coastguard Worker 
42*cd60bc56SAndroid Build Coastguard Worker 	if (can_assume(VALID_INPUT)) {
43*cd60bc56SAndroid Build Coastguard Worker 		s = (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset;
44*cd60bc56SAndroid Build Coastguard Worker 
45*cd60bc56SAndroid Build Coastguard Worker 		if (lenp)
46*cd60bc56SAndroid Build Coastguard Worker 			*lenp = strlen(s);
47*cd60bc56SAndroid Build Coastguard Worker 		return s;
48*cd60bc56SAndroid Build Coastguard Worker 	}
49*cd60bc56SAndroid Build Coastguard Worker 	totalsize = fdt_ro_probe_(fdt);
50*cd60bc56SAndroid Build Coastguard Worker 	err = totalsize;
51*cd60bc56SAndroid Build Coastguard Worker 	if (totalsize < 0)
52*cd60bc56SAndroid Build Coastguard Worker 		goto fail;
53*cd60bc56SAndroid Build Coastguard Worker 
54*cd60bc56SAndroid Build Coastguard Worker 	err = -FDT_ERR_BADOFFSET;
55*cd60bc56SAndroid Build Coastguard Worker 	absoffset = stroffset + fdt_off_dt_strings(fdt);
56*cd60bc56SAndroid Build Coastguard Worker 	if (absoffset >= (unsigned)totalsize)
57*cd60bc56SAndroid Build Coastguard Worker 		goto fail;
58*cd60bc56SAndroid Build Coastguard Worker 	len = totalsize - absoffset;
59*cd60bc56SAndroid Build Coastguard Worker 
60*cd60bc56SAndroid Build Coastguard Worker 	if (fdt_magic(fdt) == FDT_MAGIC) {
61*cd60bc56SAndroid Build Coastguard Worker 		if (stroffset < 0)
62*cd60bc56SAndroid Build Coastguard Worker 			goto fail;
63*cd60bc56SAndroid Build Coastguard Worker 		if (can_assume(LATEST) || fdt_version(fdt) >= 17) {
64*cd60bc56SAndroid Build Coastguard Worker 			if ((unsigned)stroffset >= fdt_size_dt_strings(fdt))
65*cd60bc56SAndroid Build Coastguard Worker 				goto fail;
66*cd60bc56SAndroid Build Coastguard Worker 			if ((fdt_size_dt_strings(fdt) - stroffset) < len)
67*cd60bc56SAndroid Build Coastguard Worker 				len = fdt_size_dt_strings(fdt) - stroffset;
68*cd60bc56SAndroid Build Coastguard Worker 		}
69*cd60bc56SAndroid Build Coastguard Worker 	} else if (fdt_magic(fdt) == FDT_SW_MAGIC) {
70*cd60bc56SAndroid Build Coastguard Worker 		unsigned int sw_stroffset = -stroffset;
71*cd60bc56SAndroid Build Coastguard Worker 
72*cd60bc56SAndroid Build Coastguard Worker 		if ((stroffset >= 0) ||
73*cd60bc56SAndroid Build Coastguard Worker 		    (sw_stroffset > fdt_size_dt_strings(fdt)))
74*cd60bc56SAndroid Build Coastguard Worker 			goto fail;
75*cd60bc56SAndroid Build Coastguard Worker 		if (sw_stroffset < len)
76*cd60bc56SAndroid Build Coastguard Worker 			len = sw_stroffset;
77*cd60bc56SAndroid Build Coastguard Worker 	} else {
78*cd60bc56SAndroid Build Coastguard Worker 		err = -FDT_ERR_INTERNAL;
79*cd60bc56SAndroid Build Coastguard Worker 		goto fail;
80*cd60bc56SAndroid Build Coastguard Worker 	}
81*cd60bc56SAndroid Build Coastguard Worker 
82*cd60bc56SAndroid Build Coastguard Worker 	s = (const char *)fdt + absoffset;
83*cd60bc56SAndroid Build Coastguard Worker 	n = memchr(s, '\0', len);
84*cd60bc56SAndroid Build Coastguard Worker 	if (!n) {
85*cd60bc56SAndroid Build Coastguard Worker 		/* missing terminating NULL */
86*cd60bc56SAndroid Build Coastguard Worker 		err = -FDT_ERR_TRUNCATED;
87*cd60bc56SAndroid Build Coastguard Worker 		goto fail;
88*cd60bc56SAndroid Build Coastguard Worker 	}
89*cd60bc56SAndroid Build Coastguard Worker 
90*cd60bc56SAndroid Build Coastguard Worker 	if (lenp)
91*cd60bc56SAndroid Build Coastguard Worker 		*lenp = n - s;
92*cd60bc56SAndroid Build Coastguard Worker 	return s;
93*cd60bc56SAndroid Build Coastguard Worker 
94*cd60bc56SAndroid Build Coastguard Worker fail:
95*cd60bc56SAndroid Build Coastguard Worker 	if (lenp)
96*cd60bc56SAndroid Build Coastguard Worker 		*lenp = err;
97*cd60bc56SAndroid Build Coastguard Worker 	return NULL;
98*cd60bc56SAndroid Build Coastguard Worker }
99*cd60bc56SAndroid Build Coastguard Worker 
fdt_string(const void * fdt,int stroffset)100*cd60bc56SAndroid Build Coastguard Worker const char *fdt_string(const void *fdt, int stroffset)
101*cd60bc56SAndroid Build Coastguard Worker {
102*cd60bc56SAndroid Build Coastguard Worker 	return fdt_get_string(fdt, stroffset, NULL);
103*cd60bc56SAndroid Build Coastguard Worker }
104*cd60bc56SAndroid Build Coastguard Worker 
fdt_string_eq_(const void * fdt,int stroffset,const char * s,int len)105*cd60bc56SAndroid Build Coastguard Worker static int fdt_string_eq_(const void *fdt, int stroffset,
106*cd60bc56SAndroid Build Coastguard Worker 			  const char *s, int len)
107*cd60bc56SAndroid Build Coastguard Worker {
108*cd60bc56SAndroid Build Coastguard Worker 	int slen;
109*cd60bc56SAndroid Build Coastguard Worker 	const char *p = fdt_get_string(fdt, stroffset, &slen);
110*cd60bc56SAndroid Build Coastguard Worker 
111*cd60bc56SAndroid Build Coastguard Worker 	return p && (slen == len) && (memcmp(p, s, len) == 0);
112*cd60bc56SAndroid Build Coastguard Worker }
113*cd60bc56SAndroid Build Coastguard Worker 
fdt_find_max_phandle(const void * fdt,uint32_t * phandle)114*cd60bc56SAndroid Build Coastguard Worker int fdt_find_max_phandle(const void *fdt, uint32_t *phandle)
115*cd60bc56SAndroid Build Coastguard Worker {
116*cd60bc56SAndroid Build Coastguard Worker 	uint32_t max = 0;
117*cd60bc56SAndroid Build Coastguard Worker 	int offset = -1;
118*cd60bc56SAndroid Build Coastguard Worker 
119*cd60bc56SAndroid Build Coastguard Worker 	while (true) {
120*cd60bc56SAndroid Build Coastguard Worker 		uint32_t value;
121*cd60bc56SAndroid Build Coastguard Worker 
122*cd60bc56SAndroid Build Coastguard Worker 		offset = fdt_next_node(fdt, offset, NULL);
123*cd60bc56SAndroid Build Coastguard Worker 		if (offset < 0) {
124*cd60bc56SAndroid Build Coastguard Worker 			if (offset == -FDT_ERR_NOTFOUND)
125*cd60bc56SAndroid Build Coastguard Worker 				break;
126*cd60bc56SAndroid Build Coastguard Worker 
127*cd60bc56SAndroid Build Coastguard Worker 			return offset;
128*cd60bc56SAndroid Build Coastguard Worker 		}
129*cd60bc56SAndroid Build Coastguard Worker 
130*cd60bc56SAndroid Build Coastguard Worker 		value = fdt_get_phandle(fdt, offset);
131*cd60bc56SAndroid Build Coastguard Worker 
132*cd60bc56SAndroid Build Coastguard Worker 		if (value > max)
133*cd60bc56SAndroid Build Coastguard Worker 			max = value;
134*cd60bc56SAndroid Build Coastguard Worker 	}
135*cd60bc56SAndroid Build Coastguard Worker 
136*cd60bc56SAndroid Build Coastguard Worker 	if (phandle)
137*cd60bc56SAndroid Build Coastguard Worker 		*phandle = max;
138*cd60bc56SAndroid Build Coastguard Worker 
139*cd60bc56SAndroid Build Coastguard Worker 	return 0;
140*cd60bc56SAndroid Build Coastguard Worker }
141*cd60bc56SAndroid Build Coastguard Worker 
fdt_generate_phandle(const void * fdt,uint32_t * phandle)142*cd60bc56SAndroid Build Coastguard Worker int fdt_generate_phandle(const void *fdt, uint32_t *phandle)
143*cd60bc56SAndroid Build Coastguard Worker {
144*cd60bc56SAndroid Build Coastguard Worker 	uint32_t max;
145*cd60bc56SAndroid Build Coastguard Worker 	int err;
146*cd60bc56SAndroid Build Coastguard Worker 
147*cd60bc56SAndroid Build Coastguard Worker 	err = fdt_find_max_phandle(fdt, &max);
148*cd60bc56SAndroid Build Coastguard Worker 	if (err < 0)
149*cd60bc56SAndroid Build Coastguard Worker 		return err;
150*cd60bc56SAndroid Build Coastguard Worker 
151*cd60bc56SAndroid Build Coastguard Worker 	if (max == FDT_MAX_PHANDLE)
152*cd60bc56SAndroid Build Coastguard Worker 		return -FDT_ERR_NOPHANDLES;
153*cd60bc56SAndroid Build Coastguard Worker 
154*cd60bc56SAndroid Build Coastguard Worker 	if (phandle)
155*cd60bc56SAndroid Build Coastguard Worker 		*phandle = max + 1;
156*cd60bc56SAndroid Build Coastguard Worker 
157*cd60bc56SAndroid Build Coastguard Worker 	return 0;
158*cd60bc56SAndroid Build Coastguard Worker }
159*cd60bc56SAndroid Build Coastguard Worker 
fdt_mem_rsv(const void * fdt,int n)160*cd60bc56SAndroid Build Coastguard Worker static const struct fdt_reserve_entry *fdt_mem_rsv(const void *fdt, int n)
161*cd60bc56SAndroid Build Coastguard Worker {
162*cd60bc56SAndroid Build Coastguard Worker 	unsigned int offset = n * sizeof(struct fdt_reserve_entry);
163*cd60bc56SAndroid Build Coastguard Worker 	unsigned int absoffset = fdt_off_mem_rsvmap(fdt) + offset;
164*cd60bc56SAndroid Build Coastguard Worker 
165*cd60bc56SAndroid Build Coastguard Worker 	if (!can_assume(VALID_INPUT)) {
166*cd60bc56SAndroid Build Coastguard Worker 		if (absoffset < fdt_off_mem_rsvmap(fdt))
167*cd60bc56SAndroid Build Coastguard Worker 			return NULL;
168*cd60bc56SAndroid Build Coastguard Worker 		if (absoffset > fdt_totalsize(fdt) -
169*cd60bc56SAndroid Build Coastguard Worker 		    sizeof(struct fdt_reserve_entry))
170*cd60bc56SAndroid Build Coastguard Worker 			return NULL;
171*cd60bc56SAndroid Build Coastguard Worker 	}
172*cd60bc56SAndroid Build Coastguard Worker 	return fdt_mem_rsv_(fdt, n);
173*cd60bc56SAndroid Build Coastguard Worker }
174*cd60bc56SAndroid Build Coastguard Worker 
fdt_get_mem_rsv(const void * fdt,int n,uint64_t * address,uint64_t * size)175*cd60bc56SAndroid Build Coastguard Worker int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
176*cd60bc56SAndroid Build Coastguard Worker {
177*cd60bc56SAndroid Build Coastguard Worker 	const struct fdt_reserve_entry *re;
178*cd60bc56SAndroid Build Coastguard Worker 
179*cd60bc56SAndroid Build Coastguard Worker 	FDT_RO_PROBE(fdt);
180*cd60bc56SAndroid Build Coastguard Worker 	re = fdt_mem_rsv(fdt, n);
181*cd60bc56SAndroid Build Coastguard Worker 	if (!can_assume(VALID_INPUT) && !re)
182*cd60bc56SAndroid Build Coastguard Worker 		return -FDT_ERR_BADOFFSET;
183*cd60bc56SAndroid Build Coastguard Worker 
184*cd60bc56SAndroid Build Coastguard Worker 	*address = fdt64_ld_(&re->address);
185*cd60bc56SAndroid Build Coastguard Worker 	*size = fdt64_ld_(&re->size);
186*cd60bc56SAndroid Build Coastguard Worker 	return 0;
187*cd60bc56SAndroid Build Coastguard Worker }
188*cd60bc56SAndroid Build Coastguard Worker 
fdt_num_mem_rsv(const void * fdt)189*cd60bc56SAndroid Build Coastguard Worker int fdt_num_mem_rsv(const void *fdt)
190*cd60bc56SAndroid Build Coastguard Worker {
191*cd60bc56SAndroid Build Coastguard Worker 	int i;
192*cd60bc56SAndroid Build Coastguard Worker 	const struct fdt_reserve_entry *re;
193*cd60bc56SAndroid Build Coastguard Worker 
194*cd60bc56SAndroid Build Coastguard Worker 	for (i = 0; (re = fdt_mem_rsv(fdt, i)) != NULL; i++) {
195*cd60bc56SAndroid Build Coastguard Worker 		if (fdt64_ld_(&re->size) == 0)
196*cd60bc56SAndroid Build Coastguard Worker 			return i;
197*cd60bc56SAndroid Build Coastguard Worker 	}
198*cd60bc56SAndroid Build Coastguard Worker 	return -FDT_ERR_TRUNCATED;
199*cd60bc56SAndroid Build Coastguard Worker }
200*cd60bc56SAndroid Build Coastguard Worker 
nextprop_(const void * fdt,int offset)201*cd60bc56SAndroid Build Coastguard Worker static int nextprop_(const void *fdt, int offset)
202*cd60bc56SAndroid Build Coastguard Worker {
203*cd60bc56SAndroid Build Coastguard Worker 	uint32_t tag;
204*cd60bc56SAndroid Build Coastguard Worker 	int nextoffset;
205*cd60bc56SAndroid Build Coastguard Worker 
206*cd60bc56SAndroid Build Coastguard Worker 	do {
207*cd60bc56SAndroid Build Coastguard Worker 		tag = fdt_next_tag(fdt, offset, &nextoffset);
208*cd60bc56SAndroid Build Coastguard Worker 
209*cd60bc56SAndroid Build Coastguard Worker 		switch (tag) {
210*cd60bc56SAndroid Build Coastguard Worker 		case FDT_END:
211*cd60bc56SAndroid Build Coastguard Worker 			if (nextoffset >= 0)
212*cd60bc56SAndroid Build Coastguard Worker 				return -FDT_ERR_BADSTRUCTURE;
213*cd60bc56SAndroid Build Coastguard Worker 			else
214*cd60bc56SAndroid Build Coastguard Worker 				return nextoffset;
215*cd60bc56SAndroid Build Coastguard Worker 
216*cd60bc56SAndroid Build Coastguard Worker 		case FDT_PROP:
217*cd60bc56SAndroid Build Coastguard Worker 			return offset;
218*cd60bc56SAndroid Build Coastguard Worker 		}
219*cd60bc56SAndroid Build Coastguard Worker 		offset = nextoffset;
220*cd60bc56SAndroid Build Coastguard Worker 	} while (tag == FDT_NOP);
221*cd60bc56SAndroid Build Coastguard Worker 
222*cd60bc56SAndroid Build Coastguard Worker 	return -FDT_ERR_NOTFOUND;
223*cd60bc56SAndroid Build Coastguard Worker }
224*cd60bc56SAndroid Build Coastguard Worker 
fdt_subnode_offset_namelen(const void * fdt,int offset,const char * name,int namelen)225*cd60bc56SAndroid Build Coastguard Worker int fdt_subnode_offset_namelen(const void *fdt, int offset,
226*cd60bc56SAndroid Build Coastguard Worker 			       const char *name, int namelen)
227*cd60bc56SAndroid Build Coastguard Worker {
228*cd60bc56SAndroid Build Coastguard Worker 	int depth;
229*cd60bc56SAndroid Build Coastguard Worker 
230*cd60bc56SAndroid Build Coastguard Worker 	FDT_RO_PROBE(fdt);
231*cd60bc56SAndroid Build Coastguard Worker 
232*cd60bc56SAndroid Build Coastguard Worker 	for (depth = 0;
233*cd60bc56SAndroid Build Coastguard Worker 	     (offset >= 0) && (depth >= 0);
234*cd60bc56SAndroid Build Coastguard Worker 	     offset = fdt_next_node(fdt, offset, &depth))
235*cd60bc56SAndroid Build Coastguard Worker 		if ((depth == 1)
236*cd60bc56SAndroid Build Coastguard Worker 		    && fdt_nodename_eq_(fdt, offset, name, namelen))
237*cd60bc56SAndroid Build Coastguard Worker 			return offset;
238*cd60bc56SAndroid Build Coastguard Worker 
239*cd60bc56SAndroid Build Coastguard Worker 	if (depth < 0)
240*cd60bc56SAndroid Build Coastguard Worker 		return -FDT_ERR_NOTFOUND;
241*cd60bc56SAndroid Build Coastguard Worker 	return offset; /* error */
242*cd60bc56SAndroid Build Coastguard Worker }
243*cd60bc56SAndroid Build Coastguard Worker 
fdt_subnode_offset(const void * fdt,int parentoffset,const char * name)244*cd60bc56SAndroid Build Coastguard Worker int fdt_subnode_offset(const void *fdt, int parentoffset,
245*cd60bc56SAndroid Build Coastguard Worker 		       const char *name)
246*cd60bc56SAndroid Build Coastguard Worker {
247*cd60bc56SAndroid Build Coastguard Worker 	return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name));
248*cd60bc56SAndroid Build Coastguard Worker }
249*cd60bc56SAndroid Build Coastguard Worker 
fdt_path_offset_namelen(const void * fdt,const char * path,int namelen)250*cd60bc56SAndroid Build Coastguard Worker int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen)
251*cd60bc56SAndroid Build Coastguard Worker {
252*cd60bc56SAndroid Build Coastguard Worker 	const char *end = path + namelen;
253*cd60bc56SAndroid Build Coastguard Worker 	const char *p = path;
254*cd60bc56SAndroid Build Coastguard Worker 	int offset = 0;
255*cd60bc56SAndroid Build Coastguard Worker 
256*cd60bc56SAndroid Build Coastguard Worker 	FDT_RO_PROBE(fdt);
257*cd60bc56SAndroid Build Coastguard Worker 
258*cd60bc56SAndroid Build Coastguard Worker 	if (!can_assume(VALID_INPUT) && namelen <= 0)
259*cd60bc56SAndroid Build Coastguard Worker 		return -FDT_ERR_BADPATH;
260*cd60bc56SAndroid Build Coastguard Worker 
261*cd60bc56SAndroid Build Coastguard Worker 	/* see if we have an alias */
262*cd60bc56SAndroid Build Coastguard Worker 	if (*path != '/') {
263*cd60bc56SAndroid Build Coastguard Worker 		const char *q = memchr(path, '/', end - p);
264*cd60bc56SAndroid Build Coastguard Worker 
265*cd60bc56SAndroid Build Coastguard Worker 		if (!q)
266*cd60bc56SAndroid Build Coastguard Worker 			q = end;
267*cd60bc56SAndroid Build Coastguard Worker 
268*cd60bc56SAndroid Build Coastguard Worker 		p = fdt_get_alias_namelen(fdt, p, q - p);
269*cd60bc56SAndroid Build Coastguard Worker 		if (!p)
270*cd60bc56SAndroid Build Coastguard Worker 			return -FDT_ERR_BADPATH;
271*cd60bc56SAndroid Build Coastguard Worker 		offset = fdt_path_offset(fdt, p);
272*cd60bc56SAndroid Build Coastguard Worker 
273*cd60bc56SAndroid Build Coastguard Worker 		p = q;
274*cd60bc56SAndroid Build Coastguard Worker 	}
275*cd60bc56SAndroid Build Coastguard Worker 
276*cd60bc56SAndroid Build Coastguard Worker 	while (p < end) {
277*cd60bc56SAndroid Build Coastguard Worker 		const char *q;
278*cd60bc56SAndroid Build Coastguard Worker 
279*cd60bc56SAndroid Build Coastguard Worker 		while (*p == '/') {
280*cd60bc56SAndroid Build Coastguard Worker 			p++;
281*cd60bc56SAndroid Build Coastguard Worker 			if (p == end)
282*cd60bc56SAndroid Build Coastguard Worker 				return offset;
283*cd60bc56SAndroid Build Coastguard Worker 		}
284*cd60bc56SAndroid Build Coastguard Worker 		q = memchr(p, '/', end - p);
285*cd60bc56SAndroid Build Coastguard Worker 		if (! q)
286*cd60bc56SAndroid Build Coastguard Worker 			q = end;
287*cd60bc56SAndroid Build Coastguard Worker 
288*cd60bc56SAndroid Build Coastguard Worker 		offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p);
289*cd60bc56SAndroid Build Coastguard Worker 		if (offset < 0)
290*cd60bc56SAndroid Build Coastguard Worker 			return offset;
291*cd60bc56SAndroid Build Coastguard Worker 
292*cd60bc56SAndroid Build Coastguard Worker 		p = q;
293*cd60bc56SAndroid Build Coastguard Worker 	}
294*cd60bc56SAndroid Build Coastguard Worker 
295*cd60bc56SAndroid Build Coastguard Worker 	return offset;
296*cd60bc56SAndroid Build Coastguard Worker }
297*cd60bc56SAndroid Build Coastguard Worker 
fdt_path_offset(const void * fdt,const char * path)298*cd60bc56SAndroid Build Coastguard Worker int fdt_path_offset(const void *fdt, const char *path)
299*cd60bc56SAndroid Build Coastguard Worker {
300*cd60bc56SAndroid Build Coastguard Worker 	return fdt_path_offset_namelen(fdt, path, strlen(path));
301*cd60bc56SAndroid Build Coastguard Worker }
302*cd60bc56SAndroid Build Coastguard Worker 
fdt_get_name(const void * fdt,int nodeoffset,int * len)303*cd60bc56SAndroid Build Coastguard Worker const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
304*cd60bc56SAndroid Build Coastguard Worker {
305*cd60bc56SAndroid Build Coastguard Worker 	const struct fdt_node_header *nh = fdt_offset_ptr_(fdt, nodeoffset);
306*cd60bc56SAndroid Build Coastguard Worker 	const char *nameptr;
307*cd60bc56SAndroid Build Coastguard Worker 	int err;
308*cd60bc56SAndroid Build Coastguard Worker 
309*cd60bc56SAndroid Build Coastguard Worker 	if (((err = fdt_ro_probe_(fdt)) < 0)
310*cd60bc56SAndroid Build Coastguard Worker 	    || ((err = fdt_check_node_offset_(fdt, nodeoffset)) < 0))
311*cd60bc56SAndroid Build Coastguard Worker 			goto fail;
312*cd60bc56SAndroid Build Coastguard Worker 
313*cd60bc56SAndroid Build Coastguard Worker 	nameptr = nh->name;
314*cd60bc56SAndroid Build Coastguard Worker 
315*cd60bc56SAndroid Build Coastguard Worker 	if (!can_assume(LATEST) && fdt_version(fdt) < 0x10) {
316*cd60bc56SAndroid Build Coastguard Worker 		/*
317*cd60bc56SAndroid Build Coastguard Worker 		 * For old FDT versions, match the naming conventions of V16:
318*cd60bc56SAndroid Build Coastguard Worker 		 * give only the leaf name (after all /). The actual tree
319*cd60bc56SAndroid Build Coastguard Worker 		 * contents are loosely checked.
320*cd60bc56SAndroid Build Coastguard Worker 		 */
321*cd60bc56SAndroid Build Coastguard Worker 		const char *leaf;
322*cd60bc56SAndroid Build Coastguard Worker 		leaf = strrchr(nameptr, '/');
323*cd60bc56SAndroid Build Coastguard Worker 		if (leaf == NULL) {
324*cd60bc56SAndroid Build Coastguard Worker 			err = -FDT_ERR_BADSTRUCTURE;
325*cd60bc56SAndroid Build Coastguard Worker 			goto fail;
326*cd60bc56SAndroid Build Coastguard Worker 		}
327*cd60bc56SAndroid Build Coastguard Worker 		nameptr = leaf+1;
328*cd60bc56SAndroid Build Coastguard Worker 	}
329*cd60bc56SAndroid Build Coastguard Worker 
330*cd60bc56SAndroid Build Coastguard Worker 	if (len)
331*cd60bc56SAndroid Build Coastguard Worker 		*len = strlen(nameptr);
332*cd60bc56SAndroid Build Coastguard Worker 
333*cd60bc56SAndroid Build Coastguard Worker 	return nameptr;
334*cd60bc56SAndroid Build Coastguard Worker 
335*cd60bc56SAndroid Build Coastguard Worker  fail:
336*cd60bc56SAndroid Build Coastguard Worker 	if (len)
337*cd60bc56SAndroid Build Coastguard Worker 		*len = err;
338*cd60bc56SAndroid Build Coastguard Worker 	return NULL;
339*cd60bc56SAndroid Build Coastguard Worker }
340*cd60bc56SAndroid Build Coastguard Worker 
fdt_first_property_offset(const void * fdt,int nodeoffset)341*cd60bc56SAndroid Build Coastguard Worker int fdt_first_property_offset(const void *fdt, int nodeoffset)
342*cd60bc56SAndroid Build Coastguard Worker {
343*cd60bc56SAndroid Build Coastguard Worker 	int offset;
344*cd60bc56SAndroid Build Coastguard Worker 
345*cd60bc56SAndroid Build Coastguard Worker 	if ((offset = fdt_check_node_offset_(fdt, nodeoffset)) < 0)
346*cd60bc56SAndroid Build Coastguard Worker 		return offset;
347*cd60bc56SAndroid Build Coastguard Worker 
348*cd60bc56SAndroid Build Coastguard Worker 	return nextprop_(fdt, offset);
349*cd60bc56SAndroid Build Coastguard Worker }
350*cd60bc56SAndroid Build Coastguard Worker 
fdt_next_property_offset(const void * fdt,int offset)351*cd60bc56SAndroid Build Coastguard Worker int fdt_next_property_offset(const void *fdt, int offset)
352*cd60bc56SAndroid Build Coastguard Worker {
353*cd60bc56SAndroid Build Coastguard Worker 	if ((offset = fdt_check_prop_offset_(fdt, offset)) < 0)
354*cd60bc56SAndroid Build Coastguard Worker 		return offset;
355*cd60bc56SAndroid Build Coastguard Worker 
356*cd60bc56SAndroid Build Coastguard Worker 	return nextprop_(fdt, offset);
357*cd60bc56SAndroid Build Coastguard Worker }
358*cd60bc56SAndroid Build Coastguard Worker 
fdt_get_property_by_offset_(const void * fdt,int offset,int * lenp)359*cd60bc56SAndroid Build Coastguard Worker static const struct fdt_property *fdt_get_property_by_offset_(const void *fdt,
360*cd60bc56SAndroid Build Coastguard Worker 						              int offset,
361*cd60bc56SAndroid Build Coastguard Worker 						              int *lenp)
362*cd60bc56SAndroid Build Coastguard Worker {
363*cd60bc56SAndroid Build Coastguard Worker 	int err;
364*cd60bc56SAndroid Build Coastguard Worker 	const struct fdt_property *prop;
365*cd60bc56SAndroid Build Coastguard Worker 
366*cd60bc56SAndroid Build Coastguard Worker 	if (!can_assume(VALID_INPUT) &&
367*cd60bc56SAndroid Build Coastguard Worker 	    (err = fdt_check_prop_offset_(fdt, offset)) < 0) {
368*cd60bc56SAndroid Build Coastguard Worker 		if (lenp)
369*cd60bc56SAndroid Build Coastguard Worker 			*lenp = err;
370*cd60bc56SAndroid Build Coastguard Worker 		return NULL;
371*cd60bc56SAndroid Build Coastguard Worker 	}
372*cd60bc56SAndroid Build Coastguard Worker 
373*cd60bc56SAndroid Build Coastguard Worker 	prop = fdt_offset_ptr_(fdt, offset);
374*cd60bc56SAndroid Build Coastguard Worker 
375*cd60bc56SAndroid Build Coastguard Worker 	if (lenp)
376*cd60bc56SAndroid Build Coastguard Worker 		*lenp = fdt32_ld_(&prop->len);
377*cd60bc56SAndroid Build Coastguard Worker 
378*cd60bc56SAndroid Build Coastguard Worker 	return prop;
379*cd60bc56SAndroid Build Coastguard Worker }
380*cd60bc56SAndroid Build Coastguard Worker 
fdt_get_property_by_offset(const void * fdt,int offset,int * lenp)381*cd60bc56SAndroid Build Coastguard Worker const struct fdt_property *fdt_get_property_by_offset(const void *fdt,
382*cd60bc56SAndroid Build Coastguard Worker 						      int offset,
383*cd60bc56SAndroid Build Coastguard Worker 						      int *lenp)
384*cd60bc56SAndroid Build Coastguard Worker {
385*cd60bc56SAndroid Build Coastguard Worker 	/* Prior to version 16, properties may need realignment
386*cd60bc56SAndroid Build Coastguard Worker 	 * and this API does not work. fdt_getprop_*() will, however. */
387*cd60bc56SAndroid Build Coastguard Worker 
388*cd60bc56SAndroid Build Coastguard Worker 	if (!can_assume(LATEST) && fdt_version(fdt) < 0x10) {
389*cd60bc56SAndroid Build Coastguard Worker 		if (lenp)
390*cd60bc56SAndroid Build Coastguard Worker 			*lenp = -FDT_ERR_BADVERSION;
391*cd60bc56SAndroid Build Coastguard Worker 		return NULL;
392*cd60bc56SAndroid Build Coastguard Worker 	}
393*cd60bc56SAndroid Build Coastguard Worker 
394*cd60bc56SAndroid Build Coastguard Worker 	return fdt_get_property_by_offset_(fdt, offset, lenp);
395*cd60bc56SAndroid Build Coastguard Worker }
396*cd60bc56SAndroid Build Coastguard Worker 
fdt_get_property_namelen_(const void * fdt,int offset,const char * name,int namelen,int * lenp,int * poffset)397*cd60bc56SAndroid Build Coastguard Worker static const struct fdt_property *fdt_get_property_namelen_(const void *fdt,
398*cd60bc56SAndroid Build Coastguard Worker 						            int offset,
399*cd60bc56SAndroid Build Coastguard Worker 						            const char *name,
400*cd60bc56SAndroid Build Coastguard Worker 						            int namelen,
401*cd60bc56SAndroid Build Coastguard Worker 							    int *lenp,
402*cd60bc56SAndroid Build Coastguard Worker 							    int *poffset)
403*cd60bc56SAndroid Build Coastguard Worker {
404*cd60bc56SAndroid Build Coastguard Worker 	for (offset = fdt_first_property_offset(fdt, offset);
405*cd60bc56SAndroid Build Coastguard Worker 	     (offset >= 0);
406*cd60bc56SAndroid Build Coastguard Worker 	     (offset = fdt_next_property_offset(fdt, offset))) {
407*cd60bc56SAndroid Build Coastguard Worker 		const struct fdt_property *prop;
408*cd60bc56SAndroid Build Coastguard Worker 
409*cd60bc56SAndroid Build Coastguard Worker 		prop = fdt_get_property_by_offset_(fdt, offset, lenp);
410*cd60bc56SAndroid Build Coastguard Worker 		if (!can_assume(LIBFDT_FLAWLESS) && !prop) {
411*cd60bc56SAndroid Build Coastguard Worker 			offset = -FDT_ERR_INTERNAL;
412*cd60bc56SAndroid Build Coastguard Worker 			break;
413*cd60bc56SAndroid Build Coastguard Worker 		}
414*cd60bc56SAndroid Build Coastguard Worker 		if (fdt_string_eq_(fdt, fdt32_ld_(&prop->nameoff),
415*cd60bc56SAndroid Build Coastguard Worker 				   name, namelen)) {
416*cd60bc56SAndroid Build Coastguard Worker 			if (poffset)
417*cd60bc56SAndroid Build Coastguard Worker 				*poffset = offset;
418*cd60bc56SAndroid Build Coastguard Worker 			return prop;
419*cd60bc56SAndroid Build Coastguard Worker 		}
420*cd60bc56SAndroid Build Coastguard Worker 	}
421*cd60bc56SAndroid Build Coastguard Worker 
422*cd60bc56SAndroid Build Coastguard Worker 	if (lenp)
423*cd60bc56SAndroid Build Coastguard Worker 		*lenp = offset;
424*cd60bc56SAndroid Build Coastguard Worker 	return NULL;
425*cd60bc56SAndroid Build Coastguard Worker }
426*cd60bc56SAndroid Build Coastguard Worker 
427*cd60bc56SAndroid Build Coastguard Worker 
fdt_get_property_namelen(const void * fdt,int offset,const char * name,int namelen,int * lenp)428*cd60bc56SAndroid Build Coastguard Worker const struct fdt_property *fdt_get_property_namelen(const void *fdt,
429*cd60bc56SAndroid Build Coastguard Worker 						    int offset,
430*cd60bc56SAndroid Build Coastguard Worker 						    const char *name,
431*cd60bc56SAndroid Build Coastguard Worker 						    int namelen, int *lenp)
432*cd60bc56SAndroid Build Coastguard Worker {
433*cd60bc56SAndroid Build Coastguard Worker 	/* Prior to version 16, properties may need realignment
434*cd60bc56SAndroid Build Coastguard Worker 	 * and this API does not work. fdt_getprop_*() will, however. */
435*cd60bc56SAndroid Build Coastguard Worker 	if (!can_assume(LATEST) && fdt_version(fdt) < 0x10) {
436*cd60bc56SAndroid Build Coastguard Worker 		if (lenp)
437*cd60bc56SAndroid Build Coastguard Worker 			*lenp = -FDT_ERR_BADVERSION;
438*cd60bc56SAndroid Build Coastguard Worker 		return NULL;
439*cd60bc56SAndroid Build Coastguard Worker 	}
440*cd60bc56SAndroid Build Coastguard Worker 
441*cd60bc56SAndroid Build Coastguard Worker 	return fdt_get_property_namelen_(fdt, offset, name, namelen, lenp,
442*cd60bc56SAndroid Build Coastguard Worker 					 NULL);
443*cd60bc56SAndroid Build Coastguard Worker }
444*cd60bc56SAndroid Build Coastguard Worker 
445*cd60bc56SAndroid Build Coastguard Worker 
fdt_get_property(const void * fdt,int nodeoffset,const char * name,int * lenp)446*cd60bc56SAndroid Build Coastguard Worker const struct fdt_property *fdt_get_property(const void *fdt,
447*cd60bc56SAndroid Build Coastguard Worker 					    int nodeoffset,
448*cd60bc56SAndroid Build Coastguard Worker 					    const char *name, int *lenp)
449*cd60bc56SAndroid Build Coastguard Worker {
450*cd60bc56SAndroid Build Coastguard Worker 	return fdt_get_property_namelen(fdt, nodeoffset, name,
451*cd60bc56SAndroid Build Coastguard Worker 					strlen(name), lenp);
452*cd60bc56SAndroid Build Coastguard Worker }
453*cd60bc56SAndroid Build Coastguard Worker 
fdt_getprop_namelen(const void * fdt,int nodeoffset,const char * name,int namelen,int * lenp)454*cd60bc56SAndroid Build Coastguard Worker const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
455*cd60bc56SAndroid Build Coastguard Worker 				const char *name, int namelen, int *lenp)
456*cd60bc56SAndroid Build Coastguard Worker {
457*cd60bc56SAndroid Build Coastguard Worker 	int poffset;
458*cd60bc56SAndroid Build Coastguard Worker 	const struct fdt_property *prop;
459*cd60bc56SAndroid Build Coastguard Worker 
460*cd60bc56SAndroid Build Coastguard Worker 	prop = fdt_get_property_namelen_(fdt, nodeoffset, name, namelen, lenp,
461*cd60bc56SAndroid Build Coastguard Worker 					 &poffset);
462*cd60bc56SAndroid Build Coastguard Worker 	if (!prop)
463*cd60bc56SAndroid Build Coastguard Worker 		return NULL;
464*cd60bc56SAndroid Build Coastguard Worker 
465*cd60bc56SAndroid Build Coastguard Worker 	/* Handle realignment */
466*cd60bc56SAndroid Build Coastguard Worker 	if (!can_assume(LATEST) && fdt_version(fdt) < 0x10 &&
467*cd60bc56SAndroid Build Coastguard Worker 	    (poffset + sizeof(*prop)) % 8 && fdt32_ld_(&prop->len) >= 8)
468*cd60bc56SAndroid Build Coastguard Worker 		return prop->data + 4;
469*cd60bc56SAndroid Build Coastguard Worker 	return prop->data;
470*cd60bc56SAndroid Build Coastguard Worker }
471*cd60bc56SAndroid Build Coastguard Worker 
fdt_getprop_by_offset(const void * fdt,int offset,const char ** namep,int * lenp)472*cd60bc56SAndroid Build Coastguard Worker const void *fdt_getprop_by_offset(const void *fdt, int offset,
473*cd60bc56SAndroid Build Coastguard Worker 				  const char **namep, int *lenp)
474*cd60bc56SAndroid Build Coastguard Worker {
475*cd60bc56SAndroid Build Coastguard Worker 	const struct fdt_property *prop;
476*cd60bc56SAndroid Build Coastguard Worker 
477*cd60bc56SAndroid Build Coastguard Worker 	prop = fdt_get_property_by_offset_(fdt, offset, lenp);
478*cd60bc56SAndroid Build Coastguard Worker 	if (!prop)
479*cd60bc56SAndroid Build Coastguard Worker 		return NULL;
480*cd60bc56SAndroid Build Coastguard Worker 	if (namep) {
481*cd60bc56SAndroid Build Coastguard Worker 		const char *name;
482*cd60bc56SAndroid Build Coastguard Worker 		int namelen;
483*cd60bc56SAndroid Build Coastguard Worker 
484*cd60bc56SAndroid Build Coastguard Worker 		if (!can_assume(VALID_INPUT)) {
485*cd60bc56SAndroid Build Coastguard Worker 			name = fdt_get_string(fdt, fdt32_ld_(&prop->nameoff),
486*cd60bc56SAndroid Build Coastguard Worker 					      &namelen);
487*cd60bc56SAndroid Build Coastguard Worker 			*namep = name;
488*cd60bc56SAndroid Build Coastguard Worker 			if (!name) {
489*cd60bc56SAndroid Build Coastguard Worker 				if (lenp)
490*cd60bc56SAndroid Build Coastguard Worker 					*lenp = namelen;
491*cd60bc56SAndroid Build Coastguard Worker 				return NULL;
492*cd60bc56SAndroid Build Coastguard Worker 			}
493*cd60bc56SAndroid Build Coastguard Worker 		} else {
494*cd60bc56SAndroid Build Coastguard Worker 			*namep = fdt_string(fdt, fdt32_ld_(&prop->nameoff));
495*cd60bc56SAndroid Build Coastguard Worker 		}
496*cd60bc56SAndroid Build Coastguard Worker 	}
497*cd60bc56SAndroid Build Coastguard Worker 
498*cd60bc56SAndroid Build Coastguard Worker 	/* Handle realignment */
499*cd60bc56SAndroid Build Coastguard Worker 	if (!can_assume(LATEST) && fdt_version(fdt) < 0x10 &&
500*cd60bc56SAndroid Build Coastguard Worker 	    (offset + sizeof(*prop)) % 8 && fdt32_ld_(&prop->len) >= 8)
501*cd60bc56SAndroid Build Coastguard Worker 		return prop->data + 4;
502*cd60bc56SAndroid Build Coastguard Worker 	return prop->data;
503*cd60bc56SAndroid Build Coastguard Worker }
504*cd60bc56SAndroid Build Coastguard Worker 
fdt_getprop(const void * fdt,int nodeoffset,const char * name,int * lenp)505*cd60bc56SAndroid Build Coastguard Worker const void *fdt_getprop(const void *fdt, int nodeoffset,
506*cd60bc56SAndroid Build Coastguard Worker 			const char *name, int *lenp)
507*cd60bc56SAndroid Build Coastguard Worker {
508*cd60bc56SAndroid Build Coastguard Worker 	return fdt_getprop_namelen(fdt, nodeoffset, name, strlen(name), lenp);
509*cd60bc56SAndroid Build Coastguard Worker }
510*cd60bc56SAndroid Build Coastguard Worker 
fdt_get_phandle(const void * fdt,int nodeoffset)511*cd60bc56SAndroid Build Coastguard Worker uint32_t fdt_get_phandle(const void *fdt, int nodeoffset)
512*cd60bc56SAndroid Build Coastguard Worker {
513*cd60bc56SAndroid Build Coastguard Worker 	const fdt32_t *php;
514*cd60bc56SAndroid Build Coastguard Worker 	int len;
515*cd60bc56SAndroid Build Coastguard Worker 
516*cd60bc56SAndroid Build Coastguard Worker 	/* FIXME: This is a bit sub-optimal, since we potentially scan
517*cd60bc56SAndroid Build Coastguard Worker 	 * over all the properties twice. */
518*cd60bc56SAndroid Build Coastguard Worker 	php = fdt_getprop(fdt, nodeoffset, "phandle", &len);
519*cd60bc56SAndroid Build Coastguard Worker 	if (!php || (len != sizeof(*php))) {
520*cd60bc56SAndroid Build Coastguard Worker 		php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len);
521*cd60bc56SAndroid Build Coastguard Worker 		if (!php || (len != sizeof(*php)))
522*cd60bc56SAndroid Build Coastguard Worker 			return 0;
523*cd60bc56SAndroid Build Coastguard Worker 	}
524*cd60bc56SAndroid Build Coastguard Worker 
525*cd60bc56SAndroid Build Coastguard Worker 	return fdt32_ld_(php);
526*cd60bc56SAndroid Build Coastguard Worker }
527*cd60bc56SAndroid Build Coastguard Worker 
fdt_path_getprop_namelen(const void * fdt,const char * path,const char * propname,int propnamelen,int * lenp)528*cd60bc56SAndroid Build Coastguard Worker static const void *fdt_path_getprop_namelen(const void *fdt, const char *path,
529*cd60bc56SAndroid Build Coastguard Worker 					    const char *propname, int propnamelen,
530*cd60bc56SAndroid Build Coastguard Worker 					    int *lenp)
531*cd60bc56SAndroid Build Coastguard Worker {
532*cd60bc56SAndroid Build Coastguard Worker 	int offset = fdt_path_offset(fdt, path);
533*cd60bc56SAndroid Build Coastguard Worker 
534*cd60bc56SAndroid Build Coastguard Worker 	if (offset < 0)
535*cd60bc56SAndroid Build Coastguard Worker 		return NULL;
536*cd60bc56SAndroid Build Coastguard Worker 
537*cd60bc56SAndroid Build Coastguard Worker 	return fdt_getprop_namelen(fdt, offset, propname, propnamelen, lenp);
538*cd60bc56SAndroid Build Coastguard Worker }
539*cd60bc56SAndroid Build Coastguard Worker 
fdt_get_alias_namelen(const void * fdt,const char * name,int namelen)540*cd60bc56SAndroid Build Coastguard Worker const char *fdt_get_alias_namelen(const void *fdt,
541*cd60bc56SAndroid Build Coastguard Worker 				  const char *name, int namelen)
542*cd60bc56SAndroid Build Coastguard Worker {
543*cd60bc56SAndroid Build Coastguard Worker 	int len;
544*cd60bc56SAndroid Build Coastguard Worker 	const char *alias;
545*cd60bc56SAndroid Build Coastguard Worker 
546*cd60bc56SAndroid Build Coastguard Worker 	alias = fdt_path_getprop_namelen(fdt, "/aliases", name, namelen, &len);
547*cd60bc56SAndroid Build Coastguard Worker 
548*cd60bc56SAndroid Build Coastguard Worker 	if (!can_assume(VALID_DTB) &&
549*cd60bc56SAndroid Build Coastguard Worker 	    !(alias && len > 0 && alias[len - 1] == '\0' && *alias == '/'))
550*cd60bc56SAndroid Build Coastguard Worker 		return NULL;
551*cd60bc56SAndroid Build Coastguard Worker 
552*cd60bc56SAndroid Build Coastguard Worker 	return alias;
553*cd60bc56SAndroid Build Coastguard Worker }
554*cd60bc56SAndroid Build Coastguard Worker 
fdt_get_alias(const void * fdt,const char * name)555*cd60bc56SAndroid Build Coastguard Worker const char *fdt_get_alias(const void *fdt, const char *name)
556*cd60bc56SAndroid Build Coastguard Worker {
557*cd60bc56SAndroid Build Coastguard Worker 	return fdt_get_alias_namelen(fdt, name, strlen(name));
558*cd60bc56SAndroid Build Coastguard Worker }
559*cd60bc56SAndroid Build Coastguard Worker 
fdt_get_path(const void * fdt,int nodeoffset,char * buf,int buflen)560*cd60bc56SAndroid Build Coastguard Worker int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)
561*cd60bc56SAndroid Build Coastguard Worker {
562*cd60bc56SAndroid Build Coastguard Worker 	int pdepth = 0, p = 0;
563*cd60bc56SAndroid Build Coastguard Worker 	int offset, depth, namelen;
564*cd60bc56SAndroid Build Coastguard Worker 	const char *name;
565*cd60bc56SAndroid Build Coastguard Worker 
566*cd60bc56SAndroid Build Coastguard Worker 	FDT_RO_PROBE(fdt);
567*cd60bc56SAndroid Build Coastguard Worker 
568*cd60bc56SAndroid Build Coastguard Worker 	if (buflen < 2)
569*cd60bc56SAndroid Build Coastguard Worker 		return -FDT_ERR_NOSPACE;
570*cd60bc56SAndroid Build Coastguard Worker 
571*cd60bc56SAndroid Build Coastguard Worker 	for (offset = 0, depth = 0;
572*cd60bc56SAndroid Build Coastguard Worker 	     (offset >= 0) && (offset <= nodeoffset);
573*cd60bc56SAndroid Build Coastguard Worker 	     offset = fdt_next_node(fdt, offset, &depth)) {
574*cd60bc56SAndroid Build Coastguard Worker 		while (pdepth > depth) {
575*cd60bc56SAndroid Build Coastguard Worker 			do {
576*cd60bc56SAndroid Build Coastguard Worker 				p--;
577*cd60bc56SAndroid Build Coastguard Worker 			} while (buf[p-1] != '/');
578*cd60bc56SAndroid Build Coastguard Worker 			pdepth--;
579*cd60bc56SAndroid Build Coastguard Worker 		}
580*cd60bc56SAndroid Build Coastguard Worker 
581*cd60bc56SAndroid Build Coastguard Worker 		if (pdepth >= depth) {
582*cd60bc56SAndroid Build Coastguard Worker 			name = fdt_get_name(fdt, offset, &namelen);
583*cd60bc56SAndroid Build Coastguard Worker 			if (!name)
584*cd60bc56SAndroid Build Coastguard Worker 				return namelen;
585*cd60bc56SAndroid Build Coastguard Worker 			if ((p + namelen + 1) <= buflen) {
586*cd60bc56SAndroid Build Coastguard Worker 				memcpy(buf + p, name, namelen);
587*cd60bc56SAndroid Build Coastguard Worker 				p += namelen;
588*cd60bc56SAndroid Build Coastguard Worker 				buf[p++] = '/';
589*cd60bc56SAndroid Build Coastguard Worker 				pdepth++;
590*cd60bc56SAndroid Build Coastguard Worker 			}
591*cd60bc56SAndroid Build Coastguard Worker 		}
592*cd60bc56SAndroid Build Coastguard Worker 
593*cd60bc56SAndroid Build Coastguard Worker 		if (offset == nodeoffset) {
594*cd60bc56SAndroid Build Coastguard Worker 			if (pdepth < (depth + 1))
595*cd60bc56SAndroid Build Coastguard Worker 				return -FDT_ERR_NOSPACE;
596*cd60bc56SAndroid Build Coastguard Worker 
597*cd60bc56SAndroid Build Coastguard Worker 			if (p > 1) /* special case so that root path is "/", not "" */
598*cd60bc56SAndroid Build Coastguard Worker 				p--;
599*cd60bc56SAndroid Build Coastguard Worker 			buf[p] = '\0';
600*cd60bc56SAndroid Build Coastguard Worker 			return 0;
601*cd60bc56SAndroid Build Coastguard Worker 		}
602*cd60bc56SAndroid Build Coastguard Worker 	}
603*cd60bc56SAndroid Build Coastguard Worker 
604*cd60bc56SAndroid Build Coastguard Worker 	if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
605*cd60bc56SAndroid Build Coastguard Worker 		return -FDT_ERR_BADOFFSET;
606*cd60bc56SAndroid Build Coastguard Worker 	else if (offset == -FDT_ERR_BADOFFSET)
607*cd60bc56SAndroid Build Coastguard Worker 		return -FDT_ERR_BADSTRUCTURE;
608*cd60bc56SAndroid Build Coastguard Worker 
609*cd60bc56SAndroid Build Coastguard Worker 	return offset; /* error from fdt_next_node() */
610*cd60bc56SAndroid Build Coastguard Worker }
611*cd60bc56SAndroid Build Coastguard Worker 
fdt_supernode_atdepth_offset(const void * fdt,int nodeoffset,int supernodedepth,int * nodedepth)612*cd60bc56SAndroid Build Coastguard Worker int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
613*cd60bc56SAndroid Build Coastguard Worker 				 int supernodedepth, int *nodedepth)
614*cd60bc56SAndroid Build Coastguard Worker {
615*cd60bc56SAndroid Build Coastguard Worker 	int offset, depth;
616*cd60bc56SAndroid Build Coastguard Worker 	int supernodeoffset = -FDT_ERR_INTERNAL;
617*cd60bc56SAndroid Build Coastguard Worker 
618*cd60bc56SAndroid Build Coastguard Worker 	FDT_RO_PROBE(fdt);
619*cd60bc56SAndroid Build Coastguard Worker 
620*cd60bc56SAndroid Build Coastguard Worker 	if (supernodedepth < 0)
621*cd60bc56SAndroid Build Coastguard Worker 		return -FDT_ERR_NOTFOUND;
622*cd60bc56SAndroid Build Coastguard Worker 
623*cd60bc56SAndroid Build Coastguard Worker 	for (offset = 0, depth = 0;
624*cd60bc56SAndroid Build Coastguard Worker 	     (offset >= 0) && (offset <= nodeoffset);
625*cd60bc56SAndroid Build Coastguard Worker 	     offset = fdt_next_node(fdt, offset, &depth)) {
626*cd60bc56SAndroid Build Coastguard Worker 		if (depth == supernodedepth)
627*cd60bc56SAndroid Build Coastguard Worker 			supernodeoffset = offset;
628*cd60bc56SAndroid Build Coastguard Worker 
629*cd60bc56SAndroid Build Coastguard Worker 		if (offset == nodeoffset) {
630*cd60bc56SAndroid Build Coastguard Worker 			if (nodedepth)
631*cd60bc56SAndroid Build Coastguard Worker 				*nodedepth = depth;
632*cd60bc56SAndroid Build Coastguard Worker 
633*cd60bc56SAndroid Build Coastguard Worker 			if (supernodedepth > depth)
634*cd60bc56SAndroid Build Coastguard Worker 				return -FDT_ERR_NOTFOUND;
635*cd60bc56SAndroid Build Coastguard Worker 			else
636*cd60bc56SAndroid Build Coastguard Worker 				return supernodeoffset;
637*cd60bc56SAndroid Build Coastguard Worker 		}
638*cd60bc56SAndroid Build Coastguard Worker 	}
639*cd60bc56SAndroid Build Coastguard Worker 
640*cd60bc56SAndroid Build Coastguard Worker 	if (!can_assume(VALID_INPUT)) {
641*cd60bc56SAndroid Build Coastguard Worker 		if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
642*cd60bc56SAndroid Build Coastguard Worker 			return -FDT_ERR_BADOFFSET;
643*cd60bc56SAndroid Build Coastguard Worker 		else if (offset == -FDT_ERR_BADOFFSET)
644*cd60bc56SAndroid Build Coastguard Worker 			return -FDT_ERR_BADSTRUCTURE;
645*cd60bc56SAndroid Build Coastguard Worker 	}
646*cd60bc56SAndroid Build Coastguard Worker 
647*cd60bc56SAndroid Build Coastguard Worker 	return offset; /* error from fdt_next_node() */
648*cd60bc56SAndroid Build Coastguard Worker }
649*cd60bc56SAndroid Build Coastguard Worker 
fdt_node_depth(const void * fdt,int nodeoffset)650*cd60bc56SAndroid Build Coastguard Worker int fdt_node_depth(const void *fdt, int nodeoffset)
651*cd60bc56SAndroid Build Coastguard Worker {
652*cd60bc56SAndroid Build Coastguard Worker 	int nodedepth;
653*cd60bc56SAndroid Build Coastguard Worker 	int err;
654*cd60bc56SAndroid Build Coastguard Worker 
655*cd60bc56SAndroid Build Coastguard Worker 	err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth);
656*cd60bc56SAndroid Build Coastguard Worker 	if (err)
657*cd60bc56SAndroid Build Coastguard Worker 		return (can_assume(LIBFDT_FLAWLESS) || err < 0) ? err :
658*cd60bc56SAndroid Build Coastguard Worker 			-FDT_ERR_INTERNAL;
659*cd60bc56SAndroid Build Coastguard Worker 	return nodedepth;
660*cd60bc56SAndroid Build Coastguard Worker }
661*cd60bc56SAndroid Build Coastguard Worker 
fdt_parent_offset(const void * fdt,int nodeoffset)662*cd60bc56SAndroid Build Coastguard Worker int fdt_parent_offset(const void *fdt, int nodeoffset)
663*cd60bc56SAndroid Build Coastguard Worker {
664*cd60bc56SAndroid Build Coastguard Worker 	int nodedepth = fdt_node_depth(fdt, nodeoffset);
665*cd60bc56SAndroid Build Coastguard Worker 
666*cd60bc56SAndroid Build Coastguard Worker 	if (nodedepth < 0)
667*cd60bc56SAndroid Build Coastguard Worker 		return nodedepth;
668*cd60bc56SAndroid Build Coastguard Worker 	return fdt_supernode_atdepth_offset(fdt, nodeoffset,
669*cd60bc56SAndroid Build Coastguard Worker 					    nodedepth - 1, NULL);
670*cd60bc56SAndroid Build Coastguard Worker }
671*cd60bc56SAndroid Build Coastguard Worker 
fdt_node_offset_by_prop_value(const void * fdt,int startoffset,const char * propname,const void * propval,int proplen)672*cd60bc56SAndroid Build Coastguard Worker int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
673*cd60bc56SAndroid Build Coastguard Worker 				  const char *propname,
674*cd60bc56SAndroid Build Coastguard Worker 				  const void *propval, int proplen)
675*cd60bc56SAndroid Build Coastguard Worker {
676*cd60bc56SAndroid Build Coastguard Worker 	int offset;
677*cd60bc56SAndroid Build Coastguard Worker 	const void *val;
678*cd60bc56SAndroid Build Coastguard Worker 	int len;
679*cd60bc56SAndroid Build Coastguard Worker 
680*cd60bc56SAndroid Build Coastguard Worker 	FDT_RO_PROBE(fdt);
681*cd60bc56SAndroid Build Coastguard Worker 
682*cd60bc56SAndroid Build Coastguard Worker 	/* FIXME: The algorithm here is pretty horrible: we scan each
683*cd60bc56SAndroid Build Coastguard Worker 	 * property of a node in fdt_getprop(), then if that didn't
684*cd60bc56SAndroid Build Coastguard Worker 	 * find what we want, we scan over them again making our way
685*cd60bc56SAndroid Build Coastguard Worker 	 * to the next node.  Still it's the easiest to implement
686*cd60bc56SAndroid Build Coastguard Worker 	 * approach; performance can come later. */
687*cd60bc56SAndroid Build Coastguard Worker 	for (offset = fdt_next_node(fdt, startoffset, NULL);
688*cd60bc56SAndroid Build Coastguard Worker 	     offset >= 0;
689*cd60bc56SAndroid Build Coastguard Worker 	     offset = fdt_next_node(fdt, offset, NULL)) {
690*cd60bc56SAndroid Build Coastguard Worker 		val = fdt_getprop(fdt, offset, propname, &len);
691*cd60bc56SAndroid Build Coastguard Worker 		if (val && (len == proplen)
692*cd60bc56SAndroid Build Coastguard Worker 		    && (memcmp(val, propval, len) == 0))
693*cd60bc56SAndroid Build Coastguard Worker 			return offset;
694*cd60bc56SAndroid Build Coastguard Worker 	}
695*cd60bc56SAndroid Build Coastguard Worker 
696*cd60bc56SAndroid Build Coastguard Worker 	return offset; /* error from fdt_next_node() */
697*cd60bc56SAndroid Build Coastguard Worker }
698*cd60bc56SAndroid Build Coastguard Worker 
fdt_node_offset_by_phandle(const void * fdt,uint32_t phandle)699*cd60bc56SAndroid Build Coastguard Worker int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle)
700*cd60bc56SAndroid Build Coastguard Worker {
701*cd60bc56SAndroid Build Coastguard Worker 	int offset;
702*cd60bc56SAndroid Build Coastguard Worker 
703*cd60bc56SAndroid Build Coastguard Worker 	if ((phandle == 0) || (phandle == ~0U))
704*cd60bc56SAndroid Build Coastguard Worker 		return -FDT_ERR_BADPHANDLE;
705*cd60bc56SAndroid Build Coastguard Worker 
706*cd60bc56SAndroid Build Coastguard Worker 	FDT_RO_PROBE(fdt);
707*cd60bc56SAndroid Build Coastguard Worker 
708*cd60bc56SAndroid Build Coastguard Worker 	/* FIXME: The algorithm here is pretty horrible: we
709*cd60bc56SAndroid Build Coastguard Worker 	 * potentially scan each property of a node in
710*cd60bc56SAndroid Build Coastguard Worker 	 * fdt_get_phandle(), then if that didn't find what
711*cd60bc56SAndroid Build Coastguard Worker 	 * we want, we scan over them again making our way to the next
712*cd60bc56SAndroid Build Coastguard Worker 	 * node.  Still it's the easiest to implement approach;
713*cd60bc56SAndroid Build Coastguard Worker 	 * performance can come later. */
714*cd60bc56SAndroid Build Coastguard Worker 	for (offset = fdt_next_node(fdt, -1, NULL);
715*cd60bc56SAndroid Build Coastguard Worker 	     offset >= 0;
716*cd60bc56SAndroid Build Coastguard Worker 	     offset = fdt_next_node(fdt, offset, NULL)) {
717*cd60bc56SAndroid Build Coastguard Worker 		if (fdt_get_phandle(fdt, offset) == phandle)
718*cd60bc56SAndroid Build Coastguard Worker 			return offset;
719*cd60bc56SAndroid Build Coastguard Worker 	}
720*cd60bc56SAndroid Build Coastguard Worker 
721*cd60bc56SAndroid Build Coastguard Worker 	return offset; /* error from fdt_next_node() */
722*cd60bc56SAndroid Build Coastguard Worker }
723*cd60bc56SAndroid Build Coastguard Worker 
fdt_stringlist_contains(const char * strlist,int listlen,const char * str)724*cd60bc56SAndroid Build Coastguard Worker int fdt_stringlist_contains(const char *strlist, int listlen, const char *str)
725*cd60bc56SAndroid Build Coastguard Worker {
726*cd60bc56SAndroid Build Coastguard Worker 	int len = strlen(str);
727*cd60bc56SAndroid Build Coastguard Worker 	const char *p;
728*cd60bc56SAndroid Build Coastguard Worker 
729*cd60bc56SAndroid Build Coastguard Worker 	while (listlen >= len) {
730*cd60bc56SAndroid Build Coastguard Worker 		if (memcmp(str, strlist, len+1) == 0)
731*cd60bc56SAndroid Build Coastguard Worker 			return 1;
732*cd60bc56SAndroid Build Coastguard Worker 		p = memchr(strlist, '\0', listlen);
733*cd60bc56SAndroid Build Coastguard Worker 		if (!p)
734*cd60bc56SAndroid Build Coastguard Worker 			return 0; /* malformed strlist.. */
735*cd60bc56SAndroid Build Coastguard Worker 		listlen -= (p-strlist) + 1;
736*cd60bc56SAndroid Build Coastguard Worker 		strlist = p + 1;
737*cd60bc56SAndroid Build Coastguard Worker 	}
738*cd60bc56SAndroid Build Coastguard Worker 	return 0;
739*cd60bc56SAndroid Build Coastguard Worker }
740*cd60bc56SAndroid Build Coastguard Worker 
fdt_stringlist_count(const void * fdt,int nodeoffset,const char * property)741*cd60bc56SAndroid Build Coastguard Worker int fdt_stringlist_count(const void *fdt, int nodeoffset, const char *property)
742*cd60bc56SAndroid Build Coastguard Worker {
743*cd60bc56SAndroid Build Coastguard Worker 	const char *list, *end;
744*cd60bc56SAndroid Build Coastguard Worker 	int length, count = 0;
745*cd60bc56SAndroid Build Coastguard Worker 
746*cd60bc56SAndroid Build Coastguard Worker 	list = fdt_getprop(fdt, nodeoffset, property, &length);
747*cd60bc56SAndroid Build Coastguard Worker 	if (!list)
748*cd60bc56SAndroid Build Coastguard Worker 		return length;
749*cd60bc56SAndroid Build Coastguard Worker 
750*cd60bc56SAndroid Build Coastguard Worker 	end = list + length;
751*cd60bc56SAndroid Build Coastguard Worker 
752*cd60bc56SAndroid Build Coastguard Worker 	while (list < end) {
753*cd60bc56SAndroid Build Coastguard Worker 		length = strnlen(list, end - list) + 1;
754*cd60bc56SAndroid Build Coastguard Worker 
755*cd60bc56SAndroid Build Coastguard Worker 		/* Abort if the last string isn't properly NUL-terminated. */
756*cd60bc56SAndroid Build Coastguard Worker 		if (list + length > end)
757*cd60bc56SAndroid Build Coastguard Worker 			return -FDT_ERR_BADVALUE;
758*cd60bc56SAndroid Build Coastguard Worker 
759*cd60bc56SAndroid Build Coastguard Worker 		list += length;
760*cd60bc56SAndroid Build Coastguard Worker 		count++;
761*cd60bc56SAndroid Build Coastguard Worker 	}
762*cd60bc56SAndroid Build Coastguard Worker 
763*cd60bc56SAndroid Build Coastguard Worker 	return count;
764*cd60bc56SAndroid Build Coastguard Worker }
765*cd60bc56SAndroid Build Coastguard Worker 
fdt_stringlist_search(const void * fdt,int nodeoffset,const char * property,const char * string)766*cd60bc56SAndroid Build Coastguard Worker int fdt_stringlist_search(const void *fdt, int nodeoffset, const char *property,
767*cd60bc56SAndroid Build Coastguard Worker 			  const char *string)
768*cd60bc56SAndroid Build Coastguard Worker {
769*cd60bc56SAndroid Build Coastguard Worker 	int length, len, idx = 0;
770*cd60bc56SAndroid Build Coastguard Worker 	const char *list, *end;
771*cd60bc56SAndroid Build Coastguard Worker 
772*cd60bc56SAndroid Build Coastguard Worker 	list = fdt_getprop(fdt, nodeoffset, property, &length);
773*cd60bc56SAndroid Build Coastguard Worker 	if (!list)
774*cd60bc56SAndroid Build Coastguard Worker 		return length;
775*cd60bc56SAndroid Build Coastguard Worker 
776*cd60bc56SAndroid Build Coastguard Worker 	len = strlen(string) + 1;
777*cd60bc56SAndroid Build Coastguard Worker 	end = list + length;
778*cd60bc56SAndroid Build Coastguard Worker 
779*cd60bc56SAndroid Build Coastguard Worker 	while (list < end) {
780*cd60bc56SAndroid Build Coastguard Worker 		length = strnlen(list, end - list) + 1;
781*cd60bc56SAndroid Build Coastguard Worker 
782*cd60bc56SAndroid Build Coastguard Worker 		/* Abort if the last string isn't properly NUL-terminated. */
783*cd60bc56SAndroid Build Coastguard Worker 		if (list + length > end)
784*cd60bc56SAndroid Build Coastguard Worker 			return -FDT_ERR_BADVALUE;
785*cd60bc56SAndroid Build Coastguard Worker 
786*cd60bc56SAndroid Build Coastguard Worker 		if (length == len && memcmp(list, string, length) == 0)
787*cd60bc56SAndroid Build Coastguard Worker 			return idx;
788*cd60bc56SAndroid Build Coastguard Worker 
789*cd60bc56SAndroid Build Coastguard Worker 		list += length;
790*cd60bc56SAndroid Build Coastguard Worker 		idx++;
791*cd60bc56SAndroid Build Coastguard Worker 	}
792*cd60bc56SAndroid Build Coastguard Worker 
793*cd60bc56SAndroid Build Coastguard Worker 	return -FDT_ERR_NOTFOUND;
794*cd60bc56SAndroid Build Coastguard Worker }
795*cd60bc56SAndroid Build Coastguard Worker 
fdt_stringlist_get(const void * fdt,int nodeoffset,const char * property,int idx,int * lenp)796*cd60bc56SAndroid Build Coastguard Worker const char *fdt_stringlist_get(const void *fdt, int nodeoffset,
797*cd60bc56SAndroid Build Coastguard Worker 			       const char *property, int idx,
798*cd60bc56SAndroid Build Coastguard Worker 			       int *lenp)
799*cd60bc56SAndroid Build Coastguard Worker {
800*cd60bc56SAndroid Build Coastguard Worker 	const char *list, *end;
801*cd60bc56SAndroid Build Coastguard Worker 	int length;
802*cd60bc56SAndroid Build Coastguard Worker 
803*cd60bc56SAndroid Build Coastguard Worker 	list = fdt_getprop(fdt, nodeoffset, property, &length);
804*cd60bc56SAndroid Build Coastguard Worker 	if (!list) {
805*cd60bc56SAndroid Build Coastguard Worker 		if (lenp)
806*cd60bc56SAndroid Build Coastguard Worker 			*lenp = length;
807*cd60bc56SAndroid Build Coastguard Worker 
808*cd60bc56SAndroid Build Coastguard Worker 		return NULL;
809*cd60bc56SAndroid Build Coastguard Worker 	}
810*cd60bc56SAndroid Build Coastguard Worker 
811*cd60bc56SAndroid Build Coastguard Worker 	end = list + length;
812*cd60bc56SAndroid Build Coastguard Worker 
813*cd60bc56SAndroid Build Coastguard Worker 	while (list < end) {
814*cd60bc56SAndroid Build Coastguard Worker 		length = strnlen(list, end - list) + 1;
815*cd60bc56SAndroid Build Coastguard Worker 
816*cd60bc56SAndroid Build Coastguard Worker 		/* Abort if the last string isn't properly NUL-terminated. */
817*cd60bc56SAndroid Build Coastguard Worker 		if (list + length > end) {
818*cd60bc56SAndroid Build Coastguard Worker 			if (lenp)
819*cd60bc56SAndroid Build Coastguard Worker 				*lenp = -FDT_ERR_BADVALUE;
820*cd60bc56SAndroid Build Coastguard Worker 
821*cd60bc56SAndroid Build Coastguard Worker 			return NULL;
822*cd60bc56SAndroid Build Coastguard Worker 		}
823*cd60bc56SAndroid Build Coastguard Worker 
824*cd60bc56SAndroid Build Coastguard Worker 		if (idx == 0) {
825*cd60bc56SAndroid Build Coastguard Worker 			if (lenp)
826*cd60bc56SAndroid Build Coastguard Worker 				*lenp = length - 1;
827*cd60bc56SAndroid Build Coastguard Worker 
828*cd60bc56SAndroid Build Coastguard Worker 			return list;
829*cd60bc56SAndroid Build Coastguard Worker 		}
830*cd60bc56SAndroid Build Coastguard Worker 
831*cd60bc56SAndroid Build Coastguard Worker 		list += length;
832*cd60bc56SAndroid Build Coastguard Worker 		idx--;
833*cd60bc56SAndroid Build Coastguard Worker 	}
834*cd60bc56SAndroid Build Coastguard Worker 
835*cd60bc56SAndroid Build Coastguard Worker 	if (lenp)
836*cd60bc56SAndroid Build Coastguard Worker 		*lenp = -FDT_ERR_NOTFOUND;
837*cd60bc56SAndroid Build Coastguard Worker 
838*cd60bc56SAndroid Build Coastguard Worker 	return NULL;
839*cd60bc56SAndroid Build Coastguard Worker }
840*cd60bc56SAndroid Build Coastguard Worker 
fdt_node_check_compatible(const void * fdt,int nodeoffset,const char * compatible)841*cd60bc56SAndroid Build Coastguard Worker int fdt_node_check_compatible(const void *fdt, int nodeoffset,
842*cd60bc56SAndroid Build Coastguard Worker 			      const char *compatible)
843*cd60bc56SAndroid Build Coastguard Worker {
844*cd60bc56SAndroid Build Coastguard Worker 	const void *prop;
845*cd60bc56SAndroid Build Coastguard Worker 	int len;
846*cd60bc56SAndroid Build Coastguard Worker 
847*cd60bc56SAndroid Build Coastguard Worker 	prop = fdt_getprop(fdt, nodeoffset, "compatible", &len);
848*cd60bc56SAndroid Build Coastguard Worker 	if (!prop)
849*cd60bc56SAndroid Build Coastguard Worker 		return len;
850*cd60bc56SAndroid Build Coastguard Worker 
851*cd60bc56SAndroid Build Coastguard Worker 	return !fdt_stringlist_contains(prop, len, compatible);
852*cd60bc56SAndroid Build Coastguard Worker }
853*cd60bc56SAndroid Build Coastguard Worker 
fdt_node_offset_by_compatible(const void * fdt,int startoffset,const char * compatible)854*cd60bc56SAndroid Build Coastguard Worker int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
855*cd60bc56SAndroid Build Coastguard Worker 				  const char *compatible)
856*cd60bc56SAndroid Build Coastguard Worker {
857*cd60bc56SAndroid Build Coastguard Worker 	int offset, err;
858*cd60bc56SAndroid Build Coastguard Worker 
859*cd60bc56SAndroid Build Coastguard Worker 	FDT_RO_PROBE(fdt);
860*cd60bc56SAndroid Build Coastguard Worker 
861*cd60bc56SAndroid Build Coastguard Worker 	/* FIXME: The algorithm here is pretty horrible: we scan each
862*cd60bc56SAndroid Build Coastguard Worker 	 * property of a node in fdt_node_check_compatible(), then if
863*cd60bc56SAndroid Build Coastguard Worker 	 * that didn't find what we want, we scan over them again
864*cd60bc56SAndroid Build Coastguard Worker 	 * making our way to the next node.  Still it's the easiest to
865*cd60bc56SAndroid Build Coastguard Worker 	 * implement approach; performance can come later. */
866*cd60bc56SAndroid Build Coastguard Worker 	for (offset = fdt_next_node(fdt, startoffset, NULL);
867*cd60bc56SAndroid Build Coastguard Worker 	     offset >= 0;
868*cd60bc56SAndroid Build Coastguard Worker 	     offset = fdt_next_node(fdt, offset, NULL)) {
869*cd60bc56SAndroid Build Coastguard Worker 		err = fdt_node_check_compatible(fdt, offset, compatible);
870*cd60bc56SAndroid Build Coastguard Worker 		if ((err < 0) && (err != -FDT_ERR_NOTFOUND))
871*cd60bc56SAndroid Build Coastguard Worker 			return err;
872*cd60bc56SAndroid Build Coastguard Worker 		else if (err == 0)
873*cd60bc56SAndroid Build Coastguard Worker 			return offset;
874*cd60bc56SAndroid Build Coastguard Worker 	}
875*cd60bc56SAndroid Build Coastguard Worker 
876*cd60bc56SAndroid Build Coastguard Worker 	return offset; /* error from fdt_next_node() */
877*cd60bc56SAndroid Build Coastguard Worker }
878