xref: /utopia/UTPA2-700.0.x/projects/build/scripts/dtc/libfdt/fdt_ro.c (revision 53ee8cc121a030b8d368113ac3e966b4705770ef)
1*53ee8cc1Swenshuai.xi /*
2*53ee8cc1Swenshuai.xi  * libfdt - Flat Device Tree manipulation
3*53ee8cc1Swenshuai.xi  * Copyright (C) 2006 David Gibson, IBM Corporation.
4*53ee8cc1Swenshuai.xi  *
5*53ee8cc1Swenshuai.xi  * libfdt is dual licensed: you can use it either under the terms of
6*53ee8cc1Swenshuai.xi  * the GPL, or the BSD license, at your option.
7*53ee8cc1Swenshuai.xi  *
8*53ee8cc1Swenshuai.xi  *  a) This library is free software; you can redistribute it and/or
9*53ee8cc1Swenshuai.xi  *     modify it under the terms of the GNU General Public License as
10*53ee8cc1Swenshuai.xi  *     published by the Free Software Foundation; either version 2 of the
11*53ee8cc1Swenshuai.xi  *     License, or (at your option) any later version.
12*53ee8cc1Swenshuai.xi  *
13*53ee8cc1Swenshuai.xi  *     This library is distributed in the hope that it will be useful,
14*53ee8cc1Swenshuai.xi  *     but WITHOUT ANY WARRANTY; without even the implied warranty of
15*53ee8cc1Swenshuai.xi  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16*53ee8cc1Swenshuai.xi  *     GNU General Public License for more details.
17*53ee8cc1Swenshuai.xi  *
18*53ee8cc1Swenshuai.xi  *     You should have received a copy of the GNU General Public
19*53ee8cc1Swenshuai.xi  *     License along with this library; if not, write to the Free
20*53ee8cc1Swenshuai.xi  *     Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
21*53ee8cc1Swenshuai.xi  *     MA 02110-1301 USA
22*53ee8cc1Swenshuai.xi  *
23*53ee8cc1Swenshuai.xi  * Alternatively,
24*53ee8cc1Swenshuai.xi  *
25*53ee8cc1Swenshuai.xi  *  b) Redistribution and use in source and binary forms, with or
26*53ee8cc1Swenshuai.xi  *     without modification, are permitted provided that the following
27*53ee8cc1Swenshuai.xi  *     conditions are met:
28*53ee8cc1Swenshuai.xi  *
29*53ee8cc1Swenshuai.xi  *     1. Redistributions of source code must retain the above
30*53ee8cc1Swenshuai.xi  *        copyright notice, this list of conditions and the following
31*53ee8cc1Swenshuai.xi  *        disclaimer.
32*53ee8cc1Swenshuai.xi  *     2. Redistributions in binary form must reproduce the above
33*53ee8cc1Swenshuai.xi  *        copyright notice, this list of conditions and the following
34*53ee8cc1Swenshuai.xi  *        disclaimer in the documentation and/or other materials
35*53ee8cc1Swenshuai.xi  *        provided with the distribution.
36*53ee8cc1Swenshuai.xi  *
37*53ee8cc1Swenshuai.xi  *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
38*53ee8cc1Swenshuai.xi  *     CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
39*53ee8cc1Swenshuai.xi  *     INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
40*53ee8cc1Swenshuai.xi  *     MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
41*53ee8cc1Swenshuai.xi  *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
42*53ee8cc1Swenshuai.xi  *     CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
43*53ee8cc1Swenshuai.xi  *     SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
44*53ee8cc1Swenshuai.xi  *     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
45*53ee8cc1Swenshuai.xi  *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
46*53ee8cc1Swenshuai.xi  *     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
47*53ee8cc1Swenshuai.xi  *     CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
48*53ee8cc1Swenshuai.xi  *     OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
49*53ee8cc1Swenshuai.xi  *     EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
50*53ee8cc1Swenshuai.xi  */
51*53ee8cc1Swenshuai.xi #include "libfdt_env.h"
52*53ee8cc1Swenshuai.xi 
53*53ee8cc1Swenshuai.xi #include <fdt.h>
54*53ee8cc1Swenshuai.xi #include <libfdt.h>
55*53ee8cc1Swenshuai.xi 
56*53ee8cc1Swenshuai.xi #include "libfdt_internal.h"
57*53ee8cc1Swenshuai.xi 
_fdt_nodename_eq(const void * fdt,int offset,const char * s,int len)58*53ee8cc1Swenshuai.xi static int _fdt_nodename_eq(const void *fdt, int offset,
59*53ee8cc1Swenshuai.xi 			    const char *s, int len)
60*53ee8cc1Swenshuai.xi {
61*53ee8cc1Swenshuai.xi 	const char *p = fdt_offset_ptr(fdt, offset + FDT_TAGSIZE, len+1);
62*53ee8cc1Swenshuai.xi 
63*53ee8cc1Swenshuai.xi 	if (! p)
64*53ee8cc1Swenshuai.xi 		/* short match */
65*53ee8cc1Swenshuai.xi 		return 0;
66*53ee8cc1Swenshuai.xi 
67*53ee8cc1Swenshuai.xi 	if (memcmp(p, s, len) != 0)
68*53ee8cc1Swenshuai.xi 		return 0;
69*53ee8cc1Swenshuai.xi 
70*53ee8cc1Swenshuai.xi 	if (p[len] == '\0')
71*53ee8cc1Swenshuai.xi 		return 1;
72*53ee8cc1Swenshuai.xi 	else if (!memchr(s, '@', len) && (p[len] == '@'))
73*53ee8cc1Swenshuai.xi 		return 1;
74*53ee8cc1Swenshuai.xi 	else
75*53ee8cc1Swenshuai.xi 		return 0;
76*53ee8cc1Swenshuai.xi }
77*53ee8cc1Swenshuai.xi 
fdt_string(const void * fdt,int stroffset)78*53ee8cc1Swenshuai.xi const char *fdt_string(const void *fdt, int stroffset)
79*53ee8cc1Swenshuai.xi {
80*53ee8cc1Swenshuai.xi 	return (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset;
81*53ee8cc1Swenshuai.xi }
82*53ee8cc1Swenshuai.xi 
fdt_get_mem_rsv(const void * fdt,int n,uint64_t * address,uint64_t * size)83*53ee8cc1Swenshuai.xi int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
84*53ee8cc1Swenshuai.xi {
85*53ee8cc1Swenshuai.xi 	FDT_CHECK_HEADER(fdt);
86*53ee8cc1Swenshuai.xi 	*address = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->address);
87*53ee8cc1Swenshuai.xi 	*size = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->size);
88*53ee8cc1Swenshuai.xi 	return 0;
89*53ee8cc1Swenshuai.xi }
90*53ee8cc1Swenshuai.xi 
fdt_num_mem_rsv(const void * fdt)91*53ee8cc1Swenshuai.xi int fdt_num_mem_rsv(const void *fdt)
92*53ee8cc1Swenshuai.xi {
93*53ee8cc1Swenshuai.xi 	int i = 0;
94*53ee8cc1Swenshuai.xi 
95*53ee8cc1Swenshuai.xi 	while (fdt64_to_cpu(_fdt_mem_rsv(fdt, i)->size) != 0)
96*53ee8cc1Swenshuai.xi 		i++;
97*53ee8cc1Swenshuai.xi 	return i;
98*53ee8cc1Swenshuai.xi }
99*53ee8cc1Swenshuai.xi 
fdt_subnode_offset_namelen(const void * fdt,int offset,const char * name,int namelen)100*53ee8cc1Swenshuai.xi int fdt_subnode_offset_namelen(const void *fdt, int offset,
101*53ee8cc1Swenshuai.xi 			       const char *name, int namelen)
102*53ee8cc1Swenshuai.xi {
103*53ee8cc1Swenshuai.xi 	int depth;
104*53ee8cc1Swenshuai.xi 
105*53ee8cc1Swenshuai.xi 	FDT_CHECK_HEADER(fdt);
106*53ee8cc1Swenshuai.xi 
107*53ee8cc1Swenshuai.xi 	for (depth = 0, offset = fdt_next_node(fdt, offset, &depth);
108*53ee8cc1Swenshuai.xi 	     (offset >= 0) && (depth > 0);
109*53ee8cc1Swenshuai.xi 	     offset = fdt_next_node(fdt, offset, &depth)) {
110*53ee8cc1Swenshuai.xi 		if (depth < 0)
111*53ee8cc1Swenshuai.xi 			return -FDT_ERR_NOTFOUND;
112*53ee8cc1Swenshuai.xi 		else if ((depth == 1)
113*53ee8cc1Swenshuai.xi 			 && _fdt_nodename_eq(fdt, offset, name, namelen))
114*53ee8cc1Swenshuai.xi 			return offset;
115*53ee8cc1Swenshuai.xi 	}
116*53ee8cc1Swenshuai.xi 
117*53ee8cc1Swenshuai.xi 	if (offset < 0)
118*53ee8cc1Swenshuai.xi 		return offset; /* error */
119*53ee8cc1Swenshuai.xi 	else
120*53ee8cc1Swenshuai.xi 		return -FDT_ERR_NOTFOUND;
121*53ee8cc1Swenshuai.xi }
122*53ee8cc1Swenshuai.xi 
fdt_subnode_offset(const void * fdt,int parentoffset,const char * name)123*53ee8cc1Swenshuai.xi int fdt_subnode_offset(const void *fdt, int parentoffset,
124*53ee8cc1Swenshuai.xi 		       const char *name)
125*53ee8cc1Swenshuai.xi {
126*53ee8cc1Swenshuai.xi 	return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name));
127*53ee8cc1Swenshuai.xi }
128*53ee8cc1Swenshuai.xi 
fdt_path_offset(const void * fdt,const char * path)129*53ee8cc1Swenshuai.xi int fdt_path_offset(const void *fdt, const char *path)
130*53ee8cc1Swenshuai.xi {
131*53ee8cc1Swenshuai.xi 	const char *end = path + strlen(path);
132*53ee8cc1Swenshuai.xi 	const char *p = path;
133*53ee8cc1Swenshuai.xi 	int offset = 0;
134*53ee8cc1Swenshuai.xi 
135*53ee8cc1Swenshuai.xi 	FDT_CHECK_HEADER(fdt);
136*53ee8cc1Swenshuai.xi 
137*53ee8cc1Swenshuai.xi 	if (*path != '/')
138*53ee8cc1Swenshuai.xi 		return -FDT_ERR_BADPATH;
139*53ee8cc1Swenshuai.xi 
140*53ee8cc1Swenshuai.xi 	while (*p) {
141*53ee8cc1Swenshuai.xi 		const char *q;
142*53ee8cc1Swenshuai.xi 
143*53ee8cc1Swenshuai.xi 		while (*p == '/')
144*53ee8cc1Swenshuai.xi 			p++;
145*53ee8cc1Swenshuai.xi 		if (! *p)
146*53ee8cc1Swenshuai.xi 			return offset;
147*53ee8cc1Swenshuai.xi 		q = strchr(p, '/');
148*53ee8cc1Swenshuai.xi 		if (! q)
149*53ee8cc1Swenshuai.xi 			q = end;
150*53ee8cc1Swenshuai.xi 
151*53ee8cc1Swenshuai.xi 		offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p);
152*53ee8cc1Swenshuai.xi 		if (offset < 0)
153*53ee8cc1Swenshuai.xi 			return offset;
154*53ee8cc1Swenshuai.xi 
155*53ee8cc1Swenshuai.xi 		p = q;
156*53ee8cc1Swenshuai.xi 	}
157*53ee8cc1Swenshuai.xi 
158*53ee8cc1Swenshuai.xi 	return offset;
159*53ee8cc1Swenshuai.xi }
160*53ee8cc1Swenshuai.xi 
fdt_get_name(const void * fdt,int nodeoffset,int * len)161*53ee8cc1Swenshuai.xi const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
162*53ee8cc1Swenshuai.xi {
163*53ee8cc1Swenshuai.xi 	const struct fdt_node_header *nh = _fdt_offset_ptr(fdt, nodeoffset);
164*53ee8cc1Swenshuai.xi 	int err;
165*53ee8cc1Swenshuai.xi 
166*53ee8cc1Swenshuai.xi 	if (((err = fdt_check_header(fdt)) != 0)
167*53ee8cc1Swenshuai.xi 	    || ((err = _fdt_check_node_offset(fdt, nodeoffset)) < 0))
168*53ee8cc1Swenshuai.xi 			goto fail;
169*53ee8cc1Swenshuai.xi 
170*53ee8cc1Swenshuai.xi 	if (len)
171*53ee8cc1Swenshuai.xi 		*len = strlen(nh->name);
172*53ee8cc1Swenshuai.xi 
173*53ee8cc1Swenshuai.xi 	return nh->name;
174*53ee8cc1Swenshuai.xi 
175*53ee8cc1Swenshuai.xi  fail:
176*53ee8cc1Swenshuai.xi 	if (len)
177*53ee8cc1Swenshuai.xi 		*len = err;
178*53ee8cc1Swenshuai.xi 	return NULL;
179*53ee8cc1Swenshuai.xi }
180*53ee8cc1Swenshuai.xi 
fdt_get_property(const void * fdt,int nodeoffset,const char * name,int * lenp)181*53ee8cc1Swenshuai.xi const struct fdt_property *fdt_get_property(const void *fdt,
182*53ee8cc1Swenshuai.xi 					    int nodeoffset,
183*53ee8cc1Swenshuai.xi 					    const char *name, int *lenp)
184*53ee8cc1Swenshuai.xi {
185*53ee8cc1Swenshuai.xi 	uint32_t tag;
186*53ee8cc1Swenshuai.xi 	const struct fdt_property *prop;
187*53ee8cc1Swenshuai.xi 	int namestroff;
188*53ee8cc1Swenshuai.xi 	int offset, nextoffset;
189*53ee8cc1Swenshuai.xi 	int err;
190*53ee8cc1Swenshuai.xi 
191*53ee8cc1Swenshuai.xi 	if (((err = fdt_check_header(fdt)) != 0)
192*53ee8cc1Swenshuai.xi 	    || ((err = _fdt_check_node_offset(fdt, nodeoffset)) < 0))
193*53ee8cc1Swenshuai.xi 			goto fail;
194*53ee8cc1Swenshuai.xi 
195*53ee8cc1Swenshuai.xi 	nextoffset = err;
196*53ee8cc1Swenshuai.xi 	do {
197*53ee8cc1Swenshuai.xi 		offset = nextoffset;
198*53ee8cc1Swenshuai.xi 
199*53ee8cc1Swenshuai.xi 		tag = fdt_next_tag(fdt, offset, &nextoffset);
200*53ee8cc1Swenshuai.xi 		switch (tag) {
201*53ee8cc1Swenshuai.xi 		case FDT_END:
202*53ee8cc1Swenshuai.xi 			err = -FDT_ERR_TRUNCATED;
203*53ee8cc1Swenshuai.xi 			goto fail;
204*53ee8cc1Swenshuai.xi 
205*53ee8cc1Swenshuai.xi 		case FDT_BEGIN_NODE:
206*53ee8cc1Swenshuai.xi 		case FDT_END_NODE:
207*53ee8cc1Swenshuai.xi 		case FDT_NOP:
208*53ee8cc1Swenshuai.xi 			break;
209*53ee8cc1Swenshuai.xi 
210*53ee8cc1Swenshuai.xi 		case FDT_PROP:
211*53ee8cc1Swenshuai.xi 			err = -FDT_ERR_BADSTRUCTURE;
212*53ee8cc1Swenshuai.xi 			prop = fdt_offset_ptr(fdt, offset, sizeof(*prop));
213*53ee8cc1Swenshuai.xi 			if (! prop)
214*53ee8cc1Swenshuai.xi 				goto fail;
215*53ee8cc1Swenshuai.xi 			namestroff = fdt32_to_cpu(prop->nameoff);
216*53ee8cc1Swenshuai.xi 			if (strcmp(fdt_string(fdt, namestroff), name) == 0) {
217*53ee8cc1Swenshuai.xi 				/* Found it! */
218*53ee8cc1Swenshuai.xi 				int len = fdt32_to_cpu(prop->len);
219*53ee8cc1Swenshuai.xi 				prop = fdt_offset_ptr(fdt, offset,
220*53ee8cc1Swenshuai.xi 						      sizeof(*prop)+len);
221*53ee8cc1Swenshuai.xi 				if (! prop)
222*53ee8cc1Swenshuai.xi 					goto fail;
223*53ee8cc1Swenshuai.xi 
224*53ee8cc1Swenshuai.xi 				if (lenp)
225*53ee8cc1Swenshuai.xi 					*lenp = len;
226*53ee8cc1Swenshuai.xi 
227*53ee8cc1Swenshuai.xi 				return prop;
228*53ee8cc1Swenshuai.xi 			}
229*53ee8cc1Swenshuai.xi 			break;
230*53ee8cc1Swenshuai.xi 
231*53ee8cc1Swenshuai.xi 		default:
232*53ee8cc1Swenshuai.xi 			err = -FDT_ERR_BADSTRUCTURE;
233*53ee8cc1Swenshuai.xi 			goto fail;
234*53ee8cc1Swenshuai.xi 		}
235*53ee8cc1Swenshuai.xi 	} while ((tag != FDT_BEGIN_NODE) && (tag != FDT_END_NODE));
236*53ee8cc1Swenshuai.xi 
237*53ee8cc1Swenshuai.xi 	err = -FDT_ERR_NOTFOUND;
238*53ee8cc1Swenshuai.xi  fail:
239*53ee8cc1Swenshuai.xi 	if (lenp)
240*53ee8cc1Swenshuai.xi 		*lenp = err;
241*53ee8cc1Swenshuai.xi 	return NULL;
242*53ee8cc1Swenshuai.xi }
243*53ee8cc1Swenshuai.xi 
fdt_getprop(const void * fdt,int nodeoffset,const char * name,int * lenp)244*53ee8cc1Swenshuai.xi const void *fdt_getprop(const void *fdt, int nodeoffset,
245*53ee8cc1Swenshuai.xi 		  const char *name, int *lenp)
246*53ee8cc1Swenshuai.xi {
247*53ee8cc1Swenshuai.xi 	const struct fdt_property *prop;
248*53ee8cc1Swenshuai.xi 
249*53ee8cc1Swenshuai.xi 	prop = fdt_get_property(fdt, nodeoffset, name, lenp);
250*53ee8cc1Swenshuai.xi 	if (! prop)
251*53ee8cc1Swenshuai.xi 		return NULL;
252*53ee8cc1Swenshuai.xi 
253*53ee8cc1Swenshuai.xi 	return prop->data;
254*53ee8cc1Swenshuai.xi }
255*53ee8cc1Swenshuai.xi 
fdt_get_phandle(const void * fdt,int nodeoffset)256*53ee8cc1Swenshuai.xi uint32_t fdt_get_phandle(const void *fdt, int nodeoffset)
257*53ee8cc1Swenshuai.xi {
258*53ee8cc1Swenshuai.xi 	const uint32_t *php;
259*53ee8cc1Swenshuai.xi 	int len;
260*53ee8cc1Swenshuai.xi 
261*53ee8cc1Swenshuai.xi 	php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len);
262*53ee8cc1Swenshuai.xi 	if (!php || (len != sizeof(*php)))
263*53ee8cc1Swenshuai.xi 		return 0;
264*53ee8cc1Swenshuai.xi 
265*53ee8cc1Swenshuai.xi 	return fdt32_to_cpu(*php);
266*53ee8cc1Swenshuai.xi }
267*53ee8cc1Swenshuai.xi 
fdt_get_path(const void * fdt,int nodeoffset,char * buf,int buflen)268*53ee8cc1Swenshuai.xi int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)
269*53ee8cc1Swenshuai.xi {
270*53ee8cc1Swenshuai.xi 	int pdepth = 0, p = 0;
271*53ee8cc1Swenshuai.xi 	int offset, depth, namelen;
272*53ee8cc1Swenshuai.xi 	const char *name;
273*53ee8cc1Swenshuai.xi 
274*53ee8cc1Swenshuai.xi 	FDT_CHECK_HEADER(fdt);
275*53ee8cc1Swenshuai.xi 
276*53ee8cc1Swenshuai.xi 	if (buflen < 2)
277*53ee8cc1Swenshuai.xi 		return -FDT_ERR_NOSPACE;
278*53ee8cc1Swenshuai.xi 
279*53ee8cc1Swenshuai.xi 	for (offset = 0, depth = 0;
280*53ee8cc1Swenshuai.xi 	     (offset >= 0) && (offset <= nodeoffset);
281*53ee8cc1Swenshuai.xi 	     offset = fdt_next_node(fdt, offset, &depth)) {
282*53ee8cc1Swenshuai.xi 		if (pdepth < depth)
283*53ee8cc1Swenshuai.xi 			continue; /* overflowed buffer */
284*53ee8cc1Swenshuai.xi 
285*53ee8cc1Swenshuai.xi 		while (pdepth > depth) {
286*53ee8cc1Swenshuai.xi 			do {
287*53ee8cc1Swenshuai.xi 				p--;
288*53ee8cc1Swenshuai.xi 			} while (buf[p-1] != '/');
289*53ee8cc1Swenshuai.xi 			pdepth--;
290*53ee8cc1Swenshuai.xi 		}
291*53ee8cc1Swenshuai.xi 
292*53ee8cc1Swenshuai.xi 		name = fdt_get_name(fdt, offset, &namelen);
293*53ee8cc1Swenshuai.xi 		if (!name)
294*53ee8cc1Swenshuai.xi 			return namelen;
295*53ee8cc1Swenshuai.xi 		if ((p + namelen + 1) <= buflen) {
296*53ee8cc1Swenshuai.xi 			memcpy(buf + p, name, namelen);
297*53ee8cc1Swenshuai.xi 			p += namelen;
298*53ee8cc1Swenshuai.xi 			buf[p++] = '/';
299*53ee8cc1Swenshuai.xi 			pdepth++;
300*53ee8cc1Swenshuai.xi 		}
301*53ee8cc1Swenshuai.xi 
302*53ee8cc1Swenshuai.xi 		if (offset == nodeoffset) {
303*53ee8cc1Swenshuai.xi 			if (pdepth < (depth + 1))
304*53ee8cc1Swenshuai.xi 				return -FDT_ERR_NOSPACE;
305*53ee8cc1Swenshuai.xi 
306*53ee8cc1Swenshuai.xi 			if (p > 1) /* special case so that root path is "/", not "" */
307*53ee8cc1Swenshuai.xi 				p--;
308*53ee8cc1Swenshuai.xi 			buf[p] = '\0';
309*53ee8cc1Swenshuai.xi 			return p;
310*53ee8cc1Swenshuai.xi 		}
311*53ee8cc1Swenshuai.xi 	}
312*53ee8cc1Swenshuai.xi 
313*53ee8cc1Swenshuai.xi 	if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
314*53ee8cc1Swenshuai.xi 		return -FDT_ERR_BADOFFSET;
315*53ee8cc1Swenshuai.xi 	else if (offset == -FDT_ERR_BADOFFSET)
316*53ee8cc1Swenshuai.xi 		return -FDT_ERR_BADSTRUCTURE;
317*53ee8cc1Swenshuai.xi 
318*53ee8cc1Swenshuai.xi 	return offset; /* error from fdt_next_node() */
319*53ee8cc1Swenshuai.xi }
320*53ee8cc1Swenshuai.xi 
fdt_supernode_atdepth_offset(const void * fdt,int nodeoffset,int supernodedepth,int * nodedepth)321*53ee8cc1Swenshuai.xi int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
322*53ee8cc1Swenshuai.xi 				 int supernodedepth, int *nodedepth)
323*53ee8cc1Swenshuai.xi {
324*53ee8cc1Swenshuai.xi 	int offset, depth;
325*53ee8cc1Swenshuai.xi 	int supernodeoffset = -FDT_ERR_INTERNAL;
326*53ee8cc1Swenshuai.xi 
327*53ee8cc1Swenshuai.xi 	FDT_CHECK_HEADER(fdt);
328*53ee8cc1Swenshuai.xi 
329*53ee8cc1Swenshuai.xi 	if (supernodedepth < 0)
330*53ee8cc1Swenshuai.xi 		return -FDT_ERR_NOTFOUND;
331*53ee8cc1Swenshuai.xi 
332*53ee8cc1Swenshuai.xi 	for (offset = 0, depth = 0;
333*53ee8cc1Swenshuai.xi 	     (offset >= 0) && (offset <= nodeoffset);
334*53ee8cc1Swenshuai.xi 	     offset = fdt_next_node(fdt, offset, &depth)) {
335*53ee8cc1Swenshuai.xi 		if (depth == supernodedepth)
336*53ee8cc1Swenshuai.xi 			supernodeoffset = offset;
337*53ee8cc1Swenshuai.xi 
338*53ee8cc1Swenshuai.xi 		if (offset == nodeoffset) {
339*53ee8cc1Swenshuai.xi 			if (nodedepth)
340*53ee8cc1Swenshuai.xi 				*nodedepth = depth;
341*53ee8cc1Swenshuai.xi 
342*53ee8cc1Swenshuai.xi 			if (supernodedepth > depth)
343*53ee8cc1Swenshuai.xi 				return -FDT_ERR_NOTFOUND;
344*53ee8cc1Swenshuai.xi 			else
345*53ee8cc1Swenshuai.xi 				return supernodeoffset;
346*53ee8cc1Swenshuai.xi 		}
347*53ee8cc1Swenshuai.xi 	}
348*53ee8cc1Swenshuai.xi 
349*53ee8cc1Swenshuai.xi 	if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
350*53ee8cc1Swenshuai.xi 		return -FDT_ERR_BADOFFSET;
351*53ee8cc1Swenshuai.xi 	else if (offset == -FDT_ERR_BADOFFSET)
352*53ee8cc1Swenshuai.xi 		return -FDT_ERR_BADSTRUCTURE;
353*53ee8cc1Swenshuai.xi 
354*53ee8cc1Swenshuai.xi 	return offset; /* error from fdt_next_node() */
355*53ee8cc1Swenshuai.xi }
356*53ee8cc1Swenshuai.xi 
fdt_node_depth(const void * fdt,int nodeoffset)357*53ee8cc1Swenshuai.xi int fdt_node_depth(const void *fdt, int nodeoffset)
358*53ee8cc1Swenshuai.xi {
359*53ee8cc1Swenshuai.xi 	int nodedepth;
360*53ee8cc1Swenshuai.xi 	int err;
361*53ee8cc1Swenshuai.xi 
362*53ee8cc1Swenshuai.xi 	err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth);
363*53ee8cc1Swenshuai.xi 	if (err)
364*53ee8cc1Swenshuai.xi 		return (err < 0) ? err : -FDT_ERR_INTERNAL;
365*53ee8cc1Swenshuai.xi 	return nodedepth;
366*53ee8cc1Swenshuai.xi }
367*53ee8cc1Swenshuai.xi 
fdt_parent_offset(const void * fdt,int nodeoffset)368*53ee8cc1Swenshuai.xi int fdt_parent_offset(const void *fdt, int nodeoffset)
369*53ee8cc1Swenshuai.xi {
370*53ee8cc1Swenshuai.xi 	int nodedepth = fdt_node_depth(fdt, nodeoffset);
371*53ee8cc1Swenshuai.xi 
372*53ee8cc1Swenshuai.xi 	if (nodedepth < 0)
373*53ee8cc1Swenshuai.xi 		return nodedepth;
374*53ee8cc1Swenshuai.xi 	return fdt_supernode_atdepth_offset(fdt, nodeoffset,
375*53ee8cc1Swenshuai.xi 					    nodedepth - 1, NULL);
376*53ee8cc1Swenshuai.xi }
377*53ee8cc1Swenshuai.xi 
fdt_node_offset_by_prop_value(const void * fdt,int startoffset,const char * propname,const void * propval,int proplen)378*53ee8cc1Swenshuai.xi int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
379*53ee8cc1Swenshuai.xi 				  const char *propname,
380*53ee8cc1Swenshuai.xi 				  const void *propval, int proplen)
381*53ee8cc1Swenshuai.xi {
382*53ee8cc1Swenshuai.xi 	int offset;
383*53ee8cc1Swenshuai.xi 	const void *val;
384*53ee8cc1Swenshuai.xi 	int len;
385*53ee8cc1Swenshuai.xi 
386*53ee8cc1Swenshuai.xi 	FDT_CHECK_HEADER(fdt);
387*53ee8cc1Swenshuai.xi 
388*53ee8cc1Swenshuai.xi 	/* FIXME: The algorithm here is pretty horrible: we scan each
389*53ee8cc1Swenshuai.xi 	 * property of a node in fdt_getprop(), then if that didn't
390*53ee8cc1Swenshuai.xi 	 * find what we want, we scan over them again making our way
391*53ee8cc1Swenshuai.xi 	 * to the next node.  Still it's the easiest to implement
392*53ee8cc1Swenshuai.xi 	 * approach; performance can come later. */
393*53ee8cc1Swenshuai.xi 	for (offset = fdt_next_node(fdt, startoffset, NULL);
394*53ee8cc1Swenshuai.xi 	     offset >= 0;
395*53ee8cc1Swenshuai.xi 	     offset = fdt_next_node(fdt, offset, NULL)) {
396*53ee8cc1Swenshuai.xi 		val = fdt_getprop(fdt, offset, propname, &len);
397*53ee8cc1Swenshuai.xi 		if (val && (len == proplen)
398*53ee8cc1Swenshuai.xi 		    && (memcmp(val, propval, len) == 0))
399*53ee8cc1Swenshuai.xi 			return offset;
400*53ee8cc1Swenshuai.xi 	}
401*53ee8cc1Swenshuai.xi 
402*53ee8cc1Swenshuai.xi 	return offset; /* error from fdt_next_node() */
403*53ee8cc1Swenshuai.xi }
404*53ee8cc1Swenshuai.xi 
fdt_node_offset_by_phandle(const void * fdt,uint32_t phandle)405*53ee8cc1Swenshuai.xi int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle)
406*53ee8cc1Swenshuai.xi {
407*53ee8cc1Swenshuai.xi 	if ((phandle == 0) || (phandle == -1))
408*53ee8cc1Swenshuai.xi 		return -FDT_ERR_BADPHANDLE;
409*53ee8cc1Swenshuai.xi 	phandle = cpu_to_fdt32(phandle);
410*53ee8cc1Swenshuai.xi 	return fdt_node_offset_by_prop_value(fdt, -1, "linux,phandle",
411*53ee8cc1Swenshuai.xi 					     &phandle, sizeof(phandle));
412*53ee8cc1Swenshuai.xi }
413*53ee8cc1Swenshuai.xi 
_stringlist_contains(const char * strlist,int listlen,const char * str)414*53ee8cc1Swenshuai.xi static int _stringlist_contains(const char *strlist, int listlen, const char *str)
415*53ee8cc1Swenshuai.xi {
416*53ee8cc1Swenshuai.xi 	int len = strlen(str);
417*53ee8cc1Swenshuai.xi 	const char *p;
418*53ee8cc1Swenshuai.xi 
419*53ee8cc1Swenshuai.xi 	while (listlen >= len) {
420*53ee8cc1Swenshuai.xi 		if (memcmp(str, strlist, len+1) == 0)
421*53ee8cc1Swenshuai.xi 			return 1;
422*53ee8cc1Swenshuai.xi 		p = memchr(strlist, '\0', listlen);
423*53ee8cc1Swenshuai.xi 		if (!p)
424*53ee8cc1Swenshuai.xi 			return 0; /* malformed strlist.. */
425*53ee8cc1Swenshuai.xi 		listlen -= (p-strlist) + 1;
426*53ee8cc1Swenshuai.xi 		strlist = p + 1;
427*53ee8cc1Swenshuai.xi 	}
428*53ee8cc1Swenshuai.xi 	return 0;
429*53ee8cc1Swenshuai.xi }
430*53ee8cc1Swenshuai.xi 
fdt_node_check_compatible(const void * fdt,int nodeoffset,const char * compatible)431*53ee8cc1Swenshuai.xi int fdt_node_check_compatible(const void *fdt, int nodeoffset,
432*53ee8cc1Swenshuai.xi 			      const char *compatible)
433*53ee8cc1Swenshuai.xi {
434*53ee8cc1Swenshuai.xi 	const void *prop;
435*53ee8cc1Swenshuai.xi 	int len;
436*53ee8cc1Swenshuai.xi 
437*53ee8cc1Swenshuai.xi 	prop = fdt_getprop(fdt, nodeoffset, "compatible", &len);
438*53ee8cc1Swenshuai.xi 	if (!prop)
439*53ee8cc1Swenshuai.xi 		return len;
440*53ee8cc1Swenshuai.xi 	if (_stringlist_contains(prop, len, compatible))
441*53ee8cc1Swenshuai.xi 		return 0;
442*53ee8cc1Swenshuai.xi 	else
443*53ee8cc1Swenshuai.xi 		return 1;
444*53ee8cc1Swenshuai.xi }
445*53ee8cc1Swenshuai.xi 
fdt_node_offset_by_compatible(const void * fdt,int startoffset,const char * compatible)446*53ee8cc1Swenshuai.xi int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
447*53ee8cc1Swenshuai.xi 				  const char *compatible)
448*53ee8cc1Swenshuai.xi {
449*53ee8cc1Swenshuai.xi 	int offset, err;
450*53ee8cc1Swenshuai.xi 
451*53ee8cc1Swenshuai.xi 	FDT_CHECK_HEADER(fdt);
452*53ee8cc1Swenshuai.xi 
453*53ee8cc1Swenshuai.xi 	/* FIXME: The algorithm here is pretty horrible: we scan each
454*53ee8cc1Swenshuai.xi 	 * property of a node in fdt_node_check_compatible(), then if
455*53ee8cc1Swenshuai.xi 	 * that didn't find what we want, we scan over them again
456*53ee8cc1Swenshuai.xi 	 * making our way to the next node.  Still it's the easiest to
457*53ee8cc1Swenshuai.xi 	 * implement approach; performance can come later. */
458*53ee8cc1Swenshuai.xi 	for (offset = fdt_next_node(fdt, startoffset, NULL);
459*53ee8cc1Swenshuai.xi 	     offset >= 0;
460*53ee8cc1Swenshuai.xi 	     offset = fdt_next_node(fdt, offset, NULL)) {
461*53ee8cc1Swenshuai.xi 		err = fdt_node_check_compatible(fdt, offset, compatible);
462*53ee8cc1Swenshuai.xi 		if ((err < 0) && (err != -FDT_ERR_NOTFOUND))
463*53ee8cc1Swenshuai.xi 			return err;
464*53ee8cc1Swenshuai.xi 		else if (err == 0)
465*53ee8cc1Swenshuai.xi 			return offset;
466*53ee8cc1Swenshuai.xi 	}
467*53ee8cc1Swenshuai.xi 
468*53ee8cc1Swenshuai.xi 	return offset; /* error from fdt_next_node() */
469*53ee8cc1Swenshuai.xi }
470