[U-Boot] Subject: [PATCH] libfdt: Add fdt functionality for more intuitive fdt handling

Peter Feuerer peter.feuerer at sysgo.com
Mon May 7 14:56:54 CEST 2012


libfdt: Add fdt functionality for more intuitive fdt handling

New functions:
fdt_read - retrieve the value of a property by full path
fdt_write - create or change a property with full path and create subnodes if needed
fdt_create_path - create subnode path with parents

Signed-off-by: Peter Feuerer <peter.feuerer at sysgo.com>
CC: David Gibson <david at gibson.dropbear.id.au>
CC: Gerald Van Baren <gvb at unssw.com>

---
 include/libfdt.h             |   93 ++++++++++++++++++++++++++++++++++++++++
 lib/libfdt/fdt_ro.c          |   30 +++++++++++++
 lib/libfdt/fdt_rw.c          |   97 ++++++++++++++++++++++++++++++++++++++++++
 lib/libfdt/libfdt_internal.h |    4 ++
 4 files changed, 224 insertions(+), 0 deletions(-)

diff --git a/include/libfdt.h b/include/libfdt.h
index de82ed5..822ab18 100644
--- a/include/libfdt.h
+++ b/include/libfdt.h
@@ -548,6 +548,37 @@ static inline void *fdt_getprop_w(void *fdt, int nodeoffset,
 }
 
 /**
+ * fdt_read - retrieve the value of a property by full path
+ * @fdt: pointer to the device tree blob
+ * @path: string containing the absolute path of the property
+ * @name: name of the property
+ * @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 is 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_BADPATH,
+ *		-FDT_ERR_BADMAGIC,
+ *		-FDT_ERR_BADVERSION,
+ *		-FDT_ERR_BADSTATE,
+ *		-FDT_ERR_BADSTRUCTURE,
+ *		-FDT_ERR_TRUNCATED, standard meanings
+ */
+const void *fdt_read(const void *fdt, const char *path,
+			const char *name, int *lenp);
+
+/**
  * fdt_get_phandle - retrieve the phandle of a given node
  * @fdt: pointer to the device tree blob
  * @nodeoffset: structure block offset of the node
@@ -1066,6 +1097,38 @@ int fdt_set_name(void *fdt, int nodeoffset, const char *name);
  */
 int fdt_setprop(void *fdt, int nodeoffset, const char *name,
 		const void *val, int len);
