diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2013-02-04 15:49:04 +0100 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2013-02-04 15:49:04 +0100 |
commit | 0b12784089b6a4372ed27cf1fd578d85a7d3dbd4 (patch) | |
tree | 6f25a55d72f51aeb1d42f02bf5f56edcc051b41a /commands | |
parent | 5c6cc8736ed4e14119fb2e8c0ed1ecab7caff9ae (diff) | |
parent | 9a554f8ff25685e44431079e73887b061d6f4a41 (diff) | |
download | barebox-0b12784089b6a4372ed27cf1fd578d85a7d3dbd4.tar.gz barebox-0b12784089b6a4372ed27cf1fd578d85a7d3dbd4.tar.xz |
Merge branch 'for-next/oftree'
Conflicts:
drivers/of/base.c
Diffstat (limited to 'commands')
-rw-r--r-- | commands/Kconfig | 20 | ||||
-rw-r--r-- | commands/Makefile | 2 | ||||
-rw-r--r-- | commands/bootm.c | 32 | ||||
-rw-r--r-- | commands/of_node.c | 111 | ||||
-rw-r--r-- | commands/of_property.c | 280 | ||||
-rw-r--r-- | commands/oftree.c | 130 |
6 files changed, 509 insertions, 66 deletions
diff --git a/commands/Kconfig b/commands/Kconfig index 1addd91d24..d3c338c832 100644 --- a/commands/Kconfig +++ b/commands/Kconfig @@ -481,18 +481,28 @@ 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 +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. + +config CMD_OF_NODE + tristate + select OFTREE select OFDEVICE - prompt "oftree probe support" + prompt "of_node" help - This enables the -p option to probe devices from the devicetree + The of_property command allows adding and removing devicetree nodes. endmenu diff --git a/commands/Makefile b/commands/Makefile index c4baf6a470..0ae6b9546a 100644 --- a/commands/Makefile +++ b/commands/Makefile @@ -67,6 +67,8 @@ 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_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/bootm.c b/commands/bootm.c index 5ccf2372ac..4d3f0221ca 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; printf("Loading devicetree from '%s'\n", oftree); @@ -189,36 +187,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/commands/of_node.c b/commands/of_node.c new file mode 100644 index 0000000000..a370e2699a --- /dev/null +++ b/commands/of_node.c @@ -0,0 +1,111 @@ +/* + * of_node.c - device tree node handling support + * + * Copyright (c) 2013 Sascha Hauer <s.hauer@pengutronix.de>, 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 <common.h> +#include <environment.h> +#include <fdt.h> +#include <of.h> +#include <command.h> +#include <fs.h> +#include <malloc.h> +#include <libfdt.h> +#include <linux/ctype.h> +#include <asm/byteorder.h> +#include <errno.h> +#include <getopt.h> +#include <init.h> +#include <libgen.h> + +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 diff --git a/commands/of_property.c b/commands/of_property.c new file mode 100644 index 0000000000..42b6f1123f --- /dev/null +++ b/commands/of_property.c @@ -0,0 +1,280 @@ +/* + * of_property.c - device tree property handling support + * + * Copyright (c) 2013 Sascha Hauer <s.hauer@pengutronix.de>, 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 <common.h> +#include <environment.h> +#include <fdt.h> +#include <of.h> +#include <command.h> +#include <fs.h> +#include <malloc.h> +#include <libfdt.h> +#include <linux/ctype.h> +#include <asm/byteorder.h> +#include <errno.h> +#include <getopt.h> +#include <init.h> + +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 diff --git a/commands/oftree.c b/commands/oftree.c index 7404db56b1..ddbff3e374 100644 --- a/commands/oftree.c +++ b/commands/oftree.c @@ -36,20 +36,28 @@ #include <errno.h> #include <getopt.h> #include <init.h> +#include <fcntl.h> 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 save = 0; + int free_of = 0; int ret; - while ((opt = getopt(argc, argv, "dpfn:")) > 0) { + while ((opt = getopt(argc, argv, "dpfn:ls")) > 0) { switch (opt) { + case 'l': + load = 1; + break; case 'd': dump = 1; break; @@ -62,73 +70,121 @@ static int do_oftree(int argc, char *argv[]) } break; case 'f': - free(barebox_fdt); - barebox_fdt = NULL; - return 0; + free_of = 1; + break; case 'n': node = optarg; break; + case 's': + save = 1; + break; } } + if (free_of) { + struct device_node *root = of_get_root_node(); + + if (root) + of_free(root); + + return 0; + } + if (optind < argc) file = argv[optind]; - if (!dump && !probe) + if (!dump && !probe && !load && !save) return COMMAND_ERROR_USAGE; - if (dump) { - if (file) { - fdt = read_file(file, &size); - if (!fdt) { - printf("unable to read %s\n", file); - return 1; - } + if (save) { + if (!file) { + printf("no file given\n"); + ret = -ENOENT; - fdt_print(fdt, node); - free(fdt); - } else { - if (barebox_fdt) { - fdt_print(barebox_fdt, node); - return 0; - } else { - return 1; - } + goto out; } - return 0; - } - if (probe) { - if (!file) - return COMMAND_ERROR_USAGE; + 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) { - perror("open"); + printf("unable to read %s\n", file); return 1; } - ret = of_parse_dtb(fdt); + 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(); + 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; } - return 0; + 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 <FILE>", "probe devices in oftree from <file>\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 <node>", "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 |