1*d18719a4STom Rini /*
2*d18719a4STom Rini * libfdt - Flat Device Tree manipulation
3*d18719a4STom Rini * Copyright (C) 2006 David Gibson, IBM Corporation.
4*d18719a4STom Rini *
5*d18719a4STom Rini * libfdt is dual licensed: you can use it either under the terms of
6*d18719a4STom Rini * the GPL, or the BSD license, at your option.
7*d18719a4STom Rini *
8*d18719a4STom Rini * a) This library is free software; you can redistribute it and/or
9*d18719a4STom Rini * modify it under the terms of the GNU General Public License as
10*d18719a4STom Rini * published by the Free Software Foundation; either version 2 of the
11*d18719a4STom Rini * License, or (at your option) any later version.
12*d18719a4STom Rini *
13*d18719a4STom Rini * This library is distributed in the hope that it will be useful,
14*d18719a4STom Rini * but WITHOUT ANY WARRANTY; without even the implied warranty of
15*d18719a4STom Rini * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16*d18719a4STom Rini * GNU General Public License for more details.
17*d18719a4STom Rini *
18*d18719a4STom Rini * You should have received a copy of the GNU General Public
19*d18719a4STom Rini * License along with this library; if not, write to the Free
20*d18719a4STom Rini * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
21*d18719a4STom Rini * MA 02110-1301 USA
22*d18719a4STom Rini *
23*d18719a4STom Rini * Alternatively,
24*d18719a4STom Rini *
25*d18719a4STom Rini * b) Redistribution and use in source and binary forms, with or
26*d18719a4STom Rini * without modification, are permitted provided that the following
27*d18719a4STom Rini * conditions are met:
28*d18719a4STom Rini *
29*d18719a4STom Rini * 1. Redistributions of source code must retain the above
30*d18719a4STom Rini * copyright notice, this list of conditions and the following
31*d18719a4STom Rini * disclaimer.
32*d18719a4STom Rini * 2. Redistributions in binary form must reproduce the above
33*d18719a4STom Rini * copyright notice, this list of conditions and the following
34*d18719a4STom Rini * disclaimer in the documentation and/or other materials
35*d18719a4STom Rini * provided with the distribution.
36*d18719a4STom Rini *
37*d18719a4STom Rini * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
38*d18719a4STom Rini * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
39*d18719a4STom Rini * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
40*d18719a4STom Rini * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
41*d18719a4STom Rini * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
42*d18719a4STom Rini * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
43*d18719a4STom Rini * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
44*d18719a4STom Rini * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
45*d18719a4STom Rini * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
46*d18719a4STom Rini * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
47*d18719a4STom Rini * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
48*d18719a4STom Rini * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
49*d18719a4STom Rini * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
50*d18719a4STom Rini */
51*d18719a4STom Rini #include "libfdt_env.h"
52*d18719a4STom Rini
53*d18719a4STom Rini #include <fdt.h>
54*d18719a4STom Rini #include <libfdt.h>
55*d18719a4STom Rini
56*d18719a4STom Rini #include "libfdt_internal.h"
57*d18719a4STom Rini
_fdt_nodename_eq(const void * fdt,int offset,const char * s,int len)58*d18719a4STom Rini static int _fdt_nodename_eq(const void *fdt, int offset,
59*d18719a4STom Rini const char *s, int len)
60*d18719a4STom Rini {
61*d18719a4STom Rini const char *p = fdt_offset_ptr(fdt, offset + FDT_TAGSIZE, len+1);
62*d18719a4STom Rini
63*d18719a4STom Rini if (!p)
64*d18719a4STom Rini /* short match */
65*d18719a4STom Rini return 0;
66*d18719a4STom Rini
67*d18719a4STom Rini if (memcmp(p, s, len) != 0)
68*d18719a4STom Rini return 0;
69*d18719a4STom Rini
70*d18719a4STom Rini if (p[len] == '\0')
71*d18719a4STom Rini return 1;
72*d18719a4STom Rini else if (!memchr(s, '@', len) && (p[len] == '@'))
73*d18719a4STom Rini return 1;
74*d18719a4STom Rini else
75*d18719a4STom Rini return 0;
76*d18719a4STom Rini }
77*d18719a4STom Rini
fdt_string(const void * fdt,int stroffset)78*d18719a4STom Rini const char *fdt_string(const void *fdt, int stroffset)
79*d18719a4STom Rini {
80*d18719a4STom Rini return (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset;
81*d18719a4STom Rini }
82*d18719a4STom Rini
_fdt_string_eq(const void * fdt,int stroffset,const char * s,int len)83*d18719a4STom Rini static int _fdt_string_eq(const void *fdt, int stroffset,
84*d18719a4STom Rini const char *s, int len)
85*d18719a4STom Rini {
86*d18719a4STom Rini const char *p = fdt_string(fdt, stroffset);
87*d18719a4STom Rini
88*d18719a4STom Rini return (strlen(p) == len) && (memcmp(p, s, len) == 0);
89*d18719a4STom Rini }
90*d18719a4STom Rini
fdt_get_max_phandle(const void * fdt)91*d18719a4STom Rini uint32_t fdt_get_max_phandle(const void *fdt)
92*d18719a4STom Rini {
93*d18719a4STom Rini uint32_t max_phandle = 0;
94*d18719a4STom Rini int offset;
95*d18719a4STom Rini
96*d18719a4STom Rini for (offset = fdt_next_node(fdt, -1, NULL);;
97*d18719a4STom Rini offset = fdt_next_node(fdt, offset, NULL)) {
98*d18719a4STom Rini uint32_t phandle;
99*d18719a4STom Rini
100*d18719a4STom Rini if (offset == -FDT_ERR_NOTFOUND)
101*d18719a4STom Rini return max_phandle;
102*d18719a4STom Rini
103*d18719a4STom Rini if (offset < 0)
104*d18719a4STom Rini return (uint32_t)-1;
105*d18719a4STom Rini
106*d18719a4STom Rini phandle = fdt_get_phandle(fdt, offset);
107*d18719a4STom Rini if (phandle == (uint32_t)-1)
108*d18719a4STom Rini continue;
109*d18719a4STom Rini
110*d18719a4STom Rini if (phandle > max_phandle)
111*d18719a4STom Rini max_phandle = phandle;
112*d18719a4STom Rini }
113*d18719a4STom Rini
114*d18719a4STom Rini return 0;
115*d18719a4STom Rini }
116*d18719a4STom Rini
fdt_get_mem_rsv(const void * fdt,int n,uint64_t * address,uint64_t * size)117*d18719a4STom Rini int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
118*d18719a4STom Rini {
119*d18719a4STom Rini FDT_CHECK_HEADER(fdt);
120*d18719a4STom Rini *address = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->address);
121*d18719a4STom Rini *size = fdt64_to_cpu(_fdt_mem_rsv(fdt, n)->size);
122*d18719a4STom Rini return 0;
123*d18719a4STom Rini }
124*d18719a4STom Rini
fdt_num_mem_rsv(const void * fdt)125*d18719a4STom Rini int fdt_num_mem_rsv(const void *fdt)
126*d18719a4STom Rini {
127*d18719a4STom Rini int i = 0;
128*d18719a4STom Rini
129*d18719a4STom Rini while (fdt64_to_cpu(_fdt_mem_rsv(fdt, i)->size) != 0)
130*d18719a4STom Rini i++;
131*d18719a4STom Rini return i;
132*d18719a4STom Rini }
133*d18719a4STom Rini
_nextprop(const void * fdt,int offset)134*d18719a4STom Rini static int _nextprop(const void *fdt, int offset)
135*d18719a4STom Rini {
136*d18719a4STom Rini uint32_t tag;
137*d18719a4STom Rini int nextoffset;
138*d18719a4STom Rini
139*d18719a4STom Rini do {
140*d18719a4STom Rini tag = fdt_next_tag(fdt, offset, &nextoffset);
141*d18719a4STom Rini
142*d18719a4STom Rini switch (tag) {
143*d18719a4STom Rini case FDT_END:
144*d18719a4STom Rini if (nextoffset >= 0)
145*d18719a4STom Rini return -FDT_ERR_BADSTRUCTURE;
146*d18719a4STom Rini else
147*d18719a4STom Rini return nextoffset;
148*d18719a4STom Rini
149*d18719a4STom Rini case FDT_PROP:
150*d18719a4STom Rini return offset;
151*d18719a4STom Rini }
152*d18719a4STom Rini offset = nextoffset;
153*d18719a4STom Rini } while (tag == FDT_NOP);
154*d18719a4STom Rini
155*d18719a4STom Rini return -FDT_ERR_NOTFOUND;
156*d18719a4STom Rini }
157*d18719a4STom Rini
fdt_subnode_offset_namelen(const void * fdt,int offset,const char * name,int namelen)158*d18719a4STom Rini int fdt_subnode_offset_namelen(const void *fdt, int offset,
159*d18719a4STom Rini const char *name, int namelen)
160*d18719a4STom Rini {
161*d18719a4STom Rini int depth;
162*d18719a4STom Rini
163*d18719a4STom Rini FDT_CHECK_HEADER(fdt);
164*d18719a4STom Rini
165*d18719a4STom Rini for (depth = 0;
166*d18719a4STom Rini (offset >= 0) && (depth >= 0);
167*d18719a4STom Rini offset = fdt_next_node(fdt, offset, &depth))
168*d18719a4STom Rini if ((depth == 1)
169*d18719a4STom Rini && _fdt_nodename_eq(fdt, offset, name, namelen))
170*d18719a4STom Rini return offset;
171*d18719a4STom Rini
172*d18719a4STom Rini if (depth < 0)
173*d18719a4STom Rini return -FDT_ERR_NOTFOUND;
174*d18719a4STom Rini return offset; /* error */
175*d18719a4STom Rini }
176*d18719a4STom Rini
fdt_subnode_offset(const void * fdt,int parentoffset,const char * name)177*d18719a4STom Rini int fdt_subnode_offset(const void *fdt, int parentoffset,
178*d18719a4STom Rini const char *name)
179*d18719a4STom Rini {
180*d18719a4STom Rini return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name));
181*d18719a4STom Rini }
182*d18719a4STom Rini
fdt_path_offset_namelen(const void * fdt,const char * path,int namelen)183*d18719a4STom Rini int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen)
184*d18719a4STom Rini {
185*d18719a4STom Rini const char *end = path + namelen;
186*d18719a4STom Rini const char *p = path;
187*d18719a4STom Rini int offset = 0;
188*d18719a4STom Rini
189*d18719a4STom Rini FDT_CHECK_HEADER(fdt);
190*d18719a4STom Rini
191*d18719a4STom Rini /* see if we have an alias */
192*d18719a4STom Rini if (*path != '/') {
193*d18719a4STom Rini const char *q = memchr(path, '/', end - p);
194*d18719a4STom Rini
195*d18719a4STom Rini if (!q)
196*d18719a4STom Rini q = end;
197*d18719a4STom Rini
198*d18719a4STom Rini p = fdt_get_alias_namelen(fdt, p, q - p);
199*d18719a4STom Rini if (!p)
200*d18719a4STom Rini return -FDT_ERR_BADPATH;
201*d18719a4STom Rini offset = fdt_path_offset(fdt, p);
202*d18719a4STom Rini
203*d18719a4STom Rini p = q;
204*d18719a4STom Rini }
205*d18719a4STom Rini
206*d18719a4STom Rini while (p < end) {
207*d18719a4STom Rini const char *q;
208*d18719a4STom Rini
209*d18719a4STom Rini while (*p == '/') {
210*d18719a4STom Rini p++;
211*d18719a4STom Rini if (p == end)
212*d18719a4STom Rini return offset;
213*d18719a4STom Rini }
214*d18719a4STom Rini q = memchr(p, '/', end - p);
215*d18719a4STom Rini if (! q)
216*d18719a4STom Rini q = end;
217*d18719a4STom Rini
218*d18719a4STom Rini offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p);
219*d18719a4STom Rini if (offset < 0)
220*d18719a4STom Rini return offset;
221*d18719a4STom Rini
222*d18719a4STom Rini p = q;
223*d18719a4STom Rini }
224*d18719a4STom Rini
225*d18719a4STom Rini return offset;
226*d18719a4STom Rini }
227*d18719a4STom Rini
fdt_path_offset(const void * fdt,const char * path)228*d18719a4STom Rini int fdt_path_offset(const void *fdt, const char *path)
229*d18719a4STom Rini {
230*d18719a4STom Rini return fdt_path_offset_namelen(fdt, path, strlen(path));
231*d18719a4STom Rini }
232*d18719a4STom Rini
fdt_get_name(const void * fdt,int nodeoffset,int * len)233*d18719a4STom Rini const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
234*d18719a4STom Rini {
235*d18719a4STom Rini const struct fdt_node_header *nh = _fdt_offset_ptr(fdt, nodeoffset);
236*d18719a4STom Rini int err;
237*d18719a4STom Rini
238*d18719a4STom Rini if (((err = fdt_check_header(fdt)) != 0)
239*d18719a4STom Rini || ((err = _fdt_check_node_offset(fdt, nodeoffset)) < 0))
240*d18719a4STom Rini goto fail;
241*d18719a4STom Rini
242*d18719a4STom Rini if (len)
243*d18719a4STom Rini *len = strlen(nh->name);
244*d18719a4STom Rini
245*d18719a4STom Rini return nh->name;
246*d18719a4STom Rini
247*d18719a4STom Rini fail:
248*d18719a4STom Rini if (len)
249*d18719a4STom Rini *len = err;
250*d18719a4STom Rini return NULL;
251*d18719a4STom Rini }
252*d18719a4STom Rini
fdt_first_property_offset(const void * fdt,int nodeoffset)253*d18719a4STom Rini int fdt_first_property_offset(const void *fdt, int nodeoffset)
254*d18719a4STom Rini {
255*d18719a4STom Rini int offset;
256*d18719a4STom Rini
257*d18719a4STom Rini if ((offset = _fdt_check_node_offset(fdt, nodeoffset)) < 0)
258*d18719a4STom Rini return offset;
259*d18719a4STom Rini
260*d18719a4STom Rini return _nextprop(fdt, offset);
261*d18719a4STom Rini }
262*d18719a4STom Rini
fdt_next_property_offset(const void * fdt,int offset)263*d18719a4STom Rini int fdt_next_property_offset(const void *fdt, int offset)
264*d18719a4STom Rini {
265*d18719a4STom Rini if ((offset = _fdt_check_prop_offset(fdt, offset)) < 0)
266*d18719a4STom Rini return offset;
267*d18719a4STom Rini
268*d18719a4STom Rini return _nextprop(fdt, offset);
269*d18719a4STom Rini }
270*d18719a4STom Rini
fdt_get_property_by_offset(const void * fdt,int offset,int * lenp)271*d18719a4STom Rini const struct fdt_property *fdt_get_property_by_offset(const void *fdt,
272*d18719a4STom Rini int offset,
273*d18719a4STom Rini int *lenp)
274*d18719a4STom Rini {
275*d18719a4STom Rini int err;
276*d18719a4STom Rini const struct fdt_property *prop;
277*d18719a4STom Rini
278*d18719a4STom Rini if ((err = _fdt_check_prop_offset(fdt, offset)) < 0) {
279*d18719a4STom Rini if (lenp)
280*d18719a4STom Rini *lenp = err;
281*d18719a4STom Rini return NULL;
282*d18719a4STom Rini }
283*d18719a4STom Rini
284*d18719a4STom Rini prop = _fdt_offset_ptr(fdt, offset);
285*d18719a4STom Rini
286*d18719a4STom Rini if (lenp)
287*d18719a4STom Rini *lenp = fdt32_to_cpu(prop->len);
288*d18719a4STom Rini
289*d18719a4STom Rini return prop;
290*d18719a4STom Rini }
291*d18719a4STom Rini
fdt_get_property_namelen(const void * fdt,int offset,const char * name,int namelen,int * lenp)292*d18719a4STom Rini const struct fdt_property *fdt_get_property_namelen(const void *fdt,
293*d18719a4STom Rini int offset,
294*d18719a4STom Rini const char *name,
295*d18719a4STom Rini int namelen, int *lenp)
296*d18719a4STom Rini {
297*d18719a4STom Rini for (offset = fdt_first_property_offset(fdt, offset);
298*d18719a4STom Rini (offset >= 0);
299*d18719a4STom Rini (offset = fdt_next_property_offset(fdt, offset))) {
300*d18719a4STom Rini const struct fdt_property *prop;
301*d18719a4STom Rini
302*d18719a4STom Rini if (!(prop = fdt_get_property_by_offset(fdt, offset, lenp))) {
303*d18719a4STom Rini offset = -FDT_ERR_INTERNAL;
304*d18719a4STom Rini break;
305*d18719a4STom Rini }
306*d18719a4STom Rini if (_fdt_string_eq(fdt, fdt32_to_cpu(prop->nameoff),
307*d18719a4STom Rini name, namelen))
308*d18719a4STom Rini return prop;
309*d18719a4STom Rini }
310*d18719a4STom Rini
311*d18719a4STom Rini if (lenp)
312*d18719a4STom Rini *lenp = offset;
313*d18719a4STom Rini return NULL;
314*d18719a4STom Rini }
315*d18719a4STom Rini
fdt_get_property(const void * fdt,int nodeoffset,const char * name,int * lenp)316*d18719a4STom Rini const struct fdt_property *fdt_get_property(const void *fdt,
317*d18719a4STom Rini int nodeoffset,
318*d18719a4STom Rini const char *name, int *lenp)
319*d18719a4STom Rini {
320*d18719a4STom Rini return fdt_get_property_namelen(fdt, nodeoffset, name,
321*d18719a4STom Rini strlen(name), lenp);
322*d18719a4STom Rini }
323*d18719a4STom Rini
fdt_getprop_namelen(const void * fdt,int nodeoffset,const char * name,int namelen,int * lenp)324*d18719a4STom Rini const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
325*d18719a4STom Rini const char *name, int namelen, int *lenp)
326*d18719a4STom Rini {
327*d18719a4STom Rini const struct fdt_property *prop;
328*d18719a4STom Rini
329*d18719a4STom Rini prop = fdt_get_property_namelen(fdt, nodeoffset, name, namelen, lenp);
330*d18719a4STom Rini if (!prop)
331*d18719a4STom Rini return NULL;
332*d18719a4STom Rini
333*d18719a4STom Rini return prop->data;
334*d18719a4STom Rini }
335*d18719a4STom Rini
fdt_getprop_by_offset(const void * fdt,int offset,const char ** namep,int * lenp)336*d18719a4STom Rini const void *fdt_getprop_by_offset(const void *fdt, int offset,
337*d18719a4STom Rini const char **namep, int *lenp)
338*d18719a4STom Rini {
339*d18719a4STom Rini const struct fdt_property *prop;
340*d18719a4STom Rini
341*d18719a4STom Rini prop = fdt_get_property_by_offset(fdt, offset, lenp);
342*d18719a4STom Rini if (!prop)
343*d18719a4STom Rini return NULL;
344*d18719a4STom Rini if (namep)
345*d18719a4STom Rini *namep = fdt_string(fdt, fdt32_to_cpu(prop->nameoff));
346*d18719a4STom Rini return prop->data;
347*d18719a4STom Rini }
348*d18719a4STom Rini
fdt_getprop(const void * fdt,int nodeoffset,const char * name,int * lenp)349*d18719a4STom Rini const void *fdt_getprop(const void *fdt, int nodeoffset,
350*d18719a4STom Rini const char *name, int *lenp)
351*d18719a4STom Rini {
352*d18719a4STom Rini return fdt_getprop_namelen(fdt, nodeoffset, name, strlen(name), lenp);
353*d18719a4STom Rini }
354*d18719a4STom Rini
fdt_get_phandle(const void * fdt,int nodeoffset)355*d18719a4STom Rini uint32_t fdt_get_phandle(const void *fdt, int nodeoffset)
356*d18719a4STom Rini {
357*d18719a4STom Rini const fdt32_t *php;
358*d18719a4STom Rini int len;
359*d18719a4STom Rini
360*d18719a4STom Rini /* FIXME: This is a bit sub-optimal, since we potentially scan
361*d18719a4STom Rini * over all the properties twice. */
362*d18719a4STom Rini php = fdt_getprop(fdt, nodeoffset, "phandle", &len);
363*d18719a4STom Rini if (!php || (len != sizeof(*php))) {
364*d18719a4STom Rini php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len);
365*d18719a4STom Rini if (!php || (len != sizeof(*php)))
366*d18719a4STom Rini return 0;
367*d18719a4STom Rini }
368*d18719a4STom Rini
369*d18719a4STom Rini return fdt32_to_cpu(*php);
370*d18719a4STom Rini }
371*d18719a4STom Rini
fdt_get_alias_namelen(const void * fdt,const char * name,int namelen)372*d18719a4STom Rini const char *fdt_get_alias_namelen(const void *fdt,
373*d18719a4STom Rini const char *name, int namelen)
374*d18719a4STom Rini {
375*d18719a4STom Rini int aliasoffset;
376*d18719a4STom Rini
377*d18719a4STom Rini aliasoffset = fdt_path_offset(fdt, "/aliases");
378*d18719a4STom Rini if (aliasoffset < 0)
379*d18719a4STom Rini return NULL;
380*d18719a4STom Rini
381*d18719a4STom Rini return fdt_getprop_namelen(fdt, aliasoffset, name, namelen, NULL);
382*d18719a4STom Rini }
383*d18719a4STom Rini
fdt_get_alias(const void * fdt,const char * name)384*d18719a4STom Rini const char *fdt_get_alias(const void *fdt, const char *name)
385*d18719a4STom Rini {
386*d18719a4STom Rini return fdt_get_alias_namelen(fdt, name, strlen(name));
387*d18719a4STom Rini }
388*d18719a4STom Rini
fdt_get_path(const void * fdt,int nodeoffset,char * buf,int buflen)389*d18719a4STom Rini int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)
390*d18719a4STom Rini {
391*d18719a4STom Rini int pdepth = 0, p = 0;
392*d18719a4STom Rini int offset, depth, namelen;
393*d18719a4STom Rini const char *name;
394*d18719a4STom Rini
395*d18719a4STom Rini FDT_CHECK_HEADER(fdt);
396*d18719a4STom Rini
397*d18719a4STom Rini if (buflen < 2)
398*d18719a4STom Rini return -FDT_ERR_NOSPACE;
399*d18719a4STom Rini
400*d18719a4STom Rini for (offset = 0, depth = 0;
401*d18719a4STom Rini (offset >= 0) && (offset <= nodeoffset);
402*d18719a4STom Rini offset = fdt_next_node(fdt, offset, &depth)) {
403*d18719a4STom Rini while (pdepth > depth) {
404*d18719a4STom Rini do {
405*d18719a4STom Rini p--;
406*d18719a4STom Rini } while (buf[p-1] != '/');
407*d18719a4STom Rini pdepth--;
408*d18719a4STom Rini }
409*d18719a4STom Rini
410*d18719a4STom Rini if (pdepth >= depth) {
411*d18719a4STom Rini name = fdt_get_name(fdt, offset, &namelen);
412*d18719a4STom Rini if (!name)
413*d18719a4STom Rini return namelen;
414*d18719a4STom Rini if ((p + namelen + 1) <= buflen) {
415*d18719a4STom Rini memcpy(buf + p, name, namelen);
416*d18719a4STom Rini p += namelen;
417*d18719a4STom Rini buf[p++] = '/';
418*d18719a4STom Rini pdepth++;
419*d18719a4STom Rini }
420*d18719a4STom Rini }
421*d18719a4STom Rini
422*d18719a4STom Rini if (offset == nodeoffset) {
423*d18719a4STom Rini if (pdepth < (depth + 1))
424*d18719a4STom Rini return -FDT_ERR_NOSPACE;
425*d18719a4STom Rini
426*d18719a4STom Rini if (p > 1) /* special case so that root path is "/", not "" */
427*d18719a4STom Rini p--;
428*d18719a4STom Rini buf[p] = '\0';
429*d18719a4STom Rini return 0;
430*d18719a4STom Rini }
431*d18719a4STom Rini }
432*d18719a4STom Rini
433*d18719a4STom Rini if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
434*d18719a4STom Rini return -FDT_ERR_BADOFFSET;
435*d18719a4STom Rini else if (offset == -FDT_ERR_BADOFFSET)
436*d18719a4STom Rini return -FDT_ERR_BADSTRUCTURE;
437*d18719a4STom Rini
438*d18719a4STom Rini return offset; /* error from fdt_next_node() */
439*d18719a4STom Rini }
440*d18719a4STom Rini
fdt_supernode_atdepth_offset(const void * fdt,int nodeoffset,int supernodedepth,int * nodedepth)441*d18719a4STom Rini int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
442*d18719a4STom Rini int supernodedepth, int *nodedepth)
443*d18719a4STom Rini {
444*d18719a4STom Rini int offset, depth;
445*d18719a4STom Rini int supernodeoffset = -FDT_ERR_INTERNAL;
446*d18719a4STom Rini
447*d18719a4STom Rini FDT_CHECK_HEADER(fdt);
448*d18719a4STom Rini
449*d18719a4STom Rini if (supernodedepth < 0)
450*d18719a4STom Rini return -FDT_ERR_NOTFOUND;
451*d18719a4STom Rini
452*d18719a4STom Rini for (offset = 0, depth = 0;
453*d18719a4STom Rini (offset >= 0) && (offset <= nodeoffset);
454*d18719a4STom Rini offset = fdt_next_node(fdt, offset, &depth)) {
455*d18719a4STom Rini if (depth == supernodedepth)
456*d18719a4STom Rini supernodeoffset = offset;
457*d18719a4STom Rini
458*d18719a4STom Rini if (offset == nodeoffset) {
459*d18719a4STom Rini if (nodedepth)
460*d18719a4STom Rini *nodedepth = depth;
461*d18719a4STom Rini
462*d18719a4STom Rini if (supernodedepth > depth)
463*d18719a4STom Rini return -FDT_ERR_NOTFOUND;
464*d18719a4STom Rini else
465*d18719a4STom Rini return supernodeoffset;
466*d18719a4STom Rini }
467*d18719a4STom Rini }
468*d18719a4STom Rini
469*d18719a4STom Rini if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
470*d18719a4STom Rini return -FDT_ERR_BADOFFSET;
471*d18719a4STom Rini else if (offset == -FDT_ERR_BADOFFSET)
472*d18719a4STom Rini return -FDT_ERR_BADSTRUCTURE;
473*d18719a4STom Rini
474*d18719a4STom Rini return offset; /* error from fdt_next_node() */
475*d18719a4STom Rini }
476*d18719a4STom Rini
fdt_node_depth(const void * fdt,int nodeoffset)477*d18719a4STom Rini int fdt_node_depth(const void *fdt, int nodeoffset)
478*d18719a4STom Rini {
479*d18719a4STom Rini int nodedepth;
480*d18719a4STom Rini int err;
481*d18719a4STom Rini
482*d18719a4STom Rini err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth);
483*d18719a4STom Rini if (err)
484*d18719a4STom Rini return (err < 0) ? err : -FDT_ERR_INTERNAL;
485*d18719a4STom Rini return nodedepth;
486*d18719a4STom Rini }
487*d18719a4STom Rini
fdt_parent_offset(const void * fdt,int nodeoffset)488*d18719a4STom Rini int fdt_parent_offset(const void *fdt, int nodeoffset)
489*d18719a4STom Rini {
490*d18719a4STom Rini int nodedepth = fdt_node_depth(fdt, nodeoffset);
491*d18719a4STom Rini
492*d18719a4STom Rini if (nodedepth < 0)
493*d18719a4STom Rini return nodedepth;
494*d18719a4STom Rini return fdt_supernode_atdepth_offset(fdt, nodeoffset,
495*d18719a4STom Rini nodedepth - 1, NULL);
496*d18719a4STom Rini }
497*d18719a4STom Rini
fdt_node_offset_by_prop_value(const void * fdt,int startoffset,const char * propname,const void * propval,int proplen)498*d18719a4STom Rini int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
499*d18719a4STom Rini const char *propname,
500*d18719a4STom Rini const void *propval, int proplen)
501*d18719a4STom Rini {
502*d18719a4STom Rini int offset;
503*d18719a4STom Rini const void *val;
504*d18719a4STom Rini int len;
505*d18719a4STom Rini
506*d18719a4STom Rini FDT_CHECK_HEADER(fdt);
507*d18719a4STom Rini
508*d18719a4STom Rini /* FIXME: The algorithm here is pretty horrible: we scan each
509*d18719a4STom Rini * property of a node in fdt_getprop(), then if that didn't
510*d18719a4STom Rini * find what we want, we scan over them again making our way
511*d18719a4STom Rini * to the next node. Still it's the easiest to implement
512*d18719a4STom Rini * approach; performance can come later. */
513*d18719a4STom Rini for (offset = fdt_next_node(fdt, startoffset, NULL);
514*d18719a4STom Rini offset >= 0;
515*d18719a4STom Rini offset = fdt_next_node(fdt, offset, NULL)) {
516*d18719a4STom Rini val = fdt_getprop(fdt, offset, propname, &len);
517*d18719a4STom Rini if (val && (len == proplen)
518*d18719a4STom Rini && (memcmp(val, propval, len) == 0))
519*d18719a4STom Rini return offset;
520*d18719a4STom Rini }
521*d18719a4STom Rini
522*d18719a4STom Rini return offset; /* error from fdt_next_node() */
523*d18719a4STom Rini }
524*d18719a4STom Rini
fdt_node_offset_by_phandle(const void * fdt,uint32_t phandle)525*d18719a4STom Rini int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle)
526*d18719a4STom Rini {
527*d18719a4STom Rini int offset;
528*d18719a4STom Rini
529*d18719a4STom Rini if ((phandle == 0) || (phandle == -1))
530*d18719a4STom Rini return -FDT_ERR_BADPHANDLE;
531*d18719a4STom Rini
532*d18719a4STom Rini FDT_CHECK_HEADER(fdt);
533*d18719a4STom Rini
534*d18719a4STom Rini /* FIXME: The algorithm here is pretty horrible: we
535*d18719a4STom Rini * potentially scan each property of a node in
536*d18719a4STom Rini * fdt_get_phandle(), then if that didn't find what
537*d18719a4STom Rini * we want, we scan over them again making our way to the next
538*d18719a4STom Rini * node. Still it's the easiest to implement approach;
539*d18719a4STom Rini * performance can come later. */
540*d18719a4STom Rini for (offset = fdt_next_node(fdt, -1, NULL);
541*d18719a4STom Rini offset >= 0;
542*d18719a4STom Rini offset = fdt_next_node(fdt, offset, NULL)) {
543*d18719a4STom Rini if (fdt_get_phandle(fdt, offset) == phandle)
544*d18719a4STom Rini return offset;
545*d18719a4STom Rini }
546*d18719a4STom Rini
547*d18719a4STom Rini return offset; /* error from fdt_next_node() */
548*d18719a4STom Rini }
549*d18719a4STom Rini
fdt_stringlist_contains(const char * strlist,int listlen,const char * str)550*d18719a4STom Rini int fdt_stringlist_contains(const char *strlist, int listlen, const char *str)
551*d18719a4STom Rini {
552*d18719a4STom Rini int len = strlen(str);
553*d18719a4STom Rini const char *p;
554*d18719a4STom Rini
555*d18719a4STom Rini while (listlen >= len) {
556*d18719a4STom Rini if (memcmp(str, strlist, len+1) == 0)
557*d18719a4STom Rini return 1;
558*d18719a4STom Rini p = memchr(strlist, '\0', listlen);
559*d18719a4STom Rini if (!p)
560*d18719a4STom Rini return 0; /* malformed strlist.. */
561*d18719a4STom Rini listlen -= (p-strlist) + 1;
562*d18719a4STom Rini strlist = p + 1;
563*d18719a4STom Rini }
564*d18719a4STom Rini return 0;
565*d18719a4STom Rini }
566*d18719a4STom Rini
fdt_stringlist_count(const void * fdt,int nodeoffset,const char * property)567*d18719a4STom Rini int fdt_stringlist_count(const void *fdt, int nodeoffset, const char *property)
568*d18719a4STom Rini {
569*d18719a4STom Rini const char *list, *end;
570*d18719a4STom Rini int length, count = 0;
571*d18719a4STom Rini
572*d18719a4STom Rini list = fdt_getprop(fdt, nodeoffset, property, &length);
573*d18719a4STom Rini if (!list)
574*d18719a4STom Rini return length;
575*d18719a4STom Rini
576*d18719a4STom Rini end = list + length;
577*d18719a4STom Rini
578*d18719a4STom Rini while (list < end) {
579*d18719a4STom Rini length = strnlen(list, end - list) + 1;
580*d18719a4STom Rini
581*d18719a4STom Rini /* Abort if the last string isn't properly NUL-terminated. */
582*d18719a4STom Rini if (list + length > end)
583*d18719a4STom Rini return -FDT_ERR_BADVALUE;
584*d18719a4STom Rini
585*d18719a4STom Rini list += length;
586*d18719a4STom Rini count++;
587*d18719a4STom Rini }
588*d18719a4STom Rini
589*d18719a4STom Rini return count;
590*d18719a4STom Rini }
591*d18719a4STom Rini
fdt_stringlist_search(const void * fdt,int nodeoffset,const char * property,const char * string)592*d18719a4STom Rini int fdt_stringlist_search(const void *fdt, int nodeoffset, const char *property,
593*d18719a4STom Rini const char *string)
594*d18719a4STom Rini {
595*d18719a4STom Rini int length, len, idx = 0;
596*d18719a4STom Rini const char *list, *end;
597*d18719a4STom Rini
598*d18719a4STom Rini list = fdt_getprop(fdt, nodeoffset, property, &length);
599*d18719a4STom Rini if (!list)
600*d18719a4STom Rini return length;
601*d18719a4STom Rini
602*d18719a4STom Rini len = strlen(string) + 1;
603*d18719a4STom Rini end = list + length;
604*d18719a4STom Rini
605*d18719a4STom Rini while (list < end) {
606*d18719a4STom Rini length = strnlen(list, end - list) + 1;
607*d18719a4STom Rini
608*d18719a4STom Rini /* Abort if the last string isn't properly NUL-terminated. */
609*d18719a4STom Rini if (list + length > end)
610*d18719a4STom Rini return -FDT_ERR_BADVALUE;
611*d18719a4STom Rini
612*d18719a4STom Rini if (length == len && memcmp(list, string, length) == 0)
613*d18719a4STom Rini return idx;
614*d18719a4STom Rini
615*d18719a4STom Rini list += length;
616*d18719a4STom Rini idx++;
617*d18719a4STom Rini }
618*d18719a4STom Rini
619*d18719a4STom Rini return -FDT_ERR_NOTFOUND;
620*d18719a4STom Rini }
621*d18719a4STom Rini
fdt_stringlist_get(const void * fdt,int nodeoffset,const char * property,int idx,int * lenp)622*d18719a4STom Rini const char *fdt_stringlist_get(const void *fdt, int nodeoffset,
623*d18719a4STom Rini const char *property, int idx,
624*d18719a4STom Rini int *lenp)
625*d18719a4STom Rini {
626*d18719a4STom Rini const char *list, *end;
627*d18719a4STom Rini int length;
628*d18719a4STom Rini
629*d18719a4STom Rini list = fdt_getprop(fdt, nodeoffset, property, &length);
630*d18719a4STom Rini if (!list) {
631*d18719a4STom Rini if (lenp)
632*d18719a4STom Rini *lenp = length;
633*d18719a4STom Rini
634*d18719a4STom Rini return NULL;
635*d18719a4STom Rini }
636*d18719a4STom Rini
637*d18719a4STom Rini end = list + length;
638*d18719a4STom Rini
639*d18719a4STom Rini while (list < end) {
640*d18719a4STom Rini length = strnlen(list, end - list) + 1;
641*d18719a4STom Rini
642*d18719a4STom Rini /* Abort if the last string isn't properly NUL-terminated. */
643*d18719a4STom Rini if (list + length > end) {
644*d18719a4STom Rini if (lenp)
645*d18719a4STom Rini *lenp = -FDT_ERR_BADVALUE;
646*d18719a4STom Rini
647*d18719a4STom Rini return NULL;
648*d18719a4STom Rini }
649*d18719a4STom Rini
650*d18719a4STom Rini if (idx == 0) {
651*d18719a4STom Rini if (lenp)
652*d18719a4STom Rini *lenp = length - 1;
653*d18719a4STom Rini
654*d18719a4STom Rini return list;
655*d18719a4STom Rini }
656*d18719a4STom Rini
657*d18719a4STom Rini list += length;
658*d18719a4STom Rini idx--;
659*d18719a4STom Rini }
660*d18719a4STom Rini
661*d18719a4STom Rini if (lenp)
662*d18719a4STom Rini *lenp = -FDT_ERR_NOTFOUND;
663*d18719a4STom Rini
664*d18719a4STom Rini return NULL;
665*d18719a4STom Rini }
666*d18719a4STom Rini
fdt_node_check_compatible(const void * fdt,int nodeoffset,const char * compatible)667*d18719a4STom Rini int fdt_node_check_compatible(const void *fdt, int nodeoffset,
668*d18719a4STom Rini const char *compatible)
669*d18719a4STom Rini {
670*d18719a4STom Rini const void *prop;
671*d18719a4STom Rini int len;
672*d18719a4STom Rini
673*d18719a4STom Rini prop = fdt_getprop(fdt, nodeoffset, "compatible", &len);
674*d18719a4STom Rini if (!prop)
675*d18719a4STom Rini return len;
676*d18719a4STom Rini
677*d18719a4STom Rini return !fdt_stringlist_contains(prop, len, compatible);
678*d18719a4STom Rini }
679*d18719a4STom Rini
fdt_node_offset_by_compatible(const void * fdt,int startoffset,const char * compatible)680*d18719a4STom Rini int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
681*d18719a4STom Rini const char *compatible)
682*d18719a4STom Rini {
683*d18719a4STom Rini int offset, err;
684*d18719a4STom Rini
685*d18719a4STom Rini FDT_CHECK_HEADER(fdt);
686*d18719a4STom Rini
687*d18719a4STom Rini /* FIXME: The algorithm here is pretty horrible: we scan each
688*d18719a4STom Rini * property of a node in fdt_node_check_compatible(), then if
689*d18719a4STom Rini * that didn't find what we want, we scan over them again
690*d18719a4STom Rini * making our way to the next node. Still it's the easiest to
691*d18719a4STom Rini * implement approach; performance can come later. */
692*d18719a4STom Rini for (offset = fdt_next_node(fdt, startoffset, NULL);
693*d18719a4STom Rini offset >= 0;
694*d18719a4STom Rini offset = fdt_next_node(fdt, offset, NULL)) {
695*d18719a4STom Rini err = fdt_node_check_compatible(fdt, offset, compatible);
696*d18719a4STom Rini if ((err < 0) && (err != -FDT_ERR_NOTFOUND))
697*d18719a4STom Rini return err;
698*d18719a4STom Rini else if (err == 0)
699*d18719a4STom Rini return offset;
700*d18719a4STom Rini }
701*d18719a4STom Rini
702*d18719a4STom Rini return offset; /* error from fdt_next_node() */
703*d18719a4STom Rini }
704