+/**
+ * fdt_write - create or change a property with full path and create
+ *             all subnodes to the property if needed
+ * @fdt: pointer to the device tree blob
+ * @path: string containing the absolute path of the property
+ * @name: name of the property to change
+ * @val: pointer to data to set the property value to
+ * @len: length of the property value
+ *
+ * fdt_write() sets the value of the named property in the given
+ * node to the given value and length, creating the property if it
+ * does not already exist. Additionally it creates all parent nodes if
+ * not yet existing.
+ *
+ * This function may insert or delete data from the blob, and will
+ * therefore change the offsets of some existing nodes.
+ *
+ * returns:
+ *	0, on success
+ *	-FDT_ERR_NOSPACE, there is insufficient free space in the blob to
+ *		contain the new property value
+ *	-FDT_ERR_BADOFFSET, nodeoffset did not point to FDT_BEGIN_NODE tag
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_TRUNCATED, standard meanings
+ */
+int fdt_write(void *fdt, const char *path, const char *name,
+		const void *val, int len);
 
 /**
  * fdt_setprop_cell - set a property to a single cell value
@@ -1204,6 +1267,36 @@ int fdt_add_subnode_namelen(void *fdt, int parentoffset,
 int fdt_add_subnode(void *fdt, int parentoffset, const char *name);
 
 /**
+ * fdt_create_path - create subnode path with parents
+ * @fdt: pointer to the device tree blob
+ * @path: absolute path of subnodes to create
+ *
+ * fdt_create_path() creates absolute subnode path with all needed
+ * parents, if they don't exist.
+ *
+ * This function will insert data into the blob, and will therefore
+ * change the offsets of some existing nodes.
+ *
+ * returns:
+ *	structure block offset of the created nodeequested subnode (>=0), on success
+ *	-FDT_ERR_NOTFOUND, if the requested subnode does not exist
+ *	-FDT_ERR_BADOFFSET, if parentoffset did not point to an FDT_BEGIN_NODE tag
+ *	-FDT_ERR_EXISTS, if the node at parentoffset already has a subnode of
+ *		the given name
+ *	-FDT_ERR_NOSPACE, if there is insufficient free space in the
+ *		blob to contain the new node
+ *	-FDT_ERR_NOSPACE,
+ *	-FDT_ERR_BADPATH,
+ *	-FDT_ERR_BADLAYOUT,
+ *	-FDT_ERR_BADMAGIC,
+ *	-FDT_ERR_BADVERSION,
+ *	-FDT_ERR_BADSTATE,
+ *	-FDT_ERR_BADSTRUCTURE,
+ *	-FDT_ERR_TRUNCATED, standard meanings.
+ */
+int fdt_create_path(struct fdt_header *fdt, const char *path);
+
+/**
  * fdt_del_node - delete a node (subtree)
  * @fdt: pointer to the device tree blob
  * @nodeoffset: offset of the node to nop
diff --git a/lib/libfdt/fdt_ro.c b/lib/libfdt/fdt_ro.c
index 1933010..9a08200 100644
--- a/lib/libfdt/fdt_ro.c
+++ b/lib/libfdt/fdt_ro.c
@@ -324,6 +324,36 @@ const void *fdt_getprop(const void *fdt, int nodeoffset,
 	return fdt_getprop_namelen(fdt, nodeoffset, name, strlen(name), lenp);
 }
 
+const void *fdt_read(const void *fdt, const char *path,
+			const char *name, int *lenp)
+{
+	int nodeoffset;
+	int len;
+	const void *nodep ;
+
+	if (fdt_check_header(fdt) != 0) {
+		if (lenp)
+			*lenp = -FDT_ERR_BADSTRUCTURE;
+		return NULL;
+	}
+
+	nodeoffset = fdt_path_offset(fdt, path);
+
+	if (nodeoffset < 0) {
+		if (lenp)
+			*lenp = -FDT_ERR_BADPATH;
+		return NULL;
+	} else {
+		nodep = fdt_getprop(fdt, nodeoffset, name, &len);
+		if (len <= 0)
+			return NULL;
+		if (lenp)
+			*lenp = len;
+	}
+	return nodep;
+}
+
+
 uint32_t fdt_get_phandle(const void *fdt, int nodeoffset)
 {
 	const uint32_t *php;
diff --git a/lib/libfdt/fdt_rw.c b/lib/libfdt/fdt_rw.c
index 5c27a67..ccebafb 100644
--- a/lib/libfdt/fdt_rw.c
+++ b/lib/libfdt/fdt_rw.c
@@ -293,6 +293,21 @@ int fdt_setprop(void *fdt, int nodeoffset, const char *name,
 	return 0;
 }
 
+int fdt_write(void *fdt, const char *path, const char *name,
+		const void *val, int len)
+{
+	int nodeoffset;
+
+	FDT_CHECK_HEADER(fdt);
+
+	nodeoffset = fdt_create_path(fdt, path);
+
+	if (nodeoffset < 0)
+		return nodeoffset;
+
+	return fdt_setprop(fdt, nodeoffset, name, val, len);
+}
+
 int fdt_delprop(void *fdt, int nodeoffset, const char *name)
 {
 	struct fdt_property *prop;
@@ -354,6 +369,88 @@ int fdt_add_subnode(void *fdt, int parentoffset, const char *name)
 	return fdt_add_subnode_namelen(fdt, parentoffset, name, strlen(name));
 }
 
+int fdt_create_path_internal(struct fdt_header *fdt, char *path)
+{
+	int offset = 0;
+	char *p = NULL;
+	char *last_slash = NULL;
+	char *path2 = path;
+	int ret = 0;
+
+	/* search for last slash */
+	for (p = path; *p != 0; ++p)
+		if (*p == '/')
+			last_slash = p;
+
+	/* if path ends with "/" then, error */
+	if (*(last_slash + 1) == 0)
+		return -FDT_ERR_BADPATH;
+
+	/*
+	 * if last_slash is root, use "/" instead of string
+	 * otherwise terminate string at slash
+	 */
+	if (last_slash == path)
+		path2 = "/";
+	else
+		*last_slash = 0;
+
+	/*
+	 * test if the parent path is valid, if not valid,
+	 * recursively add paths
+	 */
+	offset = fdt_path_offset(fdt, path2);
+	if (offset == -FDT_ERR_NOTFOUND)
+		offset = fdt_create_path_internal(fdt, path2);
+
+	if (offset < 0)
+		return offset;
+
+	/* path valid, create subnode */
+	ret = fdt_add_subnode(fdt, offset, last_slash + 1);
+
+	/* undo termination */
+	if (last_slash && last_slash != path)
+		*last_slash = '/';
+
+	return ret;
+}
+
+int fdt_create_path(struct fdt_header *fdt, const char *path)
+{
+	int offset = 0;
+	int ret = 0;
+	int size = 0;
+#ifndef FDT_USE_MALLOC
+	char path_mem[FDT_MAX_PATHLEN] = {0};
+	size = FDT_MAX_PATHLEN;
+#else
+	char *path_mem;
+	size = strlen(path);
+	path_mem = calloc(size, 1);
+	if (!path_mem)
+		return -FDT_ERR_NOSPACE;
+#endif
+
+	/* if full path already exists, return the offset */
+	offset = fdt_path_offset(fdt, path);
+	if (offset >= 0) {
+		ret = offset;
+		goto end;
+	}
+
+	/* copy path to local path variable, so that we can modify it */
+	strncpy(path_mem, path, size - 1);
+
+	ret = fdt_create_path_internal(fdt, path_mem);
+end:
+#ifdef FDT_USE_MALLOC
+	free(path_mem);
+#endif
+	return ret;
+
+}
+
 int fdt_del_node(void *fdt, int nodeoffset)
 {
 	int endoffset;
diff --git a/lib/libfdt/libfdt_internal.h b/lib/libfdt/libfdt_internal.h
index 381133b..786a052 100644
--- a/lib/libfdt/libfdt_internal.h
+++ b/lib/libfdt/libfdt_internal.h
@@ -55,6 +55,10 @@
 #define FDT_ALIGN(x, a)		(((x) + (a) - 1) & ~((a) - 1))
 #define FDT_TAGALIGN(x)		(FDT_ALIGN((x), FDT_TAGSIZE))
 
+#ifndef FDT_USE_MALLOC
+#define FDT_MAX_PATHLEN		2048
+#endif
+
 #define FDT_CHECK_HEADER(fdt) \
 	{ \
 		int err; \
-- 
1.7.3



More information about the U-Boot mailing list