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.feue...@sysgo.com>
CC: David Gibson <da...@gibson.dropbear.id.au>
CC: Gerald Van Baren <g...@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

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
http://lists.denx.de/mailman/listinfo/u-boot

Reply via email to