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