]>
git.ipfire.org Git - people/ms/u-boot.git/blob - lib/libfdt/fdt_ro.c
2 * libfdt - Flat Device Tree manipulation
3 * Copyright (C) 2006 David Gibson, IBM Corporation.
4 * SPDX-License-Identifier: GPL-2.0+ BSD-2-Clause
6 #include "libfdt_env.h"
15 #include "libfdt_internal.h"
17 static int _fdt_nodename_eq(const void *fdt
, int offset
,
18 const char *s
, int len
)
20 const char *p
= fdt_offset_ptr(fdt
, offset
+ FDT_TAGSIZE
, len
+1);
26 if (memcmp(p
, s
, len
) != 0)
31 else if (!memchr(s
, '@', len
) && (p
[len
] == '@'))
37 const char *fdt_string(const void *fdt
, int stroffset
)
39 return (const char *)fdt
+ fdt_off_dt_strings(fdt
) + stroffset
;
42 static int _fdt_string_eq(const void *fdt
, int stroffset
,
43 const char *s
, int len
)
45 const char *p
= fdt_string(fdt
, stroffset
);
47 return (strnlen(p
, len
+ 1) == len
) && (memcmp(p
, s
, len
) == 0);
50 int fdt_get_mem_rsv(const void *fdt
, int n
, uint64_t *address
, uint64_t *size
)
52 FDT_CHECK_HEADER(fdt
);
53 *address
= fdt64_to_cpu(_fdt_mem_rsv(fdt
, n
)->address
);
54 *size
= fdt64_to_cpu(_fdt_mem_rsv(fdt
, n
)->size
);
58 int fdt_num_mem_rsv(const void *fdt
)
62 while (fdt64_to_cpu(_fdt_mem_rsv(fdt
, i
)->size
) != 0)
67 static int _nextprop(const void *fdt
, int offset
)
73 tag
= fdt_next_tag(fdt
, offset
, &nextoffset
);
78 return -FDT_ERR_BADSTRUCTURE
;
86 } while (tag
== FDT_NOP
);
88 return -FDT_ERR_NOTFOUND
;
91 int fdt_subnode_offset_namelen(const void *fdt
, int offset
,
92 const char *name
, int namelen
)
96 FDT_CHECK_HEADER(fdt
);
99 (offset
>= 0) && (depth
>= 0);
100 offset
= fdt_next_node(fdt
, offset
, &depth
))
102 && _fdt_nodename_eq(fdt
, offset
, name
, namelen
))
106 return -FDT_ERR_NOTFOUND
;
107 return offset
; /* error */
110 int fdt_subnode_offset(const void *fdt
, int parentoffset
,
113 return fdt_subnode_offset_namelen(fdt
, parentoffset
, name
, strlen(name
));
116 int fdt_path_offset(const void *fdt
, const char *path
)
118 const char *end
= path
+ strlen(path
);
119 const char *p
= path
;
122 FDT_CHECK_HEADER(fdt
);
124 /* see if we have an alias */
126 const char *q
= strchr(path
, '/');
131 p
= fdt_get_alias_namelen(fdt
, p
, q
- p
);
133 return -FDT_ERR_BADPATH
;
134 offset
= fdt_path_offset(fdt
, p
);
150 offset
= fdt_subnode_offset_namelen(fdt
, offset
, p
, q
-p
);
160 const char *fdt_get_name(const void *fdt
, int nodeoffset
, int *len
)
162 const struct fdt_node_header
*nh
= _fdt_offset_ptr(fdt
, nodeoffset
);
165 if (((err
= fdt_check_header(fdt
)) != 0)
166 || ((err
= _fdt_check_node_offset(fdt
, nodeoffset
)) < 0))
170 *len
= strlen(nh
->name
);
180 int fdt_first_property_offset(const void *fdt
, int nodeoffset
)
184 if ((offset
= _fdt_check_node_offset(fdt
, nodeoffset
)) < 0)
187 return _nextprop(fdt
, offset
);
190 int fdt_next_property_offset(const void *fdt
, int offset
)
192 if ((offset
= _fdt_check_prop_offset(fdt
, offset
)) < 0)
195 return _nextprop(fdt
, offset
);
198 const struct fdt_property
*fdt_get_property_by_offset(const void *fdt
,
203 const struct fdt_property
*prop
;
205 if ((err
= _fdt_check_prop_offset(fdt
, offset
)) < 0) {
211 prop
= _fdt_offset_ptr(fdt
, offset
);
214 *lenp
= fdt32_to_cpu(prop
->len
);
219 const struct fdt_property
*fdt_get_property_namelen(const void *fdt
,
222 int namelen
, int *lenp
)
224 for (offset
= fdt_first_property_offset(fdt
, offset
);
226 (offset
= fdt_next_property_offset(fdt
, offset
))) {
227 const struct fdt_property
*prop
;
229 if (!(prop
= fdt_get_property_by_offset(fdt
, offset
, lenp
))) {
230 offset
= -FDT_ERR_INTERNAL
;
233 if (_fdt_string_eq(fdt
, fdt32_to_cpu(prop
->nameoff
),
243 const struct fdt_property
*fdt_get_property(const void *fdt
,
245 const char *name
, int *lenp
)
247 return fdt_get_property_namelen(fdt
, nodeoffset
, name
,
251 const void *fdt_getprop_namelen(const void *fdt
, int nodeoffset
,
252 const char *name
, int namelen
, int *lenp
)
254 const struct fdt_property
*prop
;
256 prop
= fdt_get_property_namelen(fdt
, nodeoffset
, name
, namelen
, lenp
);
263 const void *fdt_getprop_by_offset(const void *fdt
, int offset
,
264 const char **namep
, int *lenp
)
266 const struct fdt_property
*prop
;
268 prop
= fdt_get_property_by_offset(fdt
, offset
, lenp
);
272 *namep
= fdt_string(fdt
, fdt32_to_cpu(prop
->nameoff
));
276 const void *fdt_getprop(const void *fdt
, int nodeoffset
,
277 const char *name
, int *lenp
)
279 return fdt_getprop_namelen(fdt
, nodeoffset
, name
, strlen(name
), lenp
);
282 uint32_t fdt_get_phandle(const void *fdt
, int nodeoffset
)
287 /* FIXME: This is a bit sub-optimal, since we potentially scan
288 * over all the properties twice. */
289 php
= fdt_getprop(fdt
, nodeoffset
, "phandle", &len
);
290 if (!php
|| (len
!= sizeof(*php
))) {
291 php
= fdt_getprop(fdt
, nodeoffset
, "linux,phandle", &len
);
292 if (!php
|| (len
!= sizeof(*php
)))
296 return fdt32_to_cpu(*php
);
299 const char *fdt_get_alias_namelen(const void *fdt
,
300 const char *name
, int namelen
)
304 aliasoffset
= fdt_path_offset(fdt
, "/aliases");
308 return fdt_getprop_namelen(fdt
, aliasoffset
, name
, namelen
, NULL
);
311 const char *fdt_get_alias(const void *fdt
, const char *name
)
313 return fdt_get_alias_namelen(fdt
, name
, strlen(name
));
316 int fdt_get_path(const void *fdt
, int nodeoffset
, char *buf
, int buflen
)
318 int pdepth
= 0, p
= 0;
319 int offset
, depth
, namelen
;
322 FDT_CHECK_HEADER(fdt
);
325 return -FDT_ERR_NOSPACE
;
327 for (offset
= 0, depth
= 0;
328 (offset
>= 0) && (offset
<= nodeoffset
);
329 offset
= fdt_next_node(fdt
, offset
, &depth
)) {
330 while (pdepth
> depth
) {
333 } while (buf
[p
-1] != '/');
337 if (pdepth
>= depth
) {
338 name
= fdt_get_name(fdt
, offset
, &namelen
);
341 if ((p
+ namelen
+ 1) <= buflen
) {
342 memcpy(buf
+ p
, name
, namelen
);
349 if (offset
== nodeoffset
) {
350 if (pdepth
< (depth
+ 1))
351 return -FDT_ERR_NOSPACE
;
353 if (p
> 1) /* special case so that root path is "/", not "" */
360 if ((offset
== -FDT_ERR_NOTFOUND
) || (offset
>= 0))
361 return -FDT_ERR_BADOFFSET
;
362 else if (offset
== -FDT_ERR_BADOFFSET
)
363 return -FDT_ERR_BADSTRUCTURE
;
365 return offset
; /* error from fdt_next_node() */
368 int fdt_supernode_atdepth_offset(const void *fdt
, int nodeoffset
,
369 int supernodedepth
, int *nodedepth
)
372 int supernodeoffset
= -FDT_ERR_INTERNAL
;
374 FDT_CHECK_HEADER(fdt
);
376 if (supernodedepth
< 0)
377 return -FDT_ERR_NOTFOUND
;
379 for (offset
= 0, depth
= 0;
380 (offset
>= 0) && (offset
<= nodeoffset
);
381 offset
= fdt_next_node(fdt
, offset
, &depth
)) {
382 if (depth
== supernodedepth
)
383 supernodeoffset
= offset
;
385 if (offset
== nodeoffset
) {
389 if (supernodedepth
> depth
)
390 return -FDT_ERR_NOTFOUND
;
392 return supernodeoffset
;
396 if ((offset
== -FDT_ERR_NOTFOUND
) || (offset
>= 0))
397 return -FDT_ERR_BADOFFSET
;
398 else if (offset
== -FDT_ERR_BADOFFSET
)
399 return -FDT_ERR_BADSTRUCTURE
;
401 return offset
; /* error from fdt_next_node() */
404 int fdt_node_depth(const void *fdt
, int nodeoffset
)
409 err
= fdt_supernode_atdepth_offset(fdt
, nodeoffset
, 0, &nodedepth
);
411 return (err
< 0) ? err
: -FDT_ERR_INTERNAL
;
415 int fdt_parent_offset(const void *fdt
, int nodeoffset
)
417 int nodedepth
= fdt_node_depth(fdt
, nodeoffset
);
421 return fdt_supernode_atdepth_offset(fdt
, nodeoffset
,
422 nodedepth
- 1, NULL
);
425 int fdt_node_offset_by_prop_value(const void *fdt
, int startoffset
,
426 const char *propname
,
427 const void *propval
, int proplen
)
433 FDT_CHECK_HEADER(fdt
);
435 /* FIXME: The algorithm here is pretty horrible: we scan each
436 * property of a node in fdt_getprop(), then if that didn't
437 * find what we want, we scan over them again making our way
438 * to the next node. Still it's the easiest to implement
439 * approach; performance can come later. */
440 for (offset
= fdt_next_node(fdt
, startoffset
, NULL
);
442 offset
= fdt_next_node(fdt
, offset
, NULL
)) {
443 val
= fdt_getprop(fdt
, offset
, propname
, &len
);
444 if (val
&& (len
== proplen
)
445 && (memcmp(val
, propval
, len
) == 0))
449 return offset
; /* error from fdt_next_node() */
452 int fdt_node_offset_by_phandle(const void *fdt
, uint32_t phandle
)
456 if ((phandle
== 0) || (phandle
== -1))
457 return -FDT_ERR_BADPHANDLE
;
459 FDT_CHECK_HEADER(fdt
);
461 /* FIXME: The algorithm here is pretty horrible: we
462 * potentially scan each property of a node in
463 * fdt_get_phandle(), then if that didn't find what
464 * we want, we scan over them again making our way to the next
465 * node. Still it's the easiest to implement approach;
466 * performance can come later. */
467 for (offset
= fdt_next_node(fdt
, -1, NULL
);
469 offset
= fdt_next_node(fdt
, offset
, NULL
)) {
470 if (fdt_get_phandle(fdt
, offset
) == phandle
)
474 return offset
; /* error from fdt_next_node() */
477 int fdt_stringlist_contains(const char *strlist
, int listlen
, const char *str
)
479 int len
= strlen(str
);
482 while (listlen
>= len
) {
483 if (memcmp(str
, strlist
, len
+1) == 0)
485 p
= memchr(strlist
, '\0', listlen
);
487 return 0; /* malformed strlist.. */
488 listlen
-= (p
-strlist
) + 1;
494 int fdt_count_strings(const void *fdt
, int node
, const char *property
)
496 int length
, i
, count
= 0;
499 list
= fdt_getprop(fdt
, node
, property
, &length
);
503 for (i
= 0; i
< length
; i
++) {
504 int len
= strlen(list
);
514 int fdt_node_check_compatible(const void *fdt
, int nodeoffset
,
515 const char *compatible
)
520 prop
= fdt_getprop(fdt
, nodeoffset
, "compatible", &len
);
523 if (fdt_stringlist_contains(prop
, len
, compatible
))
529 int fdt_node_offset_by_compatible(const void *fdt
, int startoffset
,
530 const char *compatible
)
534 FDT_CHECK_HEADER(fdt
);
536 /* FIXME: The algorithm here is pretty horrible: we scan each
537 * property of a node in fdt_node_check_compatible(), then if
538 * that didn't find what we want, we scan over them again
539 * making our way to the next node. Still it's the easiest to
540 * implement approach; performance can come later. */
541 for (offset
= fdt_next_node(fdt
, startoffset
, NULL
);
543 offset
= fdt_next_node(fdt
, offset
, NULL
)) {
544 err
= fdt_node_check_compatible(fdt
, offset
, compatible
);
545 if ((err
< 0) && (err
!= -FDT_ERR_NOTFOUND
))
551 return offset
; /* error from fdt_next_node() */