^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * libfdt - Flat Device Tree manipulation
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright (C) 2006 David Gibson, IBM Corporation.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include "libfdt_env.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <fdt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <libfdt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include "libfdt_internal.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) static int fdt_nodename_eq_(const void *fdt, int offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) const char *s, int len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) int olen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) const char *p = fdt_get_name(fdt, offset, &olen);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) if (!p || olen < len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) /* short match */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) if (memcmp(p, s, len) != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) if (p[len] == '\0')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) else if (!memchr(s, '@', len) && (p[len] == '@'))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) const char *fdt_get_string(const void *fdt, int stroffset, int *lenp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) int32_t totalsize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) uint32_t absoffset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) size_t len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) const char *s, *n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) if (can_assume(VALID_INPUT)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) s = (const char *)fdt + fdt_off_dt_strings(fdt) + stroffset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) if (lenp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) *lenp = strlen(s);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) return s;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) totalsize = fdt_ro_probe_(fdt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) err = totalsize;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) if (totalsize < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) err = -FDT_ERR_BADOFFSET;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) absoffset = stroffset + fdt_off_dt_strings(fdt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) if (absoffset >= (unsigned)totalsize)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) len = totalsize - absoffset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) if (fdt_magic(fdt) == FDT_MAGIC) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) if (stroffset < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) if (can_assume(LATEST) || fdt_version(fdt) >= 17) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) if ((unsigned)stroffset >= fdt_size_dt_strings(fdt))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) if ((fdt_size_dt_strings(fdt) - stroffset) < len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) len = fdt_size_dt_strings(fdt) - stroffset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) } else if (fdt_magic(fdt) == FDT_SW_MAGIC) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) unsigned int sw_stroffset = -stroffset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) if ((stroffset >= 0) ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) (sw_stroffset > fdt_size_dt_strings(fdt)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) if (sw_stroffset < len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) len = sw_stroffset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) err = -FDT_ERR_INTERNAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) s = (const char *)fdt + absoffset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) n = memchr(s, '\0', len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) if (!n) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) /* missing terminating NULL */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) err = -FDT_ERR_TRUNCATED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) if (lenp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) *lenp = n - s;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) return s;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) fail:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) if (lenp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) *lenp = err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) const char *fdt_string(const void *fdt, int stroffset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) return fdt_get_string(fdt, stroffset, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) static int fdt_string_eq_(const void *fdt, int stroffset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) const char *s, int len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) int slen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) const char *p = fdt_get_string(fdt, stroffset, &slen);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) return p && (slen == len) && (memcmp(p, s, len) == 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) int fdt_find_max_phandle(const void *fdt, uint32_t *phandle)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) uint32_t max = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) int offset = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) while (true) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) uint32_t value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) offset = fdt_next_node(fdt, offset, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) if (offset < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) if (offset == -FDT_ERR_NOTFOUND)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) return offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) value = fdt_get_phandle(fdt, offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) if (value > max)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) max = value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) if (phandle)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) *phandle = max;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) int fdt_generate_phandle(const void *fdt, uint32_t *phandle)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) uint32_t max;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) err = fdt_find_max_phandle(fdt, &max);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) if (err < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) if (max == FDT_MAX_PHANDLE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) return -FDT_ERR_NOPHANDLES;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) if (phandle)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) *phandle = max + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) static const struct fdt_reserve_entry *fdt_mem_rsv(const void *fdt, int n)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) unsigned int offset = n * sizeof(struct fdt_reserve_entry);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) unsigned int absoffset = fdt_off_mem_rsvmap(fdt) + offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) if (!can_assume(VALID_INPUT)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) if (absoffset < fdt_off_mem_rsvmap(fdt))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) if (absoffset > fdt_totalsize(fdt) -
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) sizeof(struct fdt_reserve_entry))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) return fdt_mem_rsv_(fdt, n);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) int fdt_get_mem_rsv(const void *fdt, int n, uint64_t *address, uint64_t *size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) const struct fdt_reserve_entry *re;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) FDT_RO_PROBE(fdt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) re = fdt_mem_rsv(fdt, n);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) if (!can_assume(VALID_INPUT) && !re)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) return -FDT_ERR_BADOFFSET;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) *address = fdt64_ld_(&re->address);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) *size = fdt64_ld_(&re->size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) int fdt_num_mem_rsv(const void *fdt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) const struct fdt_reserve_entry *re;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) for (i = 0; (re = fdt_mem_rsv(fdt, i)) != NULL; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) if (fdt64_ld_(&re->size) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) return i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) return -FDT_ERR_TRUNCATED;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) static int nextprop_(const void *fdt, int offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) uint32_t tag;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) int nextoffset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) tag = fdt_next_tag(fdt, offset, &nextoffset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) switch (tag) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) case FDT_END:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) if (nextoffset >= 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) return -FDT_ERR_BADSTRUCTURE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) return nextoffset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) case FDT_PROP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) return offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) offset = nextoffset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) } while (tag == FDT_NOP);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) return -FDT_ERR_NOTFOUND;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) int fdt_subnode_offset_namelen(const void *fdt, int offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) const char *name, int namelen)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) int depth;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) FDT_RO_PROBE(fdt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) for (depth = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) (offset >= 0) && (depth >= 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) offset = fdt_next_node(fdt, offset, &depth))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) if ((depth == 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) && fdt_nodename_eq_(fdt, offset, name, namelen))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) return offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) if (depth < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) return -FDT_ERR_NOTFOUND;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) return offset; /* error */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) int fdt_subnode_offset(const void *fdt, int parentoffset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) const char *name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) return fdt_subnode_offset_namelen(fdt, parentoffset, name, strlen(name));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) int fdt_path_offset_namelen(const void *fdt, const char *path, int namelen)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) const char *end = path + namelen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) const char *p = path;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) int offset = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) FDT_RO_PROBE(fdt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) /* see if we have an alias */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) if (*path != '/') {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) const char *q = memchr(path, '/', end - p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) if (!q)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) q = end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) p = fdt_get_alias_namelen(fdt, p, q - p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) if (!p)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) return -FDT_ERR_BADPATH;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) offset = fdt_path_offset(fdt, p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) p = q;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) while (p < end) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) const char *q;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) while (*p == '/') {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) p++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) if (p == end)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) return offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) q = memchr(p, '/', end - p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) if (! q)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) q = end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) offset = fdt_subnode_offset_namelen(fdt, offset, p, q-p);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) if (offset < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) return offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) p = q;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) return offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) int fdt_path_offset(const void *fdt, const char *path)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) return fdt_path_offset_namelen(fdt, path, strlen(path));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) const char *fdt_get_name(const void *fdt, int nodeoffset, int *len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) const struct fdt_node_header *nh = fdt_offset_ptr_(fdt, nodeoffset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) const char *nameptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) if (((err = fdt_ro_probe_(fdt)) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) || ((err = fdt_check_node_offset_(fdt, nodeoffset)) < 0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) nameptr = nh->name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) if (!can_assume(LATEST) && fdt_version(fdt) < 0x10) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) * For old FDT versions, match the naming conventions of V16:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) * give only the leaf name (after all /). The actual tree
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) * contents are loosely checked.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) const char *leaf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) leaf = strrchr(nameptr, '/');
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) if (leaf == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) err = -FDT_ERR_BADSTRUCTURE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) goto fail;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) nameptr = leaf+1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) if (len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) *len = strlen(nameptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) return nameptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) fail:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) if (len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) *len = err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) int fdt_first_property_offset(const void *fdt, int nodeoffset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) int offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) if ((offset = fdt_check_node_offset_(fdt, nodeoffset)) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) return offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) return nextprop_(fdt, offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) int fdt_next_property_offset(const void *fdt, int offset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) if ((offset = fdt_check_prop_offset_(fdt, offset)) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) return offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) return nextprop_(fdt, offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) static const struct fdt_property *fdt_get_property_by_offset_(const void *fdt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) int offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) int *lenp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) const struct fdt_property *prop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) if (!can_assume(VALID_INPUT) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) (err = fdt_check_prop_offset_(fdt, offset)) < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) if (lenp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) *lenp = err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) prop = fdt_offset_ptr_(fdt, offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) if (lenp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) *lenp = fdt32_ld_(&prop->len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) return prop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) const struct fdt_property *fdt_get_property_by_offset(const void *fdt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) int offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) int *lenp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) /* Prior to version 16, properties may need realignment
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) * and this API does not work. fdt_getprop_*() will, however. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) if (!can_assume(LATEST) && fdt_version(fdt) < 0x10) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) if (lenp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) *lenp = -FDT_ERR_BADVERSION;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) return fdt_get_property_by_offset_(fdt, offset, lenp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) static const struct fdt_property *fdt_get_property_namelen_(const void *fdt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) int offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) const char *name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) int namelen,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) int *lenp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) int *poffset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) for (offset = fdt_first_property_offset(fdt, offset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) (offset >= 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) (offset = fdt_next_property_offset(fdt, offset))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) const struct fdt_property *prop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406) prop = fdt_get_property_by_offset_(fdt, offset, lenp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) if (!can_assume(LIBFDT_FLAWLESS) && !prop) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) offset = -FDT_ERR_INTERNAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411) if (fdt_string_eq_(fdt, fdt32_ld_(&prop->nameoff),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) name, namelen)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) if (poffset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) *poffset = offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) return prop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) if (lenp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) *lenp = offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) const struct fdt_property *fdt_get_property_namelen(const void *fdt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) int offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) const char *name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) int namelen, int *lenp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) /* Prior to version 16, properties may need realignment
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431) * and this API does not work. fdt_getprop_*() will, however. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) if (!can_assume(LATEST) && fdt_version(fdt) < 0x10) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) if (lenp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) *lenp = -FDT_ERR_BADVERSION;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) return fdt_get_property_namelen_(fdt, offset, name, namelen, lenp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443) const struct fdt_property *fdt_get_property(const void *fdt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) int nodeoffset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) const char *name, int *lenp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) return fdt_get_property_namelen(fdt, nodeoffset, name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) strlen(name), lenp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) const void *fdt_getprop_namelen(const void *fdt, int nodeoffset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452) const char *name, int namelen, int *lenp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) int poffset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) const struct fdt_property *prop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) prop = fdt_get_property_namelen_(fdt, nodeoffset, name, namelen, lenp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) &poffset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) if (!prop)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) /* Handle realignment */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) if (!can_assume(LATEST) && fdt_version(fdt) < 0x10 &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) (poffset + sizeof(*prop)) % 8 && fdt32_ld_(&prop->len) >= 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) return prop->data + 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) return prop->data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) const void *fdt_getprop_by_offset(const void *fdt, int offset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) const char **namep, int *lenp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) const struct fdt_property *prop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) prop = fdt_get_property_by_offset_(fdt, offset, lenp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) if (!prop)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) if (namep) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) const char *name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) int namelen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) if (!can_assume(VALID_INPUT)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) name = fdt_get_string(fdt, fdt32_ld_(&prop->nameoff),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483) &namelen);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) if (!name) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) if (lenp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) *lenp = namelen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) *namep = name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) *namep = fdt_string(fdt, fdt32_ld_(&prop->nameoff));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) /* Handle realignment */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496) if (!can_assume(LATEST) && fdt_version(fdt) < 0x10 &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) (offset + sizeof(*prop)) % 8 && fdt32_ld_(&prop->len) >= 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) return prop->data + 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) return prop->data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) const void *fdt_getprop(const void *fdt, int nodeoffset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503) const char *name, int *lenp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) return fdt_getprop_namelen(fdt, nodeoffset, name, strlen(name), lenp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) uint32_t fdt_get_phandle(const void *fdt, int nodeoffset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) const fdt32_t *php;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) int len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513) /* FIXME: This is a bit sub-optimal, since we potentially scan
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) * over all the properties twice. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) php = fdt_getprop(fdt, nodeoffset, "phandle", &len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516) if (!php || (len != sizeof(*php))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) php = fdt_getprop(fdt, nodeoffset, "linux,phandle", &len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) if (!php || (len != sizeof(*php)))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522) return fdt32_ld_(php);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) const char *fdt_get_alias_namelen(const void *fdt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) const char *name, int namelen)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) int aliasoffset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530) aliasoffset = fdt_path_offset(fdt, "/aliases");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) if (aliasoffset < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) return fdt_getprop_namelen(fdt, aliasoffset, name, namelen, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) const char *fdt_get_alias(const void *fdt, const char *name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) return fdt_get_alias_namelen(fdt, name, strlen(name));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) int fdt_get_path(const void *fdt, int nodeoffset, char *buf, int buflen)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) int pdepth = 0, p = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) int offset, depth, namelen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) const char *name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548) FDT_RO_PROBE(fdt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) if (buflen < 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) return -FDT_ERR_NOSPACE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) for (offset = 0, depth = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) (offset >= 0) && (offset <= nodeoffset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) offset = fdt_next_node(fdt, offset, &depth)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) while (pdepth > depth) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) p--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) } while (buf[p-1] != '/');
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560) pdepth--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) if (pdepth >= depth) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) name = fdt_get_name(fdt, offset, &namelen);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) if (!name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) return namelen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567) if ((p + namelen + 1) <= buflen) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) memcpy(buf + p, name, namelen);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) p += namelen;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570) buf[p++] = '/';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) pdepth++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575) if (offset == nodeoffset) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) if (pdepth < (depth + 1))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) return -FDT_ERR_NOSPACE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) if (p > 1) /* special case so that root path is "/", not "" */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) p--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581) buf[p] = '\0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586) if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) return -FDT_ERR_BADOFFSET;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) else if (offset == -FDT_ERR_BADOFFSET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) return -FDT_ERR_BADSTRUCTURE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) return offset; /* error from fdt_next_node() */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) int fdt_supernode_atdepth_offset(const void *fdt, int nodeoffset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595) int supernodedepth, int *nodedepth)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) int offset, depth;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) int supernodeoffset = -FDT_ERR_INTERNAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) FDT_RO_PROBE(fdt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602) if (supernodedepth < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) return -FDT_ERR_NOTFOUND;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) for (offset = 0, depth = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606) (offset >= 0) && (offset <= nodeoffset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) offset = fdt_next_node(fdt, offset, &depth)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608) if (depth == supernodedepth)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) supernodeoffset = offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) if (offset == nodeoffset) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) if (nodedepth)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613) *nodedepth = depth;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) if (supernodedepth > depth)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616) return -FDT_ERR_NOTFOUND;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) return supernodeoffset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622) if (!can_assume(VALID_INPUT)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) if ((offset == -FDT_ERR_NOTFOUND) || (offset >= 0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) return -FDT_ERR_BADOFFSET;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) else if (offset == -FDT_ERR_BADOFFSET)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) return -FDT_ERR_BADSTRUCTURE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) return offset; /* error from fdt_next_node() */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) int fdt_node_depth(const void *fdt, int nodeoffset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) int nodedepth;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) err = fdt_supernode_atdepth_offset(fdt, nodeoffset, 0, &nodedepth);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) return (can_assume(LIBFDT_FLAWLESS) || err < 0) ? err :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640) -FDT_ERR_INTERNAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) return nodedepth;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) int fdt_parent_offset(const void *fdt, int nodeoffset)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646) int nodedepth = fdt_node_depth(fdt, nodeoffset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) if (nodedepth < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649) return nodedepth;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) return fdt_supernode_atdepth_offset(fdt, nodeoffset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) nodedepth - 1, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) int fdt_node_offset_by_prop_value(const void *fdt, int startoffset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655) const char *propname,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) const void *propval, int proplen)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) int offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) const void *val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) int len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662) FDT_RO_PROBE(fdt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) /* FIXME: The algorithm here is pretty horrible: we scan each
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) * property of a node in fdt_getprop(), then if that didn't
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) * find what we want, we scan over them again making our way
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) * to the next node. Still it's the easiest to implement
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668) * approach; performance can come later. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) for (offset = fdt_next_node(fdt, startoffset, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) offset >= 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) offset = fdt_next_node(fdt, offset, NULL)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) val = fdt_getprop(fdt, offset, propname, &len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673) if (val && (len == proplen)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) && (memcmp(val, propval, len) == 0))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675) return offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) return offset; /* error from fdt_next_node() */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) int fdt_node_offset_by_phandle(const void *fdt, uint32_t phandle)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) int offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) if ((phandle == 0) || (phandle == ~0U))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) return -FDT_ERR_BADPHANDLE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) FDT_RO_PROBE(fdt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) /* FIXME: The algorithm here is pretty horrible: we
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) * potentially scan each property of a node in
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692) * fdt_get_phandle(), then if that didn't find what
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) * we want, we scan over them again making our way to the next
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) * node. Still it's the easiest to implement approach;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) * performance can come later. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) for (offset = fdt_next_node(fdt, -1, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) offset >= 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) offset = fdt_next_node(fdt, offset, NULL)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699) if (fdt_get_phandle(fdt, offset) == phandle)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) return offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) return offset; /* error from fdt_next_node() */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) int fdt_stringlist_contains(const char *strlist, int listlen, const char *str)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708) int len = strlen(str);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) const char *p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) while (listlen >= len) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) if (memcmp(str, strlist, len+1) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) p = memchr(strlist, '\0', listlen);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) if (!p)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) return 0; /* malformed strlist.. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) listlen -= (p-strlist) + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) strlist = p + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) int fdt_stringlist_count(const void *fdt, int nodeoffset, const char *property)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) const char *list, *end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) int length, count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) list = fdt_getprop(fdt, nodeoffset, property, &length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) if (!list)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730) return length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732) end = list + length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) while (list < end) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) length = strnlen(list, end - list) + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) /* Abort if the last string isn't properly NUL-terminated. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) if (list + length > end)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) return -FDT_ERR_BADVALUE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) list += length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) count++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) return count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) int fdt_stringlist_search(const void *fdt, int nodeoffset, const char *property,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) const char *string)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) int length, len, idx = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) const char *list, *end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) list = fdt_getprop(fdt, nodeoffset, property, &length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) if (!list)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756) return length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) len = strlen(string) + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) end = list + length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) while (list < end) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) length = strnlen(list, end - list) + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) /* Abort if the last string isn't properly NUL-terminated. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) if (list + length > end)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766) return -FDT_ERR_BADVALUE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) if (length == len && memcmp(list, string, length) == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) return idx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) list += length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) idx++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) return -FDT_ERR_NOTFOUND;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) const char *fdt_stringlist_get(const void *fdt, int nodeoffset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) const char *property, int idx,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780) int *lenp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) const char *list, *end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) int length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) list = fdt_getprop(fdt, nodeoffset, property, &length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) if (!list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787) if (lenp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) *lenp = length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793) end = list + length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) while (list < end) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796) length = strnlen(list, end - list) + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) /* Abort if the last string isn't properly NUL-terminated. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) if (list + length > end) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) if (lenp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) *lenp = -FDT_ERR_BADVALUE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) if (idx == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807) if (lenp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) *lenp = length - 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810) return list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813) list += length;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) idx--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) if (lenp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) *lenp = -FDT_ERR_NOTFOUND;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) int fdt_node_check_compatible(const void *fdt, int nodeoffset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) const char *compatible)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826) const void *prop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) int len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) prop = fdt_getprop(fdt, nodeoffset, "compatible", &len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) if (!prop)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) return len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) return !fdt_stringlist_contains(prop, len, compatible);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) const char *compatible)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) int offset, err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841) FDT_RO_PROBE(fdt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) /* FIXME: The algorithm here is pretty horrible: we scan each
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) * property of a node in fdt_node_check_compatible(), then if
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) * that didn't find what we want, we scan over them again
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) * making our way to the next node. Still it's the easiest to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847) * implement approach; performance can come later. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) for (offset = fdt_next_node(fdt, startoffset, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) offset >= 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850) offset = fdt_next_node(fdt, offset, NULL)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) err = fdt_node_check_compatible(fdt, offset, compatible);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) if ((err < 0) && (err != -FDT_ERR_NOTFOUND))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854) else if (err == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) return offset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) return offset; /* error from fdt_next_node() */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) }