ft_get_next_node() enumerates children of a given node.
ft_get_next_prop() enumerates propreties of a given node.

ft_getprop_offset() is like ft_getprop(), but takes a property offset rather
than a node offset and property name; it is primarily intended for use
with ft_get_next_prop().

Signed-off-by: Scott Wood <[EMAIL PROTECTED]>
---
 libfdt/fdt_ro.c       |  134 +++++++++++++++++++++++++++++++++++++++++++++++++
 libfdt/fdt_strerror.c |    1 +
 libfdt/libfdt.h       |  123 ++++++++++++++++++++++++++++++++++++++++++---
 3 files changed, 251 insertions(+), 7 deletions(-)

diff --git a/libfdt/fdt_ro.c b/libfdt/fdt_ro.c
index 12a37d5..27c943a 100644
--- a/libfdt/fdt_ro.c
+++ b/libfdt/fdt_ro.c
@@ -293,6 +293,51 @@ const void *fdt_getprop(const void *fdt, int nodeoffset,
        return prop->data;
 }
 
+const void *fdt_getprop_offset(const void *fdt, int propoffset,
+                               const char **name, int *lenp)
+{
+       uint32_t tag;
+       const struct fdt_property *prop;
+       int namestroff;
+       int err, len;
+
+       err = fdt_check_header(fdt);
+       if (err)
+               goto fail;
+
+       tag = fdt_next_tag(fdt,propoffset, NULL);
+       if (tag != FDT_PROP) {
+               err = -FDT_ERR_BADOFFSET;
+               goto fail;
+       }
+
+       err = -FDT_ERR_BADSTRUCTURE;
+       prop = fdt_offset_ptr(fdt, propoffset, sizeof(*prop));
+       if (!prop)
+               goto fail;
+
+       if (name) {
+               namestroff = fdt32_to_cpu(prop->nameoff);
+               *name = fdt_string(fdt, namestroff);
+       }
+
+       len = fdt32_to_cpu(prop->len);
+       if (lenp)
+               *lenp = len;
+
+       prop = fdt_offset_ptr(fdt, propoffset, sizeof(*prop) + len);
+       if (!prop)
+               goto fail;
+
+       return prop->data;
+
+fail:
+       if (lenp)
+               *lenp = err;
+
+       return NULL;
+}
+
 uint32_t fdt_get_phandle(const void *fdt, int nodeoffset)
 {
        const uint32_t *php;
@@ -581,3 +626,92 @@ int fdt_node_offset_by_compatible(const void *fdt, int 
startoffset,
 
        return -FDT_ERR_NOTFOUND;
 }
+
+int fdt_get_next_node(const void *fdt, int startoffset,
+                      int *depth, int recursive)
+{
+       uint32_t tag;
+       int offset, nextoffset;
+
+       CHECK_HEADER(fdt);
+
+       if (startoffset >= 0) {
+               tag = fdt_next_tag(fdt, startoffset, &nextoffset);
+               if (tag != FDT_BEGIN_NODE)
+                       return -FDT_ERR_BADOFFSET;
+       } else {
+               nextoffset = 0;
+       }
+
+       do {
+               offset = nextoffset;
+               tag = fdt_next_tag(fdt, offset, &nextoffset);
+
+               switch (tag) {
+               case FDT_BEGIN_NODE:
+                       if ((*depth)++ == 0 || recursive) {
+                               return offset;
+                       }
+
+                       break;
+
+               case FDT_END_NODE:
+                       if (--*depth < 0)
+                               return -FDT_ERR_NOTFOUND;
+
+                       break;
+
+               case FDT_PROP:
+               case FDT_END:
+               case FDT_NOP:
+                       break;
+
+               default:
+                       return -FDT_ERR_BADSTRUCTURE;
+               }
+       } while (tag != FDT_END);
+
+       if (depth != 0)
+               return -FDT_ERR_BADSTRUCTURE;
+
+       return -FDT_ERR_NOTFOUND;
+}
+
+int fdt_get_next_prop(const void *fdt, int startoffset)
+{
+       uint32_t tag;
+       int offset, nextoffset;
+
+       CHECK_HEADER(fdt);
+
+       if (startoffset >= 0) {
+               tag = fdt_next_tag(fdt, startoffset, &nextoffset);
+               if (tag != FDT_BEGIN_NODE && tag != FDT_PROP)
+                       return -FDT_ERR_BADOFFSET;
+       } else {
+               nextoffset = 0;
+       }
+
+       do {
+               offset = nextoffset;
+               tag = fdt_next_tag(fdt, offset, &nextoffset);
+
+               switch (tag) {
+               case FDT_BEGIN_NODE:
+               case FDT_END_NODE:
+                       return -FDT_ERR_NOTFOUND;
+
+               case FDT_PROP:
+                       return offset;
+
+               case FDT_END:
+               case FDT_NOP:
+                       break;
+
+               default:
+                       return -FDT_ERR_BADSTRUCTURE;
+               }
+       } while (tag != FDT_END);
+
+       return -FDT_ERR_BADSTRUCTURE;
+}
diff --git a/libfdt/fdt_strerror.c b/libfdt/fdt_strerror.c
index f9d32ef..4e87550 100644
--- a/libfdt/fdt_strerror.c
+++ b/libfdt/fdt_strerror.c
@@ -70,6 +70,7 @@ static struct errtabent errtable[] = {
        ERRTABENT(FDT_ERR_BADOFFSET),
        ERRTABENT(FDT_ERR_BADPATH),
        ERRTABENT(FDT_ERR_BADSTATE),
+       ERRTABENT(FDT_ERR_BADDEPTH),
 
        ERRTABENT(FDT_ERR_TRUNCATED),
        ERRTABENT(FDT_ERR_BADMAGIC),
diff --git a/libfdt/libfdt.h b/libfdt/libfdt.h
index d053689..6c5d4a9 100644
--- a/libfdt/libfdt.h
+++ b/libfdt/libfdt.h
@@ -85,25 +85,28 @@
        /* FDT_ERR_BADSTATE: Function was passed an incomplete device
         * tree created by the sequential-write functions, which is
         * not sufficiently complete for the requested operation. */
+#define FDT_ERR_BADDEPTH       8
+       /* FDT_ERR_BADDEPTH: Function was passed a negative
+        * (or otherwise invalid) depth. */
 
 /* Error codes: codes for bad device tree blobs */
-#define FDT_ERR_TRUNCATED      8
+#define FDT_ERR_TRUNCATED      9
        /* FDT_ERR_TRUNCATED: Structure block of the given device tree
         * ends without an FDT_END tag. */
-#define FDT_ERR_BADMAGIC       9
+#define FDT_ERR_BADMAGIC       10
        /* FDT_ERR_BADMAGIC: Given "device tree" appears not to be a
         * device tree at all - it is missing the flattened device
         * tree magic number. */
-#define FDT_ERR_BADVERSION     10
+#define FDT_ERR_BADVERSION     11
        /* FDT_ERR_BADVERSION: Given device tree has a version which
         * can't be handled by the requested operation.  For
         * read-write functions, this may mean that fdt_open_into() is
         * required to convert the tree to the expected version. */
-#define FDT_ERR_BADSTRUCTURE   11
+#define FDT_ERR_BADSTRUCTURE   12
        /* FDT_ERR_BADSTRUCTURE: Given device tree has a corrupt
         * structure block or other serious error (e.g. misnested
         * nodes, or subnodes preceding properties). */
-#define FDT_ERR_BADLAYOUT      12
+#define FDT_ERR_BADLAYOUT      13
        /* FDT_ERR_BADLAYOUT: For read-write functions, the given
         * device tree has it's sub-blocks in an order that the
         * function can't handle (memory reserve map, then structure,
@@ -111,12 +114,12 @@
         * into a form suitable for the read-write operations. */
 
 /* "Can't happen" error indicating a bug in libfdt */
-#define FDT_ERR_INTERNAL       13
+#define FDT_ERR_INTERNAL       14
        /* FDT_ERR_INTERNAL: libfdt has failed an internal assertion.
         * Should never be returned, if it is, it indicates a bug in
         * libfdt itself. */
 
-#define FDT_ERR_MAX            13
+#define FDT_ERR_MAX            14
 
 /**********************************************************************/
 /* Low-level functions (you probably don't need these)                */
@@ -409,6 +412,41 @@ static inline void *fdt_getprop_w(void *fdt, int 
nodeoffset,
 }
 
 /**
+ * fdt_getprop_offset - retrieve the value of a given property by offset
+ * @fdt: pointer to the device tree blob
+ * @propoffset: offset of the property to read
+ * @name: pointer to a character pointer (will be overwritten) or NULL
+ * @lenp: pointer to an integer variable (will be overwritten) or NULL
+ *
+ * fdt_getprop() retrieves a pointer to the value of the property
+ * named 'name' of the node at offset nodeoffset (this will be a
+ * pointer to within the device blob itself, not a copy of the value).
+ * If lenp is non-NULL, the length of the property value also
+ * returned, in the integer pointed to by lenp.
+ *
+ * returns:
+ *     pointer to the property's value
+ *             if lenp is non-NULL, *lenp contains the length of the property
+ *             value (>=0)
+ *     NULL, on error
+ *             if lenp is non-NULL, *lenp contains an error code (<0):
+ *             -FDT_ERR_NOTFOUND, node does not have named property
+ *             -FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE 
tag
+ *             -FDT_ERR_BADMAGIC,
+ *             -FDT_ERR_BADVERSION,
+ *             -FDT_ERR_BADSTATE,
+ *             -FDT_ERR_BADSTRUCTURE,
+ *             -FDT_ERR_TRUNCATED, standard meanings
+ */
+const void *fdt_getprop_offset(const void *fdt, int propoffset,
+                               const char **name, int *lenp);
+static inline void *fdt_getprop_offset_w(void *fdt, int propoffset,
+                                      const char **name, int *lenp)
+{
+       return (void *)fdt_getprop_offset(fdt, propoffset, name, lenp);
+}
+
+/**
  * fdt_get_phandle - retreive the phandle of a given node
  * @fdt: pointer to the device tree blob
  * @nodeoffset: structure block offset of the node
@@ -651,6 +689,77 @@ int fdt_node_check_compatible(const void *fdt, int 
nodeoffset,
 int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
                                  const char *compatible);
 
+/**
+ * fdt_get_next_node - enumerate children of a node
+ * @fdt: pointer to the device tree blob
+ * @startoffset: only find nodes after this offset
+ * @depth: depth of the node, should be zero upon first call
+ * @recursive: only find immediate children if zero
+ *
+ * fdt_get_next_node() returns the offset of the first node after
+ * startoffset, until depth returns to zero.
+ *
+ * To iterate through all children, the following idiom can be used:
+ *     depth = 0;
+ *     offset = parent node offset;
+ *     while (1) {
+ *             offset = fdt_get_next_node(fdt, offset, &depth, recursive);
+ *             if (offset < 0)
+ *             break;
+ *
+ *             // other code here
+ *     }
+ *
+ * To find all the children of the root node, set the initial
+ * offset to zero.  To find all nodes *including* the root
+ * node, set the initial offset and depth to -1.
+ *
+ * returns:
+ *     structure block offset of the located node (>= 0, >startoffset),
+ *              on success
+ *     -FDT_ERR_NOTFOUND, no more child nodes exist after startoffset
+ *     -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ *     -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE,
+ *     -FDT_ERR_BADSTRUCTURE,
+ *     -FDT_ERR_BADDEPTH, standard meanings
+ */
+int fdt_get_next_node(const void *fdt, int startoffset,
+                      int *depth, int recursive);
+
+/**
+ * fdt_get_next_prop - enumerate properties of a node
+ * @fdt: pointer to the device tree blob
+ * @startoffset: only find nodes after this offset
+ *
+ * fdt_get_next_prop() returns the offset of the first property after
+ * startoffset.
+ *
+ * To iterate through all properties, the following idiom can be used:
+ *     offset = node offset;
+ *     while (1) {
+ *             offset = fdt_get_next_prop(fdt, offset);
+ *             if (offset < 0)
+ *             break;
+ *
+ *             // other code here
+ *     }
+ *
+ * returns:
+ *     structure block offset of the located property (>= 0, >startoffset),
+ *              on success
+ *     -FDT_ERR_NOTFOUND, no more properties exist in the current node
+ *             after startoffset
+ *     -FDT_ERR_BADOFFSET, nodeoffset does not refer to a BEGIN_NODE tag
+ *             or a PROP tag
+ *     -FDT_ERR_BADMAGIC,
+ *     -FDT_ERR_BADVERSION,
+ *     -FDT_ERR_BADSTATE,
+ *     -FDT_ERR_BADSTRUCTURE, standard meanings
+ */
+int fdt_get_next_prop(const void *fdt, int startoffset);
+
 /**********************************************************************/
 /* Write-in-place functions                                           */
 /**********************************************************************/
-- 
1.5.3
_______________________________________________
Linuxppc-dev mailing list
Linuxppc-dev@ozlabs.org
https://ozlabs.org/mailman/listinfo/linuxppc-dev

Reply via email to