diff options
author | nwhitehorn <nwhitehorn@FreeBSD.org> | 2013-11-06 14:33:37 +0000 |
---|---|---|
committer | nwhitehorn <nwhitehorn@FreeBSD.org> | 2013-11-06 14:33:37 +0000 |
commit | 81230530ea7a98c2e418797999890ab547a8813e (patch) | |
tree | 0e2ae0b1a6cec0819396bcf16bd09076c66fb452 | |
parent | 01e00131567543f1598b602f7b09cfdff30b9972 (diff) | |
download | FreeBSD-src-81230530ea7a98c2e418797999890ab547a8813e.zip FreeBSD-src-81230530ea7a98c2e418797999890ab547a8813e.tar.gz |
Make OF_nextprop() work correctly for FDT by using the libfdt
fdt_next_property_offset() API. The old code would sometimes (e.g. on
the device tree supplied by the RB800 boot loader) get confused and stop
partway through listing properties.
MFC after: 1 week
-rw-r--r-- | sys/dev/ofw/ofw_fdt.c | 93 |
1 files changed, 26 insertions, 67 deletions
diff --git a/sys/dev/ofw/ofw_fdt.c b/sys/dev/ofw/ofw_fdt.c index a4aca3c..8c739a0 100644 --- a/sys/dev/ofw/ofw_fdt.c +++ b/sys/dev/ofw/ofw_fdt.c @@ -137,26 +137,6 @@ fdt_phandle_offset(phandle_t p) return (pint - dtoff); } -static int -fdt_pointer_offset(const void *ptr) -{ - uintptr_t dt_struct, p; - int offset; - - p = (uintptr_t)ptr; - dt_struct = (uintptr_t)fdtp + fdt_off_dt_struct(fdtp); - - if ((p < dt_struct) || - p > (dt_struct + fdt_size_dt_struct(fdtp))) - return (-1); - - offset = p - dt_struct; - if (offset < 0) - return (-1); - - return (offset); -} - /* Return the next sibling of this node or 0. */ static phandle_t ofw_fdt_peer(ofw_t ofw, phandle_t node) @@ -285,41 +265,6 @@ ofw_fdt_getprop(ofw_t ofw, phandle_t package, const char *propname, void *buf, return (len); } -static int -fdt_nextprop(int offset, char *buf, size_t size) -{ - const struct fdt_property *prop; - const char *name; - uint32_t tag; - int nextoffset, depth; - - depth = 0; - tag = fdt_next_tag(fdtp, offset, &nextoffset); - - /* Find the next prop */ - do { - offset = nextoffset; - tag = fdt_next_tag(fdtp, offset, &nextoffset); - - if (tag == FDT_BEGIN_NODE) - depth++; - else if (tag == FDT_END_NODE) - depth--; - else if ((tag == FDT_PROP) && (depth == 0)) { - prop = - (const struct fdt_property *)fdt_offset_ptr(fdtp, - offset, sizeof(*prop)); - name = fdt_string(fdtp, - fdt32_to_cpu(prop->nameoff)); - strncpy(buf, name, size); - return (strlen(name)); - } else - depth = -1; - } while (depth >= 0); - - return (0); -} - /* * Get the next property of a package. Return the actual len of retrieved * prop name. @@ -329,26 +274,40 @@ ofw_fdt_nextprop(ofw_t ofw, phandle_t package, const char *previous, char *buf, size_t size) { const struct fdt_property *prop; - int offset, rv; + const char *name; + int offset; offset = fdt_phandle_offset(package); if (offset < 0) return (-1); - if (previous == NULL) - /* Find the first prop in the node */ - return (fdt_nextprop(offset, buf, size)); + /* Find the first prop in the node */ + offset = fdt_first_property_offset(fdtp, offset); - /* - * Advance to the previous prop - */ - prop = fdt_get_property(fdtp, offset, previous, NULL); + if (previous != NULL) { + while (offset >= 0) { + prop = fdt_get_property_by_offset(fdtp, offset, NULL); + if (prop == NULL) + return (-1); /* Internal error */ + + offset = fdt_next_property_offset(fdtp, offset); + if (offset < 0) + return (0); /* No more properties */ + + /* Check if the last one was the one we wanted */ + name = fdt_string(fdtp, fdt32_to_cpu(prop->nameoff)); + if (strcmp(name, previous) == 0) + break; + } + } + + prop = fdt_get_property_by_offset(fdtp, offset, &offset); if (prop == NULL) - return (-1); + return (-1); /* Internal error */ - offset = fdt_pointer_offset(prop); - rv = fdt_nextprop(offset, buf, size); - return (rv); + strncpy(buf, fdt_string(fdtp, fdt32_to_cpu(prop->nameoff)), size); + + return (strlen(buf)); } /* Set the value of a property of a package. */ |