2 * Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation; either version 2 of
7 * the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
31 /* These are the operations we support */
33 OPER_WRITE_PROP, /* Write a property in a node */
34 OPER_CREATE_NODE, /* Create a new node */
35 OPER_REMOVE_NODE, /* Delete a node */
36 OPER_DELETE_PROP, /* Delete a property in a node */
40 enum oper_type oper; /* operation to perform */
41 int type; /* data type (s/i/u/x or 0 for default) */
42 int size; /* data size (1/2/4) */
43 int verbose; /* verbose output */
44 int auto_path; /* automatically create all path components */
49 * Report an error with a particular node.
51 * @param name Node name to report error on
52 * @param namelen Length of node name, or -1 to use entire string
53 * @param err Error number to report (-FDT_ERR_...)
55 static void report_error(const char *name, int namelen, int err)
58 namelen = strlen(name);
59 fprintf(stderr, "Error at '%1.*s': %s\n", namelen, name,
64 * Encode a series of arguments in a property value.
66 * @param disp Display information / options
67 * @param arg List of arguments from command line
68 * @param arg_count Number of arguments (may be 0)
69 * @param valuep Returns buffer containing value
70 * @param *value_len Returns length of value encoded
72 static int encode_value(struct display_info *disp, char **arg, int arg_count,
73 char **valuep, int *value_len)
75 char *value = NULL; /* holding area for value */
76 int value_size = 0; /* size of holding area */
77 char *ptr; /* pointer to current value position */
78 int len; /* length of this cell/string/byte */
80 int upto; /* the number of bytes we have written to buf */
86 fprintf(stderr, "Decoding value:\n");
89 fmt[1] = disp->type ? disp->type : 'd';
91 for (; arg_count > 0; arg++, arg_count--, upto += len) {
92 /* assume integer unless told otherwise */
93 if (disp->type == 's')
94 len = strlen(*arg) + 1;
96 len = disp->size == -1 ? 4 : disp->size;
98 /* enlarge our value buffer by a suitable margin if needed */
99 if (upto + len > value_size) {
100 value_size = (upto + len) + 500;
101 value = xrealloc(value, value_size);
105 if (disp->type == 's') {
106 memcpy(ptr, *arg, len);
108 fprintf(stderr, "\tstring: '%s'\n", ptr);
110 int *iptr = (int *)ptr;
111 sscanf(*arg, fmt, &ival);
113 *iptr = cpu_to_fdt32(ival);
115 *ptr = (uint8_t)ival;
117 fprintf(stderr, "\t%s: %d\n",
118 disp->size == 1 ? "byte" :
119 disp->size == 2 ? "short" : "int",
127 fprintf(stderr, "Value size %d\n", upto);
131 #define ALIGN(x) (((x) + (FDT_TAGSIZE) - 1) & ~((FDT_TAGSIZE) - 1))
133 static char *_realloc_fdt(char *fdt, int delta)
135 int new_sz = fdt_totalsize(fdt) + delta;
136 fdt = xrealloc(fdt, new_sz);
137 fdt_open_into(fdt, fdt, new_sz);
141 static char *realloc_node(char *fdt, const char *name)
144 /* FDT_BEGIN_NODE, node name in off_struct and FDT_END_NODE */
145 delta = sizeof(struct fdt_node_header) + ALIGN(strlen(name) + 1)
147 return _realloc_fdt(fdt, delta);
150 static char *realloc_property(char *fdt, int nodeoffset,
151 const char *name, int newlen)
156 if (!fdt_get_property(fdt, nodeoffset, name, &oldlen))
157 /* strings + property header */
158 delta = sizeof(struct fdt_property) + strlen(name) + 1;
161 /* actual value in off_struct */
162 delta += ALIGN(newlen) - ALIGN(oldlen);
164 return _realloc_fdt(fdt, delta);
167 static int store_key_value(char **blob, const char *node_name,
168 const char *property, const char *buf, int len)
173 node = fdt_path_offset(*blob, node_name);
175 report_error(node_name, -1, node);
179 err = fdt_setprop(*blob, node, property, buf, len);
180 if (err == -FDT_ERR_NOSPACE) {
181 *blob = realloc_property(*blob, node, property, len);
182 err = fdt_setprop(*blob, node, property, buf, len);
185 report_error(property, -1, err);
192 * Create paths as needed for all components of a path
194 * Any components of the path that do not exist are created. Errors are
197 * @param blob FDT blob to write into
198 * @param in_path Path to process
199 * @return 0 if ok, -1 on error
201 static int create_paths(char **blob, const char *in_path)
203 const char *path = in_path;
205 int node, offset = 0;
207 /* skip leading '/' */
211 for (sep = path; *sep; path = sep + 1, offset = node) {
212 /* equivalent to strchrnul(), but it requires _GNU_SOURCE */
213 sep = strchr(path, '/');
215 sep = path + strlen(path);
217 node = fdt_subnode_offset_namelen(*blob, offset, path,
219 if (node == -FDT_ERR_NOTFOUND) {
220 *blob = realloc_node(*blob, path);
221 node = fdt_add_subnode_namelen(*blob, offset, path,
225 report_error(path, sep - path, node);
234 * Create a new node in the fdt.
236 * This will overwrite the node_name string. Any error is reported.
238 * TODO: Perhaps create fdt_path_offset_namelen() so we don't need to do this.
240 * @param blob FDT blob to write into
241 * @param node_name Name of node to create
242 * @return new node offset if found, or -1 on failure
244 static int create_node(char **blob, const char *node_name)
249 p = strrchr(node_name, '/');
251 report_error(node_name, -1, -FDT_ERR_BADPATH);
256 *blob = realloc_node(*blob, p + 1);
259 node = fdt_path_offset(*blob, node_name);
261 report_error(node_name, -1, node);
266 node = fdt_add_subnode(*blob, node, p + 1);
268 report_error(p + 1, -1, node);
276 * Delete a property of a node in the fdt.
278 * @param blob FDT blob to write into
279 * @param node_name Path to node containing the property to delete
280 * @param prop_name Name of property to delete
281 * @return 0 on success, or -1 on failure
283 static int delete_prop(char *blob, const char *node_name, const char *prop_name)
287 node = fdt_path_offset(blob, node_name);
289 report_error(node_name, -1, node);
293 node = fdt_delprop(blob, node, prop_name);
295 report_error(node_name, -1, node);
303 * Delete a node in the fdt.
305 * @param blob FDT blob to write into
306 * @param node_name Name of node to delete
307 * @return 0 on success, or -1 on failure
309 static int delete_node(char *blob, const char *node_name)
313 node = fdt_path_offset(blob, node_name);
315 report_error(node_name, -1, node);
319 node = fdt_del_node(blob, node);
321 report_error(node_name, -1, node);
328 static int do_fdtput(struct display_info *disp, const char *filename,
329 char **arg, int arg_count)
336 blob = utilfdt_read(filename);
340 switch (disp->oper) {
341 case OPER_WRITE_PROP:
343 * Convert the arguments into a single binary value, then
344 * store them into the property.
346 assert(arg_count >= 2);
347 if (disp->auto_path && create_paths(&blob, *arg))
349 if (encode_value(disp, arg + 2, arg_count - 2, &value, &len) ||
350 store_key_value(&blob, *arg, arg[1], value, len))
353 case OPER_CREATE_NODE:
354 for (; ret >= 0 && arg_count--; arg++) {
356 ret = create_paths(&blob, *arg);
358 ret = create_node(&blob, *arg);
361 case OPER_REMOVE_NODE:
362 for (; ret >= 0 && arg_count--; arg++)
363 ret = delete_node(blob, *arg);
365 case OPER_DELETE_PROP:
367 for (arg++; ret >= 0 && arg_count-- > 1; arg++)
368 ret = delete_prop(blob, node, *arg);
373 ret = utilfdt_write(filename, blob);
385 /* Usage related data. */
386 static const char usage_synopsis[] =
387 "write a property value to a device tree\n"
388 " fdtput <options> <dt file> <node> <property> [<value>...]\n"
389 " fdtput -c <options> <dt file> [<node>...]\n"
390 " fdtput -r <options> <dt file> [<node>...]\n"
391 " fdtput -d <options> <dt file> <node> [<property>...]\n"
393 "The command line arguments are joined together into a single value.\n"
395 static const char usage_short_opts[] = "crdpt:v" USAGE_COMMON_SHORT_OPTS;
396 static struct option const usage_long_opts[] = {
397 {"create", no_argument, NULL, 'c'},
398 {"remove", no_argument, NULL, 'r'},
399 {"delete", no_argument, NULL, 'd'},
400 {"auto-path", no_argument, NULL, 'p'},
401 {"type", a_argument, NULL, 't'},
402 {"verbose", no_argument, NULL, 'v'},
403 USAGE_COMMON_LONG_OPTS,
405 static const char * const usage_opts_help[] = {
406 "Create nodes if they don't already exist",
407 "Delete nodes (and any subnodes) if they already exist",
408 "Delete properties if they already exist",
409 "Automatically create nodes as needed for the node path",
411 "Display each value decoded from command line",
412 USAGE_COMMON_OPTS_HELP
415 int main(int argc, char *argv[])
418 struct display_info disp;
419 char *filename = NULL;
421 memset(&disp, '\0', sizeof(disp));
423 disp.oper = OPER_WRITE_PROP;
424 while ((opt = util_getopt_long()) != EOF) {
426 * TODO: add options to:
428 * - pack fdt before writing
429 * - set amount of free space when writing
432 case_USAGE_COMMON_FLAGS
435 disp.oper = OPER_CREATE_NODE;
438 disp.oper = OPER_REMOVE_NODE;
441 disp.oper = OPER_DELETE_PROP;
447 if (utilfdt_decode_type(optarg, &disp.type,
449 usage("Invalid type string");
459 filename = argv[optind++];
461 usage("missing filename");
466 if (disp.oper == OPER_WRITE_PROP) {
468 usage("missing node");
470 usage("missing property");
473 if (disp.oper == OPER_DELETE_PROP)
475 usage("missing node");
477 if (do_fdtput(&disp, filename, argv, argc))