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
fdt32_t *iptr = (fdt32_t *)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))