[U-Boot] [PATCH - resend due to bounce] libfdt: Add fdt functionality for more intuitive

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@sysgo.com CC: David Gibson david@gibson.dropbear.id.au CC: Gerald Van Baren gvb@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; \

Hi Peter,
On 05/07/2012 09:52 AM, Peter Feuerer wrote:
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@sysgo.com CC: David Gibson david@gibson.dropbear.id.au CC: Gerald Van Baren gvb@unssw.com
As David pointed out, this needs to go through the upstream libfdt (dtc) library so that we stay in sync.
http://git.jdl.com/gitweb/?p=dtc.git;a=summary
Thanks, gvb
participants (2)
-
Jerry Van Baren
-
Peter Feuerer