[DTC PATCH] libfdt: Add ft_get_next_node(), ft_get_next_prop(), and ft_getprop_offset().

Scott Wood scottwood at freescale.com
Tue Jan 15 03:30:04 EST 2008


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 <scottwood at freescale.com>
---
 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



More information about the Linuxppc-dev mailing list