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