From f30b191e36ddc086c3f58a572096d650fd5a6dfa Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 10 Jan 2013 14:37:17 +0100 Subject: [PATCH 01/19] of: make of_get_fixed_tree more universally usable Currently the bootm code uses of_fix_tree to apply the fixups to the devicetree given on the command line. This function assumes that there is enough space for the fixups available. Also on ARM we have to make sure the tree does not cross 1Mib boundaries. This patch moves the space allocation and alignment ensurance to of_get_fixed_tree and uses it in bootm. This is the first step for making of_get_fixed_tree the single point of devicetree handling in barebox. of_get_fixed_tree now takes an argument of the input fdt. If it is given, this one is used, otherwise an internal oftree is used which will be created in subsequent patches. Signed-off-by: Sascha Hauer --- arch/arm/lib/bootu.c | 2 +- arch/arm/lib/bootz.c | 2 +- commands/bootm.c | 32 +++++++--------------------- common/oftree.c | 50 +++++++++++++++++++++++++++++++++++++++----- include/of.h | 2 +- 5 files changed, 56 insertions(+), 32 deletions(-) diff --git a/arch/arm/lib/bootu.c b/arch/arm/lib/bootu.c index 75e0de323..fdb03621b 100644 --- a/arch/arm/lib/bootu.c +++ b/arch/arm/lib/bootu.c @@ -23,7 +23,7 @@ static int do_bootu(int argc, char *argv[]) kernel = (void *)simple_strtoul(argv[1], NULL, 0); #ifdef CONFIG_OFTREE - oftree = of_get_fixed_tree(); + oftree = of_get_fixed_tree(NULL); #endif start_linux(kernel, 0, 0, 0, oftree); diff --git a/arch/arm/lib/bootz.c b/arch/arm/lib/bootz.c index 9f5b3b442..e32a77ba4 100644 --- a/arch/arm/lib/bootz.c +++ b/arch/arm/lib/bootz.c @@ -109,7 +109,7 @@ static int do_bootz(int argc, char *argv[]) printf("loaded zImage from %s with size %d\n", argv[1], end); #ifdef CONFIG_OFTREE - oftree = of_get_fixed_tree(); + oftree = of_get_fixed_tree(NULL); #endif start_linux(zimage, swap, 0, 0, oftree); diff --git a/commands/bootm.c b/commands/bootm.c index 483e6a193..d8b846910 100644 --- a/commands/bootm.c +++ b/commands/bootm.c @@ -139,9 +139,7 @@ static int bootm_open_oftree(struct image_data *data, const char *oftree, int nu { enum filetype ft; struct fdt_header *fdt, *fixfdt; - int ret; size_t size; - unsigned int align; if (bootm_verbose(data)) printf("Loading oftree from '%s'\n", oftree); @@ -190,36 +188,18 @@ static int bootm_open_oftree(struct image_data *data, const char *oftree, int nu file_type_to_string(ft)); } - /* - * ARM Linux uses a single 1MiB section (with 1MiB alignment) - * for mapping the devicetree, so we are not allowed to cross - * 1MiB boundaries. - */ - align = 1 << fls(size + OFTREE_SIZE_INCREASE - 1); - - fixfdt = xmemalign(align, size + OFTREE_SIZE_INCREASE); - memcpy(fixfdt, fdt, size); - - - ret = fdt_open_into(fdt, fixfdt, size + OFTREE_SIZE_INCREASE); + fixfdt = of_get_fixed_tree(fdt); + if (!fixfdt) + return -EINVAL; free(fdt); - if (ret) { - printf("unable to parse %s\n", oftree); - return -ENODEV; - } - - ret = of_fix_tree(fixfdt); - if (ret) - return ret; - if (bootm_verbose(data) > 1) fdt_print(fixfdt, "/"); data->oftree = fixfdt; - return ret; + return 0; } #endif @@ -420,6 +400,10 @@ static int do_bootm(int argc, char *argv[]) ret = bootm_open_oftree(&data, oftree, oftree_num); if (ret) goto err_out; + } else { + data.oftree = of_get_fixed_tree(NULL); + if (bootm_verbose(&data) && data.oftree) + printf("using internal devicetree\n"); } #endif if (data.os_address == UIMAGE_SOME_ADDRESS) diff --git a/common/oftree.c b/common/oftree.c index 3e8c6f8c6..0dd6d5c3e 100644 --- a/common/oftree.c +++ b/common/oftree.c @@ -294,6 +294,10 @@ int of_register_fixup(int (*fixup)(struct fdt_header *)) return 0; } +/* + * Apply registered fixups for the given fdt. The fdt must have + * enough free space to apply the fixups. + */ int of_fix_tree(struct fdt_header *fdt) { struct of_fixup *of_fixup; @@ -308,14 +312,50 @@ int of_fix_tree(struct fdt_header *fdt) return 0; } -struct fdt_header *of_get_fixed_tree(void) +/* + * The size by which we increase the dtb to have space for additional + * fixups. Ideally this would be done by libfdt automatically + */ +#define OFTREE_SIZE_INCREASE 0x8000 + +/* + * Get the fixed fdt. This function uses the fdt input pointer + * if provided or the barebox internal devicetree if not. + * It increases the size of the tree and applies the registered + * fixups. + */ +struct fdt_header *of_get_fixed_tree(struct fdt_header *fdt) { int ret; + void *fixfdt; + int size, align; - if (!barebox_fdt) + if (!fdt) return NULL; - ret = of_fix_tree(barebox_fdt); + + size = fdt_totalsize(fdt); + + /* + * ARM Linux uses a single 1MiB section (with 1MiB alignment) + * for mapping the devicetree, so we are not allowed to cross + * 1MiB boundaries. + */ + align = 1 << fls(size + OFTREE_SIZE_INCREASE - 1); + + fixfdt = xmemalign(align, size + OFTREE_SIZE_INCREASE); + ret = fdt_open_into(fdt, fixfdt, size + OFTREE_SIZE_INCREASE); + if (ret) - return NULL; - return barebox_fdt; + goto out_free; + + ret = of_fix_tree(fixfdt); + if (ret) + goto out_free; + + return fixfdt; + +out_free: + free(fixfdt); + + return NULL; } diff --git a/include/of.h b/include/of.h index 58b459008..3999ded5c 100644 --- a/include/of.h +++ b/include/of.h @@ -9,7 +9,7 @@ extern struct fdt_header *barebox_fdt; int fdt_print(struct fdt_header *working_fdt, const char *pathp); -struct fdt_header *of_get_fixed_tree(void); +struct fdt_header *of_get_fixed_tree(struct fdt_header *fdt); int of_fix_tree(struct fdt_header *fdt); int of_register_fixup(int (*fixup)(struct fdt_header *)); From 99bb8de76f074aaeaa719a7ac76a7d3e1a859ae5 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 9 Jan 2013 13:42:55 +0100 Subject: [PATCH 02/19] of: Fix invalid path for of_find_node_by_path When of_find_node_by_path is called with a non existing path we return just some node. return NULL instead. Signed-off-by: Sascha Hauer --- drivers/of/base.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/of/base.c b/drivers/of/base.c index 7a41618ec..399adc847 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -487,9 +487,10 @@ struct device_node *of_find_node_by_path(const char *path) list_for_each_entry(np, &allnodes, list) { if (np->full_name && (strcmp(np->full_name, path) == 0)) - break; + return np; } - return np; + + return NULL; } EXPORT_SYMBOL(of_find_node_by_path); From da852397e074875d0b37a4ae0dd8334a0fc9f1ce Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 9 Jan 2013 13:56:20 +0100 Subject: [PATCH 03/19] ARM android image: remove double of_fix_tree With bootm of_fix_tree() will already be called from the generic bootm code, so do not do this again in the Android image handler. Signed-off-by: Sascha Hauer Cc: Jean-Christophe PLAGNIOL-VILLARD --- arch/arm/lib/bootm.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/arch/arm/lib/bootm.c b/arch/arm/lib/bootm.c index 51ac9af60..b7dc96ee3 100644 --- a/arch/arm/lib/bootm.c +++ b/arch/arm/lib/bootm.c @@ -402,12 +402,6 @@ static int do_bootm_aimage(struct image_data *data) if (!getenv("aimage_noverwrite_tags")) armlinux_set_bootparams((void*)header->tags_addr); - if (IS_ENABLED(CONFIG_OFTREE) && data->oftree) { - ret = of_fix_tree(data->oftree); - if (ret) - goto err_out; - } - cmp = &header->second_stage; if (cmp->size) { void (*second)(void); From 818dccf28b72e23e6d94ad0ee46e8ab3d4ae09d6 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 9 Jan 2013 14:55:30 +0100 Subject: [PATCH 04/19] of: of_free fixes - Add missing prototype for of_free() - When root node is freed set root_node to NULL - (re)scan aliases after freeing a node. This is necessary because the freed node may be an alias or point to an alias Signed-off-by: Sascha Hauer --- drivers/of/base.c | 11 +++++++++++ include/of.h | 1 + 2 files changed, 12 insertions(+) diff --git a/drivers/of/base.c b/drivers/of/base.c index 399adc847..6c1ccd742 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -138,6 +138,12 @@ static void of_alias_add(struct alias_prop *ap, struct device_node *np, void of_alias_scan(void) { struct property *pp; + struct alias_prop *app, *tmp; + + list_for_each_entry_safe(app, tmp, &aliases_lookup, link) + free(app); + + INIT_LIST_HEAD(&aliases_lookup); of_aliases = of_find_node_by_path("/aliases"); if (!of_aliases) @@ -777,6 +783,11 @@ void of_free(struct device_node *node) free(node->name); free(node->full_name); free(node); + + if (node == root_node) + root_node = NULL; + + of_alias_scan(); } static void __of_probe(struct device_node *node) diff --git a/include/of.h b/include/of.h index 3999ded5c..40549172c 100644 --- a/include/of.h +++ b/include/of.h @@ -107,6 +107,7 @@ int of_machine_is_compatible(const char *compat); void of_print_nodes(struct device_node *node, int indent); int of_probe(void); int of_parse_dtb(struct fdt_header *fdt); +void of_free(struct device_node *node); int of_property_read_string(struct device_node *np, const char *propname, const char **out_string); From 969120f125185c13fd43d9e8003daf4c90f93f6d Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 9 Jan 2013 15:04:54 +0100 Subject: [PATCH 05/19] of of_free: remove old node from allnodes list Signed-off-by: Sascha Hauer --- drivers/of/base.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/of/base.c b/drivers/of/base.c index 6c1ccd742..3e91e362a 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -761,6 +761,8 @@ void of_free(struct device_node *node) if (!node) return; + list_del(&node->list); + list_for_each_entry_safe(p, pt, &node->properties, list) { list_del(&p->list); free(p->name); From 05ed875f3519406571795229716363a6834b1b01 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 9 Jan 2013 23:21:32 +0100 Subject: [PATCH 06/19] of: return root node when looking for a node with path / Signed-off-by: Sascha Hauer --- drivers/of/base.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/of/base.c b/drivers/of/base.c index 3e91e362a..69fbf9a2d 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -491,6 +491,9 @@ struct device_node *of_find_node_by_path(const char *path) { struct device_node *np; + if (!strcmp(path, "/")) + return root_node; + list_for_each_entry(np, &allnodes, list) { if (np->full_name && (strcmp(np->full_name, path) == 0)) return np; From 86e787e84565e6c08696450e9d14d066f3f76056 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Tue, 8 Jan 2013 18:13:30 +0100 Subject: [PATCH 07/19] of: rename of_parse_dtb to of_unflatten_dtb The process of unflatten the device tree is known from the kernel, so rename the function, because that's what it does. Signed-off-by: Sascha Hauer --- commands/oftree.c | 2 +- drivers/of/base.c | 2 +- include/of.h | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/commands/oftree.c b/commands/oftree.c index 7404db56b..b9d3c7bf2 100644 --- a/commands/oftree.c +++ b/commands/oftree.c @@ -108,7 +108,7 @@ static int do_oftree(int argc, char *argv[]) return 1; } - ret = of_parse_dtb(fdt); + ret = of_unflatten_dtb(fdt); if (ret) { printf("parse oftree: %s\n", strerror(-ret)); return 1; diff --git a/drivers/of/base.c b/drivers/of/base.c index 69fbf9a2d..cb1989d96 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -833,7 +833,7 @@ int of_probe(void) * Parse a flat device tree binary blob and store it in the barebox * internal tree format, */ -int of_parse_dtb(struct fdt_header *fdt) +int of_unflatten_dtb(struct fdt_header *fdt) { const void *nodep; /* property node pointer */ int nodeoffset; /* node offset from libfdt */ diff --git a/include/of.h b/include/of.h index 40549172c..7682503b2 100644 --- a/include/of.h +++ b/include/of.h @@ -108,6 +108,7 @@ void of_print_nodes(struct device_node *node, int indent); int of_probe(void); int of_parse_dtb(struct fdt_header *fdt); void of_free(struct device_node *node); +int of_unflatten_dtb(struct fdt_header *fdt); int of_property_read_string(struct device_node *np, const char *propname, const char **out_string); From 875430927dfbdb0bb7653c0bba29862e57fa0e85 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 9 Jan 2013 09:39:06 +0100 Subject: [PATCH 08/19] of: Add support for converting the unflattened tree back to a dtb We already have support for unflattening the devicetree. This patch adds support for converting it back to a dtb. Signed-off-by: Sascha Hauer --- drivers/of/base.c | 66 +++++++++++++++++++++++++++++++++++++++++++++++ include/of.h | 6 +++++ 2 files changed, 72 insertions(+) diff --git a/drivers/of/base.c b/drivers/of/base.c index cb1989d96..96ddcbc4c 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -24,6 +24,7 @@ #include #include #include +#include #include /** @@ -909,6 +910,71 @@ int of_unflatten_dtb(struct fdt_header *fdt) return 0; } +static int __of_flatten_dtb(void *fdt, struct device_node *node) +{ + struct property *p; + struct device_node *n; + int ret; + + ret = fdt_begin_node(fdt, node->name); + if (ret) + return ret; + + list_for_each_entry(p, &node->properties, list) { + ret = fdt_property(fdt, p->name, p->value, p->length); + if (ret) + return ret; + } + + list_for_each_entry(n, &node->children, parent_list) { + ret = __of_flatten_dtb(fdt, n); + if (ret) + return ret; + } + + ret = fdt_end_node(fdt); + + return ret; +} + +#define DTB_SIZE SZ_128K + +void *of_flatten_dtb(void) +{ + void *fdt; + int ret; + + if (!root_node) + return NULL; + + fdt = malloc(DTB_SIZE); + if (!fdt) + return NULL; + + memset(fdt, 0, DTB_SIZE); + + ret = fdt_create(fdt, DTB_SIZE); + if (ret) + goto out_free; + + ret = fdt_finish_reservemap(fdt); + if (ret) + goto out_free; + + ret = __of_flatten_dtb(fdt, root_node); + if (ret) + goto out_free; + + fdt_finish(fdt); + + return fdt; + +out_free: + free(fdt); + + return NULL; +} + int of_device_is_stdout_path(struct device_d *dev) { struct device_node *dn; diff --git a/include/of.h b/include/of.h index 7682503b2..dfc1b38e3 100644 --- a/include/of.h +++ b/include/of.h @@ -121,6 +121,7 @@ struct device_node *of_get_root_node(void); int of_alias_get_id(struct device_node *np, const char *stem); int of_device_is_stdout_path(struct device_d *dev); const char *of_get_model(void); +void *of_flatten_dtb(void); #else static inline int of_parse_partitions(const char *cdevname, struct device_node *node) @@ -147,6 +148,11 @@ static inline const char *of_get_model(void) { return NULL; } + +static inline void *of_flatten_dtb(void) +{ + return NULL; +} #endif #endif /* __OF_H */ From 4979d8e9d5f6bc51700ca0f9e4ceaf153bd9f77e Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Thu, 10 Jan 2013 15:05:20 +0100 Subject: [PATCH 09/19] of: remove unused barebox_fdt barebox_fdt should once become the pointer to the barebox internal devicetree. Since barebox has its own internal devicetree format this was never used. remove it. Signed-off-by: Sascha Hauer --- commands/oftree.c | 9 +-------- common/oftree.c | 2 -- include/of.h | 2 -- 3 files changed, 1 insertion(+), 12 deletions(-) diff --git a/commands/oftree.c b/commands/oftree.c index b9d3c7bf2..17af9eb58 100644 --- a/commands/oftree.c +++ b/commands/oftree.c @@ -62,8 +62,6 @@ static int do_oftree(int argc, char *argv[]) } break; case 'f': - free(barebox_fdt); - barebox_fdt = NULL; return 0; case 'n': node = optarg; @@ -88,12 +86,7 @@ static int do_oftree(int argc, char *argv[]) fdt_print(fdt, node); free(fdt); } else { - if (barebox_fdt) { - fdt_print(barebox_fdt, node); - return 0; - } else { - return 1; - } + return 1; } return 0; } diff --git a/common/oftree.c b/common/oftree.c index 0dd6d5c3e..d699cb6cf 100644 --- a/common/oftree.c +++ b/common/oftree.c @@ -246,8 +246,6 @@ int fdt_get_path_or_create(struct fdt_header *fdt, const char *path) return nodeoffset; } -struct fdt_header *barebox_fdt; - static int of_fixup_bootargs(struct fdt_header *fdt) { int nodeoffset; diff --git a/include/of.h b/include/of.h index dfc1b38e3..2c0af52d8 100644 --- a/include/of.h +++ b/include/of.h @@ -5,8 +5,6 @@ #include #include -extern struct fdt_header *barebox_fdt; - int fdt_print(struct fdt_header *working_fdt, const char *pathp); struct fdt_header *of_get_fixed_tree(struct fdt_header *fdt); From f3e173f6c2a086f33e7d661a92418c479d33648a Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 9 Jan 2013 14:00:25 +0100 Subject: [PATCH 10/19] ARM bootm: only use concatenated oftree when no other is available When an oftree is already specified use it. This lets the user boot a kernel with an oftree he provided himself rather than hardcoding the concatenated one. Signed-off-by: Sascha Hauer --- arch/arm/lib/bootm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/arch/arm/lib/bootm.c b/arch/arm/lib/bootm.c index b7dc96ee3..dc2900479 100644 --- a/arch/arm/lib/bootm.c +++ b/arch/arm/lib/bootm.c @@ -138,6 +138,9 @@ static int do_bootz_linux_fdt(int fd, struct image_data *data) u32 end; + if (data->oftree) + return -ENXIO; + header = &__header; ret = read(fd, header, sizeof(*header)); if (ret < sizeof(*header)) From 9e824f30c21c1f6b667b82a287105803598b98a1 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 9 Jan 2013 15:30:17 +0100 Subject: [PATCH 11/19] of: unflatten: allow overlay dtbs This implements overlaying a currently loaded dtb with another dtb. We used to return -EBUSY when a oftree is currently loaded. Instead of doing this, check if a node already exists before creating a new one. Similarly, if a property already exists, just overwrite the value instead of creating a new property. Signed-off-by: Sascha Hauer --- drivers/of/base.c | 33 ++++++++++++++++++++++----------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/drivers/of/base.c b/drivers/of/base.c index 96ddcbc4c..50c7ec98f 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -845,13 +845,11 @@ int of_unflatten_dtb(struct fdt_header *fdt) const struct fdt_property *fdt_prop; const char *pathp; int depth = 10000; - struct device_node *node = NULL; + struct device_node *node = NULL, *n; + struct property *p; char buf[1024]; int ret; - if (root_node) - return -EBUSY; - nodeoffset = fdt_path_offset(fdt, "/"); if (nodeoffset < 0) { /* @@ -875,12 +873,17 @@ int of_unflatten_dtb(struct fdt_header *fdt) if (ret) return -EINVAL; - node = new_device_node(node); - if (!node->parent) - root_node = node; - node->full_name = xstrdup(buf); - node->name = xstrdup(pathp); - list_add_tail(&node->list, &allnodes); + n = of_find_node_by_path(buf); + if (n) { + node = n; + } else { + node = new_device_node(node); + if (!node->parent) + root_node = node; + node->full_name = xstrdup(buf); + node->name = xstrdup(pathp); + list_add_tail(&node->list, &allnodes); + } break; case FDT_END_NODE: node = node->parent; @@ -892,7 +895,15 @@ int of_unflatten_dtb(struct fdt_header *fdt) fdt32_to_cpu(fdt_prop->nameoff)); len = fdt32_to_cpu(fdt_prop->len); nodep = fdt_prop->data; - new_property(node, pathp, nodep, len); + + p = of_find_property(node, pathp); + if (p) { + free(p->value); + p->value = xzalloc(len); + memcpy(p->value, nodep, len); + } else { + new_property(node, pathp, nodep, len); + } break; case FDT_NOP: break; From e118761c5f7e8e41fa3503ae96885459869dcb84 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 9 Jan 2013 13:14:45 +0100 Subject: [PATCH 12/19] oftree command: refactor This has several improvements for the oftree command: - loading a devicetree (-l) and actually probing (-p) it now is separated - the command now can dump the internal devicetree or a dtb given on the command line. - The -f option now actually frees the internal devicetree With this the usage pattern for this command is: oftree -l /env/oftree oftree -d -n /sound oftree -d /env/oftree oftree -f oftree -p oftree -l -p /env/oftree Signed-off-by: Sascha Hauer --- commands/Kconfig | 9 +--- commands/oftree.c | 103 +++++++++++++++++++++++++++++++--------------- common/oftree.c | 11 +++-- 3 files changed, 79 insertions(+), 44 deletions(-) diff --git a/commands/Kconfig b/commands/Kconfig index 53cee5cbf..b9151ed25 100644 --- a/commands/Kconfig +++ b/commands/Kconfig @@ -471,19 +471,12 @@ config CMD_GO config CMD_OFTREE tristate select OFTREE + select OFDEVICE prompt "oftree" help The oftree command has support for dumping devicetrees and, if enabled, to probe devices from the devicetree -config CMD_OFTREE_PROBE - bool - depends on CMD_OFTREE - select OFDEVICE - prompt "oftree probe support" - help - This enables the -p option to probe devices from the devicetree - endmenu menu "testing" diff --git a/commands/oftree.c b/commands/oftree.c index 17af9eb58..c5239eb8e 100644 --- a/commands/oftree.c +++ b/commands/oftree.c @@ -39,17 +39,23 @@ static int do_oftree(int argc, char *argv[]) { - struct fdt_header *fdt; + struct fdt_header *fdt = NULL; + void *fdt_free = NULL; int size; int opt; char *file = NULL; const char *node = "/"; int dump = 0; int probe = 0; + int load = 0; + int free_of = 0; int ret; - while ((opt = getopt(argc, argv, "dpfn:")) > 0) { + while ((opt = getopt(argc, argv, "dpfn:l")) > 0) { switch (opt) { + case 'l': + load = 1; + break; case 'd': dump = 1; break; @@ -62,66 +68,97 @@ static int do_oftree(int argc, char *argv[]) } break; case 'f': - return 0; + free_of = 1; + break; case 'n': node = optarg; break; } } - if (optind < argc) - file = argv[optind]; + if (free_of) { + struct device_node *root = of_get_root_node(); - if (!dump && !probe) - return COMMAND_ERROR_USAGE; + if (root) + of_free(root); - if (dump) { - if (file) { - fdt = read_file(file, &size); - if (!fdt) { - printf("unable to read %s\n", file); - return 1; - } - - fdt_print(fdt, node); - free(fdt); - } else { - return 1; - } return 0; } - if (probe) { - if (!file) - return COMMAND_ERROR_USAGE; + if (optind < argc) + file = argv[optind]; + if (!dump && !probe && !load) + return COMMAND_ERROR_USAGE; + + if (file) { fdt = read_file(file, &size); if (!fdt) { - perror("open"); + printf("unable to read %s\n", file); return 1; } + fdt_free = fdt; + } + + if (load) { + if (!fdt) { + printf("no fdt given\n"); + ret = -ENOENT; + + goto out; + } + ret = of_unflatten_dtb(fdt); if (ret) { printf("parse oftree: %s\n", strerror(-ret)); - return 1; + goto out; } - - of_probe(); } - return 0; + if (dump) { + if (fdt) { + ret = fdt_print(fdt, node); + } else { + struct device_node *n = of_find_node_by_path(node); + + if (!n) { + ret = -ENOENT; + goto out; + } + + of_print_nodes(n, 0); + + ret = 0; + } + + goto out; + } + + if (probe) { + ret = of_probe(); + if (ret) + goto out; + } + + ret = 0; +out: + free(fdt_free); + + return ret; } BAREBOX_CMD_HELP_START(oftree) -BAREBOX_CMD_HELP_USAGE("oftree [OPTIONS]\n") -BAREBOX_CMD_HELP_OPT ("-p ", "probe devices in oftree from \n") -BAREBOX_CMD_HELP_OPT ("-d [FILE]", "dump oftree from [FILE] or the parsed tree if no file is given\n") -BAREBOX_CMD_HELP_OPT ("-f", "free stored oftree\n") +BAREBOX_CMD_HELP_USAGE("oftree [OPTIONS] [DTB]\n") +BAREBOX_CMD_HELP_OPT ("-l", "Load [DTB] to internal devicetree\n") +BAREBOX_CMD_HELP_OPT ("-p", "probe devices from stored devicetree\n") +BAREBOX_CMD_HELP_OPT ("-d", "dump oftree from [DTB] or the parsed tree if no dtb is given\n") +BAREBOX_CMD_HELP_OPT ("-f", "free stored devicetree\n") +BAREBOX_CMD_HELP_OPT ("-n ", "specify root devicenode to dump for -d\n") BAREBOX_CMD_HELP_END BAREBOX_CMD_START(oftree) .cmd = do_oftree, - .usage = "handle oftrees", + .usage = "handle devicetrees", BAREBOX_CMD_HELP(cmd_oftree_help) BAREBOX_CMD_END diff --git a/common/oftree.c b/common/oftree.c index d699cb6cf..0df5209bd 100644 --- a/common/oftree.c +++ b/common/oftree.c @@ -325,11 +325,14 @@ int of_fix_tree(struct fdt_header *fdt) struct fdt_header *of_get_fixed_tree(struct fdt_header *fdt) { int ret; - void *fixfdt; + void *fixfdt, *internalfdt = NULL; int size, align; - if (!fdt) - return NULL; + if (!fdt) { + fdt = internalfdt = of_flatten_dtb(); + if (!fdt) + return NULL; + } size = fdt_totalsize(fdt); @@ -343,6 +346,8 @@ struct fdt_header *of_get_fixed_tree(struct fdt_header *fdt) fixfdt = xmemalign(align, size + OFTREE_SIZE_INCREASE); ret = fdt_open_into(fdt, fixfdt, size + OFTREE_SIZE_INCREASE); + free(internalfdt); + if (ret) goto out_free; From 517fcac5f02c8e26a600f1cf14c26af8265f3b29 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 9 Jan 2013 16:47:16 +0100 Subject: [PATCH 13/19] of: add of_delete_property This adds a function to delete a property from the currently loaded devicetree. Also export new_property as of_new_property. Signed-off-by: Sascha Hauer --- drivers/of/base.c | 13 +++++++++++-- include/of.h | 3 +++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/drivers/of/base.c b/drivers/of/base.c index 50c7ec98f..a6a12f07f 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -600,7 +600,7 @@ static struct device_node *new_device_node(struct device_node *parent) return node; } -static struct property *new_property(struct device_node *node, const char *name, +struct property *of_new_property(struct device_node *node, const char *name, const void *data, int len) { struct property *prop; @@ -617,6 +617,15 @@ static struct property *new_property(struct device_node *node, const char *name, return prop; } +void of_delete_property(struct property *pp) +{ + list_del(&pp->list); + + free(pp->name); + free(pp->value); + free(pp); +} + static struct device_d *add_of_device(struct device_node *node) { struct device_d *dev; @@ -902,7 +911,7 @@ int of_unflatten_dtb(struct fdt_header *fdt) p->value = xzalloc(len); memcpy(p->value, nodep, len); } else { - new_property(node, pathp, nodep, len); + of_new_property(node, pathp, nodep, len); } break; case FDT_NOP: diff --git a/include/of.h b/include/of.h index 2c0af52d8..3679b01ea 100644 --- a/include/of.h +++ b/include/of.h @@ -107,6 +107,9 @@ int of_probe(void); int of_parse_dtb(struct fdt_header *fdt); void of_free(struct device_node *node); int of_unflatten_dtb(struct fdt_header *fdt); +struct property *of_new_property(struct device_node *node, const char *name, + const void *data, int len); +void of_delete_property(struct property *pp); int of_property_read_string(struct device_node *np, const char *propname, const char **out_string); From a2288e64b74b5df8a40309dd636ae2ce8c39b12b Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 9 Jan 2013 23:19:59 +0100 Subject: [PATCH 14/19] of: rename new_device_node to of_new_node and export it of_new_node now takes the parent node and the name as argument and creates a new node. This simplifies the caller and also makes the function useful for others, so export it. Signed-off-by: Sascha Hauer --- drivers/of/base.c | 24 +++++++++++++++++------- include/of.h | 1 + 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/drivers/of/base.c b/drivers/of/base.c index a6a12f07f..93a4af9c6 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -585,18 +585,33 @@ void of_print_nodes(struct device_node *node, int indent) printf("};\n"); } -static struct device_node *new_device_node(struct device_node *parent) +struct device_node *of_new_node(struct device_node *parent, const char *name) { struct device_node *node; + if (!parent && root_node) + return NULL; + node = xzalloc(sizeof(*node)); node->parent = parent; if (parent) list_add_tail(&node->parent_list, &parent->children); + else + root_node = node; INIT_LIST_HEAD(&node->children); INIT_LIST_HEAD(&node->properties); + if (parent) { + node->name = xstrdup(name); + node->full_name = asprintf("%s/%s", node->parent->full_name, name); + } else { + node->name = xstrdup(""); + node->full_name = xstrdup(""); + } + + list_add_tail(&node->list, &allnodes); + return node; } @@ -886,12 +901,7 @@ int of_unflatten_dtb(struct fdt_header *fdt) if (n) { node = n; } else { - node = new_device_node(node); - if (!node->parent) - root_node = node; - node->full_name = xstrdup(buf); - node->name = xstrdup(pathp); - list_add_tail(&node->list, &allnodes); + node = of_new_node(node, pathp); } break; case FDT_END_NODE: diff --git a/include/of.h b/include/of.h index 3679b01ea..d3a310f2f 100644 --- a/include/of.h +++ b/include/of.h @@ -107,6 +107,7 @@ int of_probe(void); int of_parse_dtb(struct fdt_header *fdt); void of_free(struct device_node *node); int of_unflatten_dtb(struct fdt_header *fdt); +struct device_node *of_new_node(struct device_node *parent, const char *name); struct property *of_new_property(struct device_node *node, const char *name, const void *data, int len); void of_delete_property(struct property *pp); From 8943b86aa8e821ed1b5238de840fbfadfeb37224 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 9 Jan 2013 16:41:44 +0100 Subject: [PATCH 15/19] commands: Add of_property command The of_property command allows to modify/add/delete properties. Parsing user input is based on U-Boot code with some fixes added for catching invalid input. Signed-off-by: Sascha Hauer --- commands/Kconfig | 9 ++ commands/Makefile | 1 + commands/of_property.c | 280 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 290 insertions(+) create mode 100644 commands/of_property.c diff --git a/commands/Kconfig b/commands/Kconfig index b9151ed25..4e0b8694d 100644 --- a/commands/Kconfig +++ b/commands/Kconfig @@ -477,6 +477,15 @@ config CMD_OFTREE The oftree command has support for dumping devicetrees and, if enabled, to probe devices from the devicetree +config CMD_OF_PROPERTY + tristate + select OFTREE + select OFDEVICE + prompt "of_property" + help + The of_property command allows setting and deleting of properties in + the currently loaded devicetree. + endmenu menu "testing" diff --git a/commands/Makefile b/commands/Makefile index 359f56621..98d61c63a 100644 --- a/commands/Makefile +++ b/commands/Makefile @@ -67,6 +67,7 @@ obj-$(CONFIG_CMD_LED_TRIGGER) += trigger.o obj-$(CONFIG_CMD_USB) += usb.o obj-$(CONFIG_CMD_TIME) += time.o obj-$(CONFIG_CMD_OFTREE) += oftree.o +obj-$(CONFIG_CMD_OF_PROPERTY) += of_property.o obj-$(CONFIG_CMD_MAGICVAR) += magicvar.o obj-$(CONFIG_CMD_IOMEM) += iomem.o obj-$(CONFIG_CMD_LINUX_EXEC) += linux_exec.o diff --git a/commands/of_property.c b/commands/of_property.c new file mode 100644 index 000000000..42b6f1123 --- /dev/null +++ b/commands/of_property.c @@ -0,0 +1,280 @@ +/* + * of_property.c - device tree property handling support + * + * Copyright (c) 2013 Sascha Hauer , Pengutronix + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int of_parse_prop_cells(char * const *newval, int count, char *data, int *len) +{ + char *cp; + unsigned long tmp; /* holds converted values */ + int stridx = 0; + char *newp = newval[0]; + + newp++; + + while (1) { + if (*newp == '>') + return 0; + + if (*newp == '\0') { + newp = newval[++stridx]; + + if (stridx == count) { + printf("missing '>'\n"); + return -EINVAL; + } + + continue; + } + + cp = newp; + tmp = simple_strtoul(cp, &newp, 0); + *(__be32 *)data = __cpu_to_be32(tmp); + data += 4; + *len += 4; + + /* If the ptr didn't advance, something went wrong */ + if ((newp - cp) <= 0) { + printf("cannot not convert \"%s\"\n", cp); + return -EINVAL; + } + + while (*newp == ' ') + newp++; + } +} + +static int of_parse_prop_stream(char * const *newval, int count, char *data, int *len) +{ + char *cp; + unsigned long tmp; /* holds converted values */ + int stridx = 0; + char *newp = newval[0]; + + newp++; + + while (1) { + if (*newp == ']') + return 0; + + while (*newp == ' ') + newp++; + + if (*newp == '\0') { + newp = newval[++stridx]; + + if (stridx == count) { + printf("missing ']'\n"); + return -EINVAL; + } + + continue; + } + + cp = newp; + tmp = simple_strtoul(newp, &newp, 16); + *data++ = tmp & 0xff; + *len = *len + 1; + + /* If the ptr didn't advance, something went wrong */ + if ((newp - cp) <= 0) { + printf("cannot not convert \"%s\"\n", cp); + return -EINVAL; + } + } +} + +static int of_parse_prop_string(char * const *newval, int count, char *data, int *len) +{ + int stridx = 0; + char *newp = newval[0]; + + /* + * Assume it is one or more strings. Copy it into our + * data area for convenience (including the + * terminating '\0's). + */ + while (stridx < count) { + size_t length = strlen(newp) + 1; + + strcpy(data, newp); + data += length; + *len += length; + newp = newval[++stridx]; + } + + return 0; +} + +/* + * Parse the user's input, partially heuristic. Valid formats: + * <0x00112233 4 05> - an array of cells. Numbers follow standard + * C conventions. + * [00 11 22 .. nn] - byte stream + * "string" - If the the value doesn't start with "<" or "[", it is + * treated as a string. Note that the quotes are + * stripped by the parser before we get the string. + * newval: An array of strings containing the new property as specified + * on the command line + * count: The number of strings in the array + * data: A bytestream to be placed in the property + * len: The length of the resulting bytestream + */ +static int of_parse_prop(char * const *newval, int count, char *data, int *len) +{ + char *newp; /* temporary newval char pointer */ + + *len = 0; + + if (!count) + return 0; + + newp = newval[0]; + + switch (*newp) { + case '<': + return of_parse_prop_cells(newval, count, data, len); + case '[': + return of_parse_prop_stream(newval, count, data, len); + default: + return of_parse_prop_string(newval, count, data, len); + } +} + +static int do_of_property(int argc, char *argv[]) +{ + int opt; + int delete = 0; + int set = 0; + int ret; + char *path = NULL, *propname = NULL; + struct device_node *node = NULL; + struct property *pp = NULL; + + while ((opt = getopt(argc, argv, "ds")) > 0) { + switch (opt) { + case 'd': + delete = 1; + break; + case 's': + set = 1; + break; + default: + return COMMAND_ERROR_USAGE; + } + } + + if (optind < argc) { + path = argv[optind]; + node = of_find_node_by_path(path); + if (!node) { + printf("Cannot find nodepath %s\n", path); + return -ENOENT; + } + } + + if (optind + 1 < argc) { + propname = argv[optind + 1]; + + pp = of_find_property(node, propname); + if (!set && !pp) { + printf("Cannot find property %s\n", propname); + return -ENOENT; + } + } + + debug("path: %s propname: %s\n", path, propname); + + if (delete) { + if (!node || !pp) + return COMMAND_ERROR_USAGE; + + of_delete_property(pp); + + return 0; + } + + if (set) { + int num_args = argc - optind - 2; + int len; + void *data; + + if (!node) + return COMMAND_ERROR_USAGE; + + /* + * standard console buffer size. The result won't be bigger than the + * string input. + */ + data = malloc(1024); + if (!data) + return -ENOMEM; + + ret = of_parse_prop(&argv[optind + 2], num_args, data, &len); + if (ret) { + free(data); + return ret; + } + + if (pp) { + free(pp->value); + /* limit property data to the actual size */ + data = xrealloc(data, len); + pp->value = data; + pp->length = len; + } else { + pp = of_new_property(node, propname, data, len); + if (!pp) { + printf("Cannot create property %s\n", propname); + free(data); + return 1; + } + } + } + + return 0; +} + +BAREBOX_CMD_HELP_START(of_property) +BAREBOX_CMD_HELP_USAGE("of_property [OPTIONS] [NODE] [PROPERTY] [VALUES]\n") +BAREBOX_CMD_HELP_OPT ("-s", "set property to value\n") +BAREBOX_CMD_HELP_OPT ("-d", "delete property\n") +BAREBOX_CMD_HELP_TEXT ("\nvalid formats for values:\n") +BAREBOX_CMD_HELP_TEXT ("<0x00112233 4 05> - an array of cells\n") +BAREBOX_CMD_HELP_TEXT ("[00 11 22 .. nn] - byte stream\n") +BAREBOX_CMD_HELP_TEXT ("If the value does not start with '<' or '[' it is interpreted as strings\n") +BAREBOX_CMD_HELP_END + +BAREBOX_CMD_START(of_property) + .cmd = do_of_property, + .usage = "handle of properties", + BAREBOX_CMD_HELP(cmd_of_property_help) +BAREBOX_CMD_END From db474fe0bb5e0efbb4c48d278c1bf9c592e94d4e Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 9 Jan 2013 23:23:55 +0100 Subject: [PATCH 16/19] commands: Add of_node command This command allows to create/delete device nodes. Signed-off-by: Sascha Hauer --- commands/Kconfig | 8 ++++ commands/Makefile | 1 + commands/of_node.c | 111 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 120 insertions(+) create mode 100644 commands/of_node.c diff --git a/commands/Kconfig b/commands/Kconfig index 4e0b8694d..d0ea29e10 100644 --- a/commands/Kconfig +++ b/commands/Kconfig @@ -486,6 +486,14 @@ config CMD_OF_PROPERTY The of_property command allows setting and deleting of properties in the currently loaded devicetree. +config CMD_OF_NODE + tristate + select OFTREE + select OFDEVICE + prompt "of_node" + help + The of_property command allows adding and removing devicetree nodes. + endmenu menu "testing" diff --git a/commands/Makefile b/commands/Makefile index 98d61c63a..2df807b0c 100644 --- a/commands/Makefile +++ b/commands/Makefile @@ -68,6 +68,7 @@ obj-$(CONFIG_CMD_USB) += usb.o obj-$(CONFIG_CMD_TIME) += time.o obj-$(CONFIG_CMD_OFTREE) += oftree.o obj-$(CONFIG_CMD_OF_PROPERTY) += of_property.o +obj-$(CONFIG_CMD_OF_NODE) += of_node.o obj-$(CONFIG_CMD_MAGICVAR) += magicvar.o obj-$(CONFIG_CMD_IOMEM) += iomem.o obj-$(CONFIG_CMD_LINUX_EXEC) += linux_exec.o diff --git a/commands/of_node.c b/commands/of_node.c new file mode 100644 index 000000000..a370e2699 --- /dev/null +++ b/commands/of_node.c @@ -0,0 +1,111 @@ +/* + * of_node.c - device tree node handling support + * + * Copyright (c) 2013 Sascha Hauer , Pengutronix + * + * See file CREDITS for list of people who contributed to this + * project. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int do_of_node(int argc, char *argv[]) +{ + int opt; + int delete = 0; + int create = 0; + char *path = NULL; + struct device_node *node = NULL; + + while ((opt = getopt(argc, argv, "cd")) > 0) { + switch (opt) { + case 'c': + create = 1; + break; + case 'd': + delete = 1; + break; + default: + return COMMAND_ERROR_USAGE; + } + } + + if (optind < argc) { + path = argv[optind]; + } + + if (create) { + char *name; + + if (!path) + return COMMAND_ERROR_USAGE; + + name = xstrdup(basename(path)); + path = dirname(path); + + node = of_find_node_by_path(path); + if (!node) { + printf("Cannot find nodepath %s\n", path); + free(name); + return -ENOENT; + } + + debug("create node \"%s\" \"%s\"\n", path, name); + + of_new_node(node, name); + + free(name); + + return 0; + } + + if (delete) { + if (!path) + return COMMAND_ERROR_USAGE; + + node = of_find_node_by_path(path); + if (!node) { + printf("Cannot find nodepath %s\n", path); + return -ENOENT; + } + + of_free(node); + } + + return 0; +} + +BAREBOX_CMD_HELP_START(of_node) +BAREBOX_CMD_HELP_USAGE("of_node [OPTIONS] [NODE] [NAME]\n") +BAREBOX_CMD_HELP_OPT ("-c", "create a new node\n") +BAREBOX_CMD_HELP_OPT ("-d", "delete a node\n") +BAREBOX_CMD_HELP_END + +BAREBOX_CMD_START(of_node) + .cmd = do_of_node, + .usage = "handle of nodes", + BAREBOX_CMD_HELP(cmd_of_node_help) +BAREBOX_CMD_END From 555dc6cc608632a3edd159fae59d13021540aa9e Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 11 Jan 2013 16:33:18 +0100 Subject: [PATCH 17/19] of: speed up unflatten We calculate the full path of the current node using fdt_get_path which takes a lot of time since libfdt has to iterate over the dtb several times. Speed this up by creating and using a of_find_child function which does not have to iterate over the whole tree but only over its direct children. On an i.MX51 board this speeds up unflatten the tree from 60ms to 3.7ms. Signed-off-by: Sascha Hauer --- drivers/of/base.c | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/drivers/of/base.c b/drivers/of/base.c index 93a4af9c6..eaaeaf4f4 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -854,6 +854,27 @@ int of_probe(void) return 0; } +static struct device_node *of_find_child(struct device_node *node, const char *name) +{ + struct device_node *_n; + + if (!root_node) + return NULL; + + if (!node && !*name) + return root_node; + + if (!node) + node = root_node; + + list_for_each_entry(_n, &node->children, parent_list) { + if (!strcmp(_n->name, name)) + return _n; + } + + return NULL; +} + /* * Parse a flat device tree binary blob and store it in the barebox * internal tree format, @@ -871,8 +892,6 @@ int of_unflatten_dtb(struct fdt_header *fdt) int depth = 10000; struct device_node *node = NULL, *n; struct property *p; - char buf[1024]; - int ret; nodeoffset = fdt_path_offset(fdt, "/"); if (nodeoffset < 0) { @@ -893,11 +912,7 @@ int of_unflatten_dtb(struct fdt_header *fdt) if (pathp == NULL) pathp = "/* NULL pointer error */"; - ret = fdt_get_path(fdt, nodeoffset, buf, 1024); - if (ret) - return -EINVAL; - - n = of_find_node_by_path(buf); + n = of_find_child(node, pathp); if (n) { node = n; } else { From a886dac94e8466c640e4aa23e1629467a941f439 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 11 Jan 2013 17:38:52 +0100 Subject: [PATCH 18/19] Add write_file function write_file() will write a buffer to a file. The file is created if necessary. Signed-off-by: Sascha Hauer --- fs/fs.c | 19 +++++++++++++++++++ include/fs.h | 5 +++++ 2 files changed, 24 insertions(+) diff --git a/fs/fs.c b/fs/fs.c index 04331fcd0..f84051613 100644 --- a/fs/fs.c +++ b/fs/fs.c @@ -67,6 +67,25 @@ err_out: EXPORT_SYMBOL(read_file); +int write_file(const char *filename, void *buf, size_t size) +{ + int fd, ret; + + fd = open(filename, O_WRONLY | O_TRUNC | O_CREAT); + if (fd < 0) + return fd; + + ret = write_full(fd, buf, size); + + close(fd); + + if (ret < 0) + return ret; + + return 0; +} +EXPORT_SYMBOL(write_file); + char *mkmodestr(unsigned long mode, char *str) { static const char *l = "xwr"; diff --git a/include/fs.h b/include/fs.h index 8ff730091..919daab67 100644 --- a/include/fs.h +++ b/include/fs.h @@ -166,6 +166,11 @@ char *mkmodestr(unsigned long mode, char *str); */ void *read_file(const char *filename, size_t *size); +/* + * Write a buffer to a file. This file is newly created. + */ +int write_file(const char *filename, void *buf, size_t size); + /* * This function turns 'path' into an absolute path and removes all occurrences * of "..", "." and double slashes. The returned string must be freed wit free(). From 9a554f8ff25685e44431079e73887b061d6f4a41 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Fri, 11 Jan 2013 17:38:26 +0100 Subject: [PATCH 19/19] oftree command: Add -s option to save internal oftree to file Signed-off-by: Sascha Hauer --- commands/oftree.c | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/commands/oftree.c b/commands/oftree.c index c5239eb8e..ddbff3e37 100644 --- a/commands/oftree.c +++ b/commands/oftree.c @@ -36,6 +36,7 @@ #include #include #include +#include static int do_oftree(int argc, char *argv[]) { @@ -48,10 +49,11 @@ static int do_oftree(int argc, char *argv[]) int dump = 0; int probe = 0; int load = 0; + int save = 0; int free_of = 0; int ret; - while ((opt = getopt(argc, argv, "dpfn:l")) > 0) { + while ((opt = getopt(argc, argv, "dpfn:ls")) > 0) { switch (opt) { case 'l': load = 1; @@ -73,6 +75,9 @@ static int do_oftree(int argc, char *argv[]) case 'n': node = optarg; break; + case 's': + save = 1; + break; } } @@ -88,9 +93,30 @@ static int do_oftree(int argc, char *argv[]) if (optind < argc) file = argv[optind]; - if (!dump && !probe && !load) + if (!dump && !probe && !load && !save) return COMMAND_ERROR_USAGE; + if (save) { + if (!file) { + printf("no file given\n"); + ret = -ENOENT; + + goto out; + } + + fdt = of_get_fixed_tree(NULL); + if (!fdt) { + printf("no devicetree available\n"); + ret = -EINVAL; + + goto out; + } + + ret = write_file(file, fdt, fdt_totalsize(fdt)); + + goto out; + } + if (file) { fdt = read_file(file, &size); if (!fdt) {