diff options
Diffstat (limited to 'qemu/dtc/fdtput.c')
-rw-r--r-- | qemu/dtc/fdtput.c | 401 |
1 files changed, 0 insertions, 401 deletions
diff --git a/qemu/dtc/fdtput.c b/qemu/dtc/fdtput.c deleted file mode 100644 index 5226a4efd..000000000 --- a/qemu/dtc/fdtput.c +++ /dev/null @@ -1,401 +0,0 @@ -/* - * Copyright (c) 2011 The Chromium OS Authors. All rights reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * 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. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, - * MA 02111-1307 USA - */ - -#include <assert.h> -#include <ctype.h> -#include <getopt.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - -#include <libfdt.h> - -#include "util.h" - -/* These are the operations we support */ -enum oper_type { - OPER_WRITE_PROP, /* Write a property in a node */ - OPER_CREATE_NODE, /* Create a new node */ -}; - -struct display_info { - enum oper_type oper; /* operation to perform */ - int type; /* data type (s/i/u/x or 0 for default) */ - int size; /* data size (1/2/4) */ - int verbose; /* verbose output */ - int auto_path; /* automatically create all path components */ -}; - - -/** - * Report an error with a particular node. - * - * @param name Node name to report error on - * @param namelen Length of node name, or -1 to use entire string - * @param err Error number to report (-FDT_ERR_...) - */ -static void report_error(const char *name, int namelen, int err) -{ - if (namelen == -1) - namelen = strlen(name); - fprintf(stderr, "Error at '%1.*s': %s\n", namelen, name, - fdt_strerror(err)); -} - -/** - * Encode a series of arguments in a property value. - * - * @param disp Display information / options - * @param arg List of arguments from command line - * @param arg_count Number of arguments (may be 0) - * @param valuep Returns buffer containing value - * @param *value_len Returns length of value encoded - */ -static int encode_value(struct display_info *disp, char **arg, int arg_count, - char **valuep, int *value_len) -{ - char *value = NULL; /* holding area for value */ - int value_size = 0; /* size of holding area */ - char *ptr; /* pointer to current value position */ - int len; /* length of this cell/string/byte */ - int ival; - int upto; /* the number of bytes we have written to buf */ - char fmt[3]; - - upto = 0; - - if (disp->verbose) - fprintf(stderr, "Decoding value:\n"); - - fmt[0] = '%'; - fmt[1] = disp->type ? disp->type : 'd'; - fmt[2] = '\0'; - for (; arg_count > 0; arg++, arg_count--, upto += len) { - /* assume integer unless told otherwise */ - if (disp->type == 's') - len = strlen(*arg) + 1; - else - len = disp->size == -1 ? 4 : disp->size; - - /* enlarge our value buffer by a suitable margin if needed */ - if (upto + len > value_size) { - value_size = (upto + len) + 500; - value = realloc(value, value_size); - if (!value) { - fprintf(stderr, "Out of mmory: cannot alloc " - "%d bytes\n", value_size); - return -1; - } - } - - ptr = value + upto; - if (disp->type == 's') { - memcpy(ptr, *arg, len); - if (disp->verbose) - fprintf(stderr, "\tstring: '%s'\n", ptr); - } else { - int *iptr = (int *)ptr; - sscanf(*arg, fmt, &ival); - if (len == 4) - *iptr = cpu_to_fdt32(ival); - else - *ptr = (uint8_t)ival; - if (disp->verbose) { - fprintf(stderr, "\t%s: %d\n", - disp->size == 1 ? "byte" : - disp->size == 2 ? "short" : "int", - ival); - } - } - } - *value_len = upto; - *valuep = value; - if (disp->verbose) - fprintf(stderr, "Value size %d\n", upto); - return 0; -} - -#define ALIGN(x) (((x) + (FDT_TAGSIZE) - 1) & ~((FDT_TAGSIZE) - 1)) - -static char *_realloc_fdt(char *fdt, int delta) -{ - int new_sz = fdt_totalsize(fdt) + delta; - fdt = xrealloc(fdt, new_sz); - fdt_open_into(fdt, fdt, new_sz); - return fdt; -} - -static char *realloc_node(char *fdt, const char *name) -{ - int delta; - /* FDT_BEGIN_NODE, node name in off_struct and FDT_END_NODE */ - delta = sizeof(struct fdt_node_header) + ALIGN(strlen(name) + 1) - + FDT_TAGSIZE; - return _realloc_fdt(fdt, delta); -} - -static char *realloc_property(char *fdt, int nodeoffset, - const char *name, int newlen) -{ - int delta = 0; - int oldlen = 0; - - if (!fdt_get_property(fdt, nodeoffset, name, &oldlen)) - /* strings + property header */ - delta = sizeof(struct fdt_property) + strlen(name) + 1; - - if (newlen > oldlen) - /* actual value in off_struct */ - delta += ALIGN(newlen) - ALIGN(oldlen); - - return _realloc_fdt(fdt, delta); -} - -static int store_key_value(char **blob, const char *node_name, - const char *property, const char *buf, int len) -{ - int node; - int err; - - node = fdt_path_offset(*blob, node_name); - if (node < 0) { - report_error(node_name, -1, node); - return -1; - } - - err = fdt_setprop(*blob, node, property, buf, len); - if (err == -FDT_ERR_NOSPACE) { - *blob = realloc_property(*blob, node, property, len); - err = fdt_setprop(*blob, node, property, buf, len); - } - if (err) { - report_error(property, -1, err); - return -1; - } - return 0; -} - -/** - * Create paths as needed for all components of a path - * - * Any components of the path that do not exist are created. Errors are - * reported. - * - * @param blob FDT blob to write into - * @param in_path Path to process - * @return 0 if ok, -1 on error - */ -static int create_paths(char **blob, const char *in_path) -{ - const char *path = in_path; - const char *sep; - int node, offset = 0; - - /* skip leading '/' */ - while (*path == '/') - path++; - - for (sep = path; *sep; path = sep + 1, offset = node) { - /* equivalent to strchrnul(), but it requires _GNU_SOURCE */ - sep = strchr(path, '/'); - if (!sep) - sep = path + strlen(path); - - node = fdt_subnode_offset_namelen(*blob, offset, path, - sep - path); - if (node == -FDT_ERR_NOTFOUND) { - *blob = realloc_node(*blob, path); - node = fdt_add_subnode_namelen(*blob, offset, path, - sep - path); - } - if (node < 0) { - report_error(path, sep - path, node); - return -1; - } - } - - return 0; -} - -/** - * Create a new node in the fdt. - * - * This will overwrite the node_name string. Any error is reported. - * - * TODO: Perhaps create fdt_path_offset_namelen() so we don't need to do this. - * - * @param blob FDT blob to write into - * @param node_name Name of node to create - * @return new node offset if found, or -1 on failure - */ -static int create_node(char **blob, const char *node_name) -{ - int node = 0; - char *p; - - p = strrchr(node_name, '/'); - if (!p) { - report_error(node_name, -1, -FDT_ERR_BADPATH); - return -1; - } - *p = '\0'; - - *blob = realloc_node(*blob, p + 1); - - if (p > node_name) { - node = fdt_path_offset(*blob, node_name); - if (node < 0) { - report_error(node_name, -1, node); - return -1; - } - } - - node = fdt_add_subnode(*blob, node, p + 1); - if (node < 0) { - report_error(p + 1, -1, node); - return -1; - } - - return 0; -} - -static int do_fdtput(struct display_info *disp, const char *filename, - char **arg, int arg_count) -{ - char *value; - char *blob; - int len, ret = 0; - - blob = utilfdt_read(filename); - if (!blob) - return -1; - - switch (disp->oper) { - case OPER_WRITE_PROP: - /* - * Convert the arguments into a single binary value, then - * store them into the property. - */ - assert(arg_count >= 2); - if (disp->auto_path && create_paths(&blob, *arg)) - return -1; - if (encode_value(disp, arg + 2, arg_count - 2, &value, &len) || - store_key_value(&blob, *arg, arg[1], value, len)) - ret = -1; - break; - case OPER_CREATE_NODE: - for (; ret >= 0 && arg_count--; arg++) { - if (disp->auto_path) - ret = create_paths(&blob, *arg); - else - ret = create_node(&blob, *arg); - } - break; - } - if (ret >= 0) { - fdt_pack(blob); - ret = utilfdt_write(filename, blob); - } - - free(blob); - return ret; -} - -/* Usage related data. */ -static const char usage_synopsis[] = - "write a property value to a device tree\n" - " fdtput <options> <dt file> <node> <property> [<value>...]\n" - " fdtput -c <options> <dt file> [<node>...]\n" - "\n" - "The command line arguments are joined together into a single value.\n" - USAGE_TYPE_MSG; -static const char usage_short_opts[] = "cpt:v" USAGE_COMMON_SHORT_OPTS; -static struct option const usage_long_opts[] = { - {"create", no_argument, NULL, 'c'}, - {"auto-path", no_argument, NULL, 'p'}, - {"type", a_argument, NULL, 't'}, - {"verbose", no_argument, NULL, 'v'}, - USAGE_COMMON_LONG_OPTS, -}; -static const char * const usage_opts_help[] = { - "Create nodes if they don't already exist", - "Automatically create nodes as needed for the node path", - "Type of data", - "Display each value decoded from command line", - USAGE_COMMON_OPTS_HELP -}; - -int main(int argc, char *argv[]) -{ - int opt; - struct display_info disp; - char *filename = NULL; - - memset(&disp, '\0', sizeof(disp)); - disp.size = -1; - disp.oper = OPER_WRITE_PROP; - while ((opt = util_getopt_long()) != EOF) { - /* - * TODO: add options to: - * - delete property - * - delete node (optionally recursively) - * - rename node - * - pack fdt before writing - * - set amount of free space when writing - */ - switch (opt) { - case_USAGE_COMMON_FLAGS - - case 'c': - disp.oper = OPER_CREATE_NODE; - break; - case 'p': - disp.auto_path = 1; - break; - case 't': - if (utilfdt_decode_type(optarg, &disp.type, - &disp.size)) - usage("Invalid type string"); - break; - - case 'v': - disp.verbose = 1; - break; - } - } - - if (optind < argc) - filename = argv[optind++]; - if (!filename) - usage("missing filename"); - - argv += optind; - argc -= optind; - - if (disp.oper == OPER_WRITE_PROP) { - if (argc < 1) - usage("missing node"); - if (argc < 2) - usage("missing property"); - } - - if (do_fdtput(&disp, filename, argv, argc)) - return 1; - return 0; -} |