9
0
Fork 0

Merge branch 'for-next/oftree'

Conflicts:
	drivers/of/base.c
This commit is contained in:
Sascha Hauer 2013-02-04 15:49:04 +01:00
commit 0b12784089
14 changed files with 756 additions and 111 deletions

View File

@ -138,6 +138,9 @@ static int do_bootz_linux_fdt(int fd, struct image_data *data)
u32 end; u32 end;
if (data->oftree)
return -ENXIO;
header = &__header; header = &__header;
ret = read(fd, header, sizeof(*header)); ret = read(fd, header, sizeof(*header));
if (ret < sizeof(*header)) if (ret < sizeof(*header))
@ -402,12 +405,6 @@ static int do_bootm_aimage(struct image_data *data)
if (!getenv("aimage_noverwrite_tags")) if (!getenv("aimage_noverwrite_tags"))
armlinux_set_bootparams((void*)header->tags_addr); 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; cmp = &header->second_stage;
if (cmp->size) { if (cmp->size) {
void (*second)(void); void (*second)(void);

View File

@ -23,7 +23,7 @@ static int do_bootu(int argc, char *argv[])
kernel = (void *)simple_strtoul(argv[1], NULL, 0); kernel = (void *)simple_strtoul(argv[1], NULL, 0);
#ifdef CONFIG_OFTREE #ifdef CONFIG_OFTREE
oftree = of_get_fixed_tree(); oftree = of_get_fixed_tree(NULL);
#endif #endif
start_linux(kernel, 0, 0, 0, oftree); start_linux(kernel, 0, 0, 0, oftree);

View File

@ -109,7 +109,7 @@ static int do_bootz(int argc, char *argv[])
printf("loaded zImage from %s with size %d\n", argv[1], end); printf("loaded zImage from %s with size %d\n", argv[1], end);
#ifdef CONFIG_OFTREE #ifdef CONFIG_OFTREE
oftree = of_get_fixed_tree(); oftree = of_get_fixed_tree(NULL);
#endif #endif
start_linux(zimage, swap, 0, 0, oftree); start_linux(zimage, swap, 0, 0, oftree);

View File

@ -481,18 +481,28 @@ config CMD_GO
config CMD_OFTREE config CMD_OFTREE
tristate tristate
select OFTREE select OFTREE
select OFDEVICE
prompt "oftree" prompt "oftree"
help help
The oftree command has support for dumping devicetrees and, if The oftree command has support for dumping devicetrees and, if
enabled, to probe devices from the devicetree enabled, to probe devices from the devicetree
config CMD_OFTREE_PROBE config CMD_OF_PROPERTY
bool tristate
depends on CMD_OFTREE select OFTREE
select OFDEVICE select OFDEVICE
prompt "oftree probe support" prompt "of_property"
help help
This enables the -p option to probe devices from the devicetree 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 endmenu

View File

@ -67,6 +67,8 @@ obj-$(CONFIG_CMD_LED_TRIGGER) += trigger.o
obj-$(CONFIG_CMD_USB) += usb.o obj-$(CONFIG_CMD_USB) += usb.o
obj-$(CONFIG_CMD_TIME) += time.o obj-$(CONFIG_CMD_TIME) += time.o
obj-$(CONFIG_CMD_OFTREE) += oftree.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_MAGICVAR) += magicvar.o
obj-$(CONFIG_CMD_IOMEM) += iomem.o obj-$(CONFIG_CMD_IOMEM) += iomem.o
obj-$(CONFIG_CMD_LINUX_EXEC) += linux_exec.o obj-$(CONFIG_CMD_LINUX_EXEC) += linux_exec.o

View File

@ -139,9 +139,7 @@ static int bootm_open_oftree(struct image_data *data, const char *oftree, int nu
{ {
enum filetype ft; enum filetype ft;
struct fdt_header *fdt, *fixfdt; struct fdt_header *fdt, *fixfdt;
int ret;
size_t size; size_t size;
unsigned int align;
printf("Loading devicetree from '%s'\n", oftree); 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)); file_type_to_string(ft));
} }
/* fixfdt = of_get_fixed_tree(fdt);
* ARM Linux uses a single 1MiB section (with 1MiB alignment) if (!fixfdt)
* for mapping the devicetree, so we are not allowed to cross return -EINVAL;
* 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);
free(fdt); 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) if (bootm_verbose(data) > 1)
fdt_print(fixfdt, "/"); fdt_print(fixfdt, "/");
data->oftree = fixfdt; data->oftree = fixfdt;
return ret; return 0;
} }
#endif #endif
@ -420,6 +400,10 @@ static int do_bootm(int argc, char *argv[])
ret = bootm_open_oftree(&data, oftree, oftree_num); ret = bootm_open_oftree(&data, oftree, oftree_num);
if (ret) if (ret)
goto err_out; goto err_out;
} else {
data.oftree = of_get_fixed_tree(NULL);
if (bootm_verbose(&data) && data.oftree)
printf("using internal devicetree\n");
} }
#endif #endif
if (data.os_address == UIMAGE_SOME_ADDRESS) if (data.os_address == UIMAGE_SOME_ADDRESS)

111
commands/of_node.c Normal file
View File

@ -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

280
commands/of_property.c Normal file
View File

@ -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

View File

@ -36,20 +36,28 @@
#include <errno.h> #include <errno.h>
#include <getopt.h> #include <getopt.h>
#include <init.h> #include <init.h>
#include <fcntl.h>
static int do_oftree(int argc, char *argv[]) static int do_oftree(int argc, char *argv[])
{ {
struct fdt_header *fdt; struct fdt_header *fdt = NULL;
void *fdt_free = NULL;
int size; int size;
int opt; int opt;
char *file = NULL; char *file = NULL;
const char *node = "/"; const char *node = "/";
int dump = 0; int dump = 0;
int probe = 0; int probe = 0;
int load = 0;
int save = 0;
int free_of = 0;
int ret; int ret;
while ((opt = getopt(argc, argv, "dpfn:")) > 0) { while ((opt = getopt(argc, argv, "dpfn:ls")) > 0) {
switch (opt) { switch (opt) {
case 'l':
load = 1;
break;
case 'd': case 'd':
dump = 1; dump = 1;
break; break;
@ -62,73 +70,121 @@ static int do_oftree(int argc, char *argv[])
} }
break; break;
case 'f': case 'f':
free(barebox_fdt); free_of = 1;
barebox_fdt = NULL; break;
return 0;
case 'n': case 'n':
node = optarg; node = optarg;
break; 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) if (optind < argc)
file = argv[optind]; file = argv[optind];
if (!dump && !probe) if (!dump && !probe && !load && !save)
return COMMAND_ERROR_USAGE; 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) {
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));
goto out;
}
}
if (dump) { if (dump) {
if (file) { if (fdt) {
fdt = read_file(file, &size); ret = fdt_print(fdt, node);
if (!fdt) { } else {
printf("unable to read %s\n", file); struct device_node *n = of_find_node_by_path(node);
return 1;
if (!n) {
ret = -ENOENT;
goto out;
} }
fdt_print(fdt, node); of_print_nodes(n, 0);
free(fdt);
} else { ret = 0;
if (barebox_fdt) {
fdt_print(barebox_fdt, node);
return 0;
} else {
return 1;
}
} }
return 0;
goto out;
} }
if (probe) { if (probe) {
if (!file) ret = of_probe();
return COMMAND_ERROR_USAGE; if (ret)
goto out;
fdt = read_file(file, &size);
if (!fdt) {
perror("open");
return 1;
}
ret = of_parse_dtb(fdt);
if (ret) {
printf("parse oftree: %s\n", strerror(-ret));
return 1;
}
of_probe();
} }
return 0; ret = 0;
out:
free(fdt_free);
return ret;
} }
BAREBOX_CMD_HELP_START(oftree) BAREBOX_CMD_HELP_START(oftree)
BAREBOX_CMD_HELP_USAGE("oftree [OPTIONS]\n") BAREBOX_CMD_HELP_USAGE("oftree [OPTIONS] [DTB]\n")
BAREBOX_CMD_HELP_OPT ("-p <FILE>", "probe devices in oftree from <file>\n") BAREBOX_CMD_HELP_OPT ("-l", "Load [DTB] to internal devicetree\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 ("-p", "probe devices from stored devicetree\n")
BAREBOX_CMD_HELP_OPT ("-f", "free stored oftree\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_HELP_END
BAREBOX_CMD_START(oftree) BAREBOX_CMD_START(oftree)
.cmd = do_oftree, .cmd = do_oftree,
.usage = "handle oftrees", .usage = "handle devicetrees",
BAREBOX_CMD_HELP(cmd_oftree_help) BAREBOX_CMD_HELP(cmd_oftree_help)
BAREBOX_CMD_END BAREBOX_CMD_END

View File

@ -246,8 +246,6 @@ int fdt_get_path_or_create(struct fdt_header *fdt, const char *path)
return nodeoffset; return nodeoffset;
} }
struct fdt_header *barebox_fdt;
static int of_fixup_bootargs(struct fdt_header *fdt) static int of_fixup_bootargs(struct fdt_header *fdt)
{ {
int nodeoffset; int nodeoffset;
@ -294,6 +292,10 @@ int of_register_fixup(int (*fixup)(struct fdt_header *))
return 0; 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) int of_fix_tree(struct fdt_header *fdt)
{ {
struct of_fixup *of_fixup; struct of_fixup *of_fixup;
@ -308,14 +310,55 @@ int of_fix_tree(struct fdt_header *fdt)
return 0; 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; int ret;
void *fixfdt, *internalfdt = NULL;
int size, align;
if (!fdt) {
fdt = internalfdt = of_flatten_dtb();
if (!fdt)
return NULL;
}
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);
free(internalfdt);
if (!barebox_fdt)
return NULL;
ret = of_fix_tree(barebox_fdt);
if (ret) if (ret)
return NULL; goto out_free;
return barebox_fdt;
ret = of_fix_tree(fixfdt);
if (ret)
goto out_free;
return fixfdt;
out_free:
free(fixfdt);
return NULL;
} }

View File

@ -24,6 +24,7 @@
#include <malloc.h> #include <malloc.h>
#include <init.h> #include <init.h>
#include <memory.h> #include <memory.h>
#include <sizes.h>
#include <linux/ctype.h> #include <linux/ctype.h>
/** /**
@ -138,6 +139,12 @@ static void of_alias_add(struct alias_prop *ap, struct device_node *np,
void of_alias_scan(void) void of_alias_scan(void)
{ {
struct property *pp; 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"); of_aliases = of_find_node_by_path("/aliases");
if (!of_aliases) if (!of_aliases)
@ -485,10 +492,14 @@ struct device_node *of_find_node_by_path(const char *path)
{ {
struct device_node *np; struct device_node *np;
if (!strcmp(path, "/"))
return root_node;
list_for_each_entry(np, &allnodes, list) { list_for_each_entry(np, &allnodes, list) {
if (np->full_name && (strcmp(np->full_name, path) == 0)) if (np->full_name && (strcmp(np->full_name, path) == 0))
return np; return np;
} }
return NULL; return NULL;
} }
EXPORT_SYMBOL(of_find_node_by_path); EXPORT_SYMBOL(of_find_node_by_path);
@ -574,22 +585,37 @@ void of_print_nodes(struct device_node *node, int indent)
printf("};\n"); 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; struct device_node *node;
if (!parent && root_node)
return NULL;
node = xzalloc(sizeof(*node)); node = xzalloc(sizeof(*node));
node->parent = parent; node->parent = parent;
if (parent) if (parent)
list_add_tail(&node->parent_list, &parent->children); list_add_tail(&node->parent_list, &parent->children);
else
root_node = node;
INIT_LIST_HEAD(&node->children); INIT_LIST_HEAD(&node->children);
INIT_LIST_HEAD(&node->properties); 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; 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) const void *data, int len)
{ {
struct property *prop; struct property *prop;
@ -606,6 +632,15 @@ static struct property *new_property(struct device_node *node, const char *name,
return prop; 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) static struct device_d *add_of_device(struct device_node *node)
{ {
struct device_d *dev; struct device_d *dev;
@ -754,6 +789,8 @@ void of_free(struct device_node *node)
if (!node) if (!node)
return; return;
list_del(&node->list);
list_for_each_entry_safe(p, pt, &node->properties, list) { list_for_each_entry_safe(p, pt, &node->properties, list) {
list_del(&p->list); list_del(&p->list);
free(p->name); free(p->name);
@ -776,6 +813,11 @@ void of_free(struct device_node *node)
free(node->name); free(node->name);
free(node->full_name); free(node->full_name);
free(node); free(node);
if (node == root_node)
root_node = NULL;
of_alias_scan();
} }
static void __of_probe(struct device_node *node) static void __of_probe(struct device_node *node)
@ -812,11 +854,32 @@ int of_probe(void)
return 0; 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 * Parse a flat device tree binary blob and store it in the barebox
* internal tree format, * 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 */ const void *nodep; /* property node pointer */
int nodeoffset; /* node offset from libfdt */ int nodeoffset; /* node offset from libfdt */
@ -827,12 +890,8 @@ int of_parse_dtb(struct fdt_header *fdt)
const struct fdt_property *fdt_prop; const struct fdt_property *fdt_prop;
const char *pathp; const char *pathp;
int depth = 10000; int depth = 10000;
struct device_node *node = NULL; struct device_node *node = NULL, *n;
char buf[1024]; struct property *p;
int ret;
if (root_node)
return -EBUSY;
nodeoffset = fdt_path_offset(fdt, "/"); nodeoffset = fdt_path_offset(fdt, "/");
if (nodeoffset < 0) { if (nodeoffset < 0) {
@ -853,16 +912,12 @@ int of_parse_dtb(struct fdt_header *fdt)
if (pathp == NULL) if (pathp == NULL)
pathp = "/* NULL pointer error */"; pathp = "/* NULL pointer error */";
ret = fdt_get_path(fdt, nodeoffset, buf, 1024); n = of_find_child(node, pathp);
if (ret) if (n) {
return -EINVAL; node = n;
} else {
node = new_device_node(node); node = of_new_node(node, pathp);
if (!node->parent) }
root_node = node;
node->full_name = xstrdup(buf);
node->name = xstrdup(pathp);
list_add_tail(&node->list, &allnodes);
break; break;
case FDT_END_NODE: case FDT_END_NODE:
node = node->parent; node = node->parent;
@ -874,7 +929,15 @@ int of_parse_dtb(struct fdt_header *fdt)
fdt32_to_cpu(fdt_prop->nameoff)); fdt32_to_cpu(fdt_prop->nameoff));
len = fdt32_to_cpu(fdt_prop->len); len = fdt32_to_cpu(fdt_prop->len);
nodep = fdt_prop->data; 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 {
of_new_property(node, pathp, nodep, len);
}
break; break;
case FDT_NOP: case FDT_NOP:
break; break;
@ -892,6 +955,71 @@ int of_parse_dtb(struct fdt_header *fdt)
return 0; 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) int of_device_is_stdout_path(struct device_d *dev)
{ {
struct device_node *dn; struct device_node *dn;

19
fs/fs.c
View File

@ -67,6 +67,25 @@ err_out:
EXPORT_SYMBOL(read_file); 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) char *mkmodestr(unsigned long mode, char *str)
{ {
static const char *l = "xwr"; static const char *l = "xwr";

View File

@ -166,6 +166,11 @@ char *mkmodestr(unsigned long mode, char *str);
*/ */
void *read_file(const char *filename, size_t *size); 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 * This function turns 'path' into an absolute path and removes all occurrences
* of "..", "." and double slashes. The returned string must be freed wit free(). * of "..", "." and double slashes. The returned string must be freed wit free().

View File

@ -5,11 +5,9 @@
#include <errno.h> #include <errno.h>
#include <asm/byteorder.h> #include <asm/byteorder.h>
extern struct fdt_header *barebox_fdt;
int fdt_print(struct fdt_header *working_fdt, const char *pathp); 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_fix_tree(struct fdt_header *fdt);
int of_register_fixup(int (*fixup)(struct fdt_header *)); int of_register_fixup(int (*fixup)(struct fdt_header *));
@ -107,6 +105,12 @@ int of_machine_is_compatible(const char *compat);
void of_print_nodes(struct device_node *node, int indent); void of_print_nodes(struct device_node *node, int indent);
int of_probe(void); int of_probe(void);
int of_parse_dtb(struct fdt_header *fdt); 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);
int of_property_read_string(struct device_node *np, const char *propname, int of_property_read_string(struct device_node *np, const char *propname,
const char **out_string); const char **out_string);
@ -119,6 +123,7 @@ struct device_node *of_get_root_node(void);
int of_alias_get_id(struct device_node *np, const char *stem); int of_alias_get_id(struct device_node *np, const char *stem);
int of_device_is_stdout_path(struct device_d *dev); int of_device_is_stdout_path(struct device_d *dev);
const char *of_get_model(void); const char *of_get_model(void);
void *of_flatten_dtb(void);
#else #else
static inline int of_parse_partitions(const char *cdevname, static inline int of_parse_partitions(const char *cdevname,
struct device_node *node) struct device_node *node)
@ -145,6 +150,11 @@ static inline const char *of_get_model(void)
{ {
return NULL; return NULL;
} }
static inline void *of_flatten_dtb(void)
{
return NULL;
}
#endif #endif
#endif /* __OF_H */ #endif /* __OF_H */