0001
0002
0003
0004
0005
0006 #include <assert.h>
0007 #include <ctype.h>
0008 #include <getopt.h>
0009 #include <stdio.h>
0010 #include <stdlib.h>
0011 #include <string.h>
0012
0013 #include <libfdt.h>
0014
0015 #include "util.h"
0016
0017
0018 enum oper_type {
0019 OPER_WRITE_PROP,
0020 OPER_CREATE_NODE,
0021 };
0022
0023 struct display_info {
0024 enum oper_type oper;
0025 int type;
0026 int size;
0027 int verbose;
0028 int auto_path;
0029 };
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039 static void report_error(const char *name, int namelen, int err)
0040 {
0041 if (namelen == -1)
0042 namelen = strlen(name);
0043 fprintf(stderr, "Error at '%1.*s': %s\n", namelen, name,
0044 fdt_strerror(err));
0045 }
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056 static int encode_value(struct display_info *disp, char **arg, int arg_count,
0057 char **valuep, int *value_len)
0058 {
0059 char *value = NULL;
0060 int value_size = 0;
0061 char *ptr;
0062 int len;
0063 int ival;
0064 int upto;
0065 char fmt[3];
0066
0067 upto = 0;
0068
0069 if (disp->verbose)
0070 fprintf(stderr, "Decoding value:\n");
0071
0072 fmt[0] = '%';
0073 fmt[1] = disp->type ? disp->type : 'd';
0074 fmt[2] = '\0';
0075 for (; arg_count > 0; arg++, arg_count--, upto += len) {
0076
0077 if (disp->type == 's')
0078 len = strlen(*arg) + 1;
0079 else
0080 len = disp->size == -1 ? 4 : disp->size;
0081
0082
0083 if (upto + len > value_size) {
0084 value_size = (upto + len) + 500;
0085 value = realloc(value, value_size);
0086 if (!value) {
0087 fprintf(stderr, "Out of mmory: cannot alloc "
0088 "%d bytes\n", value_size);
0089 return -1;
0090 }
0091 }
0092
0093 ptr = value + upto;
0094 if (disp->type == 's') {
0095 memcpy(ptr, *arg, len);
0096 if (disp->verbose)
0097 fprintf(stderr, "\tstring: '%s'\n", ptr);
0098 } else {
0099 int *iptr = (int *)ptr;
0100 sscanf(*arg, fmt, &ival);
0101 if (len == 4)
0102 *iptr = cpu_to_fdt32(ival);
0103 else
0104 *ptr = (uint8_t)ival;
0105 if (disp->verbose) {
0106 fprintf(stderr, "\t%s: %d\n",
0107 disp->size == 1 ? "byte" :
0108 disp->size == 2 ? "short" : "int",
0109 ival);
0110 }
0111 }
0112 }
0113 *value_len = upto;
0114 *valuep = value;
0115 if (disp->verbose)
0116 fprintf(stderr, "Value size %d\n", upto);
0117 return 0;
0118 }
0119
0120 static int store_key_value(void *blob, const char *node_name,
0121 const char *property, const char *buf, int len)
0122 {
0123 int node;
0124 int err;
0125
0126 node = fdt_path_offset(blob, node_name);
0127 if (node < 0) {
0128 report_error(node_name, -1, node);
0129 return -1;
0130 }
0131
0132 err = fdt_setprop(blob, node, property, buf, len);
0133 if (err) {
0134 report_error(property, -1, err);
0135 return -1;
0136 }
0137 return 0;
0138 }
0139
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149
0150 static int create_paths(void *blob, const char *in_path)
0151 {
0152 const char *path = in_path;
0153 const char *sep;
0154 int node, offset = 0;
0155
0156
0157 while (*path == '/')
0158 path++;
0159
0160 for (sep = path; *sep; path = sep + 1, offset = node) {
0161
0162 sep = strchr(path, '/');
0163 if (!sep)
0164 sep = path + strlen(path);
0165
0166 node = fdt_subnode_offset_namelen(blob, offset, path,
0167 sep - path);
0168 if (node == -FDT_ERR_NOTFOUND) {
0169 node = fdt_add_subnode_namelen(blob, offset, path,
0170 sep - path);
0171 }
0172 if (node < 0) {
0173 report_error(path, sep - path, node);
0174 return -1;
0175 }
0176 }
0177
0178 return 0;
0179 }
0180
0181
0182
0183
0184
0185
0186
0187
0188
0189
0190
0191
0192 static int create_node(void *blob, const char *node_name)
0193 {
0194 int node = 0;
0195 char *p;
0196
0197 p = strrchr(node_name, '/');
0198 if (!p) {
0199 report_error(node_name, -1, -FDT_ERR_BADPATH);
0200 return -1;
0201 }
0202 *p = '\0';
0203
0204 if (p > node_name) {
0205 node = fdt_path_offset(blob, node_name);
0206 if (node < 0) {
0207 report_error(node_name, -1, node);
0208 return -1;
0209 }
0210 }
0211
0212 node = fdt_add_subnode(blob, node, p + 1);
0213 if (node < 0) {
0214 report_error(p + 1, -1, node);
0215 return -1;
0216 }
0217
0218 return 0;
0219 }
0220
0221 static int do_fdtput(struct display_info *disp, const char *filename,
0222 char **arg, int arg_count)
0223 {
0224 char *value;
0225 char *blob;
0226 int len, ret = 0;
0227
0228 blob = utilfdt_read(filename);
0229 if (!blob)
0230 return -1;
0231
0232 switch (disp->oper) {
0233 case OPER_WRITE_PROP:
0234
0235
0236
0237
0238 assert(arg_count >= 2);
0239 if (disp->auto_path && create_paths(blob, *arg))
0240 return -1;
0241 if (encode_value(disp, arg + 2, arg_count - 2, &value, &len) ||
0242 store_key_value(blob, *arg, arg[1], value, len))
0243 ret = -1;
0244 break;
0245 case OPER_CREATE_NODE:
0246 for (; ret >= 0 && arg_count--; arg++) {
0247 if (disp->auto_path)
0248 ret = create_paths(blob, *arg);
0249 else
0250 ret = create_node(blob, *arg);
0251 }
0252 break;
0253 }
0254 if (ret >= 0)
0255 ret = utilfdt_write(filename, blob);
0256
0257 free(blob);
0258 return ret;
0259 }
0260
0261 static const char *usage_msg =
0262 "fdtput - write a property value to a device tree\n"
0263 "\n"
0264 "The command line arguments are joined together into a single value.\n"
0265 "\n"
0266 "Usage:\n"
0267 " fdtput <options> <dt file> <node> <property> [<value>...]\n"
0268 " fdtput -c <options> <dt file> [<node>...]\n"
0269 "Options:\n"
0270 "\t-c\t\tCreate nodes if they don't already exist\n"
0271 "\t-p\t\tAutomatically create nodes as needed for the node path\n"
0272 "\t-t <type>\tType of data\n"
0273 "\t-v\t\tVerbose: display each value decoded from command line\n"
0274 "\t-h\t\tPrint this help\n\n"
0275 USAGE_TYPE_MSG;
0276
0277 static void usage(const char *msg)
0278 {
0279 if (msg)
0280 fprintf(stderr, "Error: %s\n\n", msg);
0281
0282 fprintf(stderr, "%s", usage_msg);
0283 exit(2);
0284 }
0285
0286 int main(int argc, char *argv[])
0287 {
0288 struct display_info disp;
0289 char *filename = NULL;
0290
0291 memset(&disp, '\0', sizeof(disp));
0292 disp.size = -1;
0293 disp.oper = OPER_WRITE_PROP;
0294 for (;;) {
0295 int c = getopt(argc, argv, "chpt:v");
0296 if (c == -1)
0297 break;
0298
0299
0300
0301
0302
0303
0304
0305
0306
0307
0308 switch (c) {
0309 case 'c':
0310 disp.oper = OPER_CREATE_NODE;
0311 break;
0312 case 'h':
0313 case '?':
0314 usage(NULL);
0315 case 'p':
0316 disp.auto_path = 1;
0317 break;
0318 case 't':
0319 if (utilfdt_decode_type(optarg, &disp.type,
0320 &disp.size))
0321 usage("Invalid type string");
0322 break;
0323
0324 case 'v':
0325 disp.verbose = 1;
0326 break;
0327 }
0328 }
0329
0330 if (optind < argc)
0331 filename = argv[optind++];
0332 if (!filename)
0333 usage("Missing filename");
0334
0335 argv += optind;
0336 argc -= optind;
0337
0338 if (disp.oper == OPER_WRITE_PROP) {
0339 if (argc < 1)
0340 usage("Missing node");
0341 if (argc < 2)
0342 usage("Missing property");
0343 }
0344
0345 if (do_fdtput(&disp, filename, argv, argc))
0346 return 1;
0347 return 0;
0348 }