linux/scripts/dtc/fdtput.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
   3 *
   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.
   8 *
   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.
  13 *
  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,
  17 * MA 02111-1307 USA
  18 */
  19
  20#include <assert.h>
  21#include <ctype.h>
  22#include <getopt.h>
  23#include <stdio.h>
  24#include <stdlib.h>
  25#include <string.h>
  26
  27#include <libfdt.h>
  28
  29#include "util.h"
  30
  31/* These are the operations we support */
  32enum oper_type {
  33        OPER_WRITE_PROP,                /* Write a property in a node */
  34        OPER_CREATE_NODE,               /* Create a new node */
  35};
  36
  37struct display_info {
  38        enum oper_type oper;    /* operation to perform */
  39        int type;               /* data type (s/i/u/x or 0 for default) */
  40        int size;               /* data size (1/2/4) */
  41        int verbose;            /* verbose output */
  42        int auto_path;          /* automatically create all path components */
  43};
  44
  45
  46/**
  47 * Report an error with a particular node.
  48 *
  49 * @param name          Node name to report error on
  50 * @param namelen       Length of node name, or -1 to use entire string
  51 * @param err           Error number to report (-FDT_ERR_...)
  52 */
  53static void report_error(const char *name, int namelen, int err)
  54{
  55        if (namelen == -1)
  56                namelen = strlen(name);
  57        fprintf(stderr, "Error at '%1.*s': %s\n", namelen, name,
  58                fdt_strerror(err));
  59}
  60
  61/**
  62 * Encode a series of arguments in a property value.
  63 *
  64 * @param disp          Display information / options
  65 * @param arg           List of arguments from command line
  66 * @param arg_count     Number of arguments (may be 0)
  67 * @param valuep        Returns buffer containing value
  68 * @param *value_len    Returns length of value encoded
  69 */
  70static int encode_value(struct display_info *disp, char **arg, int arg_count,
  71                        char **valuep, int *value_len)
  72{
  73        char *value = NULL;     /* holding area for value */
  74        int value_size = 0;     /* size of holding area */
  75        char *ptr;              /* pointer to current value position */
  76        int len;                /* length of this cell/string/byte */
  77        int ival;
  78        int upto;       /* the number of bytes we have written to buf */
  79        char fmt[3];
  80
  81        upto = 0;
  82
  83        if (disp->verbose)
  84                fprintf(stderr, "Decoding value:\n");
  85
  86        fmt[0] = '%';
  87        fmt[1] = disp->type ? disp->type : 'd';
  88        fmt[2] = '\0';
  89        for (; arg_count > 0; arg++, arg_count--, upto += len) {
  90                /* assume integer unless told otherwise */
  91                if (disp->type == 's')
  92                        len = strlen(*arg) + 1;
  93                else
  94                        len = disp->size == -1 ? 4 : disp->size;
  95
  96                /* enlarge our value buffer by a suitable margin if needed */
  97                if (upto + len > value_size) {
  98                        value_size = (upto + len) + 500;
  99                        value = realloc(value, value_size);
 100                        if (!value) {
 101                                fprintf(stderr, "Out of mmory: cannot alloc "
 102                                        "%d bytes\n", value_size);
 103                                return -1;
 104                        }
 105                }
 106
 107                ptr = value + upto;
 108                if (disp->type == 's') {
 109                        memcpy(ptr, *arg, len);
 110                        if (disp->verbose)
 111                                fprintf(stderr, "\tstring: '%s'\n", ptr);
 112                } else {
 113                        int *iptr = (int *)ptr;
 114                        sscanf(*arg, fmt, &ival);
 115                        if (len == 4)
 116                                *iptr = cpu_to_fdt32(ival);
 117                        else
 118                                *ptr = (uint8_t)ival;
 119                        if (disp->verbose) {
 120                                fprintf(stderr, "\t%s: %d\n",
 121                                        disp->size == 1 ? "byte" :
 122                                        disp->size == 2 ? "short" : "int",
 123                                        ival);
 124                        }
 125                }
 126        }
 127        *value_len = upto;
 128        *valuep = value;
 129        if (disp->verbose)
 130                fprintf(stderr, "Value size %d\n", upto);
 131        return 0;
 132}
 133
 134static int store_key_value(void *blob, const char *node_name,
 135                const char *property, const char *buf, int len)
 136{
 137        int node;
 138        int err;
 139
 140        node = fdt_path_offset(blob, node_name);
 141        if (node < 0) {
 142                report_error(node_name, -1, node);
 143                return -1;
 144        }
 145
 146        err = fdt_setprop(blob, node, property, buf, len);
 147        if (err) {
 148                report_error(property, -1, err);
 149                return -1;
 150        }
 151        return 0;
 152}
 153
 154/**
 155 * Create paths as needed for all components of a path
 156 *
 157 * Any components of the path that do not exist are created. Errors are
 158 * reported.
 159 *
 160 * @param blob          FDT blob to write into
 161 * @param in_path       Path to process
 162 * @return 0 if ok, -1 on error
 163 */
 164static int create_paths(void *blob, const char *in_path)
 165{
 166        const char *path = in_path;
 167        const char *sep;
 168        int node, offset = 0;
 169
 170        /* skip leading '/' */
 171        while (*path == '/')
 172                path++;
 173
 174        for (sep = path; *sep; path = sep + 1, offset = node) {
 175                /* equivalent to strchrnul(), but it requires _GNU_SOURCE */
 176                sep = strchr(path, '/');
 177                if (!sep)
 178                        sep = path + strlen(path);
 179
 180                node = fdt_subnode_offset_namelen(blob, offset, path,
 181                                sep - path);
 182                if (node == -FDT_ERR_NOTFOUND) {
 183                        node = fdt_add_subnode_namelen(blob, offset, path,
 184                                                       sep - path);
 185                }
 186                if (node < 0) {
 187                        report_error(path, sep - path, node);
 188                        return -1;
 189                }
 190        }
 191
 192        return 0;
 193}
 194
 195/**
 196 * Create a new node in the fdt.
 197 *
 198 * This will overwrite the node_name string. Any error is reported.
 199 *
 200 * TODO: Perhaps create fdt_path_offset_namelen() so we don't need to do this.
 201 *
 202 * @param blob          FDT blob to write into
 203 * @param node_name     Name of node to create
 204 * @return new node offset if found, or -1 on failure
 205 */
 206static int create_node(void *blob, const char *node_name)
 207{
 208        int node = 0;
 209        char *p;
 210
 211        p = strrchr(node_name, '/');
 212        if (!p) {
 213                report_error(node_name, -1, -FDT_ERR_BADPATH);
 214                return -1;
 215        }
 216        *p = '\0';
 217
 218        if (p > node_name) {
 219                node = fdt_path_offset(blob, node_name);
 220                if (node < 0) {
 221                        report_error(node_name, -1, node);
 222                        return -1;
 223                }
 224        }
 225
 226        node = fdt_add_subnode(blob, node, p + 1);
 227        if (node < 0) {
 228                report_error(p + 1, -1, node);
 229                return -1;
 230        }
 231
 232        return 0;
 233}
 234
 235static int do_fdtput(struct display_info *disp, const char *filename,
 236                    char **arg, int arg_count)
 237{
 238        char *value;
 239        char *blob;
 240        int len, ret = 0;
 241
 242        blob = utilfdt_read(filename);
 243        if (!blob)
 244                return -1;
 245
 246        switch (disp->oper) {
 247        case OPER_WRITE_PROP:
 248                /*
 249                 * Convert the arguments into a single binary value, then
 250                 * store them into the property.
 251                 */
 252                assert(arg_count >= 2);
 253                if (disp->auto_path && create_paths(blob, *arg))
 254                        return -1;
 255                if (encode_value(disp, arg + 2, arg_count - 2, &value, &len) ||
 256                        store_key_value(blob, *arg, arg[1], value, len))
 257                        ret = -1;
 258                break;
 259        case OPER_CREATE_NODE:
 260                for (; ret >= 0 && arg_count--; arg++) {
 261                        if (disp->auto_path)
 262                                ret = create_paths(blob, *arg);
 263                        else
 264                                ret = create_node(blob, *arg);
 265                }
 266                break;
 267        }
 268        if (ret >= 0)
 269                ret = utilfdt_write(filename, blob);
 270
 271        free(blob);
 272        return ret;
 273}
 274
 275static const char *usage_msg =
 276        "fdtput - write a property value to a device tree\n"
 277        "\n"
 278        "The command line arguments are joined together into a single value.\n"
 279        "\n"
 280        "Usage:\n"
 281        "       fdtput <options> <dt file> <node> <property> [<value>...]\n"
 282        "       fdtput -c <options> <dt file> [<node>...]\n"
 283        "Options:\n"
 284        "\t-c\t\tCreate nodes if they don't already exist\n"
 285        "\t-p\t\tAutomatically create nodes as needed for the node path\n"
 286        "\t-t <type>\tType of data\n"
 287        "\t-v\t\tVerbose: display each value decoded from command line\n"
 288        "\t-h\t\tPrint this help\n\n"
 289        USAGE_TYPE_MSG;
 290
 291static void usage(const char *msg)
 292{
 293        if (msg)
 294                fprintf(stderr, "Error: %s\n\n", msg);
 295
 296        fprintf(stderr, "%s", usage_msg);
 297        exit(2);
 298}
 299
 300int main(int argc, char *argv[])
 301{
 302        struct display_info disp;
 303        char *filename = NULL;
 304
 305        memset(&disp, '\0', sizeof(disp));
 306        disp.size = -1;
 307        disp.oper = OPER_WRITE_PROP;
 308        for (;;) {
 309                int c = getopt(argc, argv, "chpt:v");
 310                if (c == -1)
 311                        break;
 312
 313                /*
 314                 * TODO: add options to:
 315                 * - delete property
 316                 * - delete node (optionally recursively)
 317                 * - rename node
 318                 * - pack fdt before writing
 319                 * - set amount of free space when writing
 320                 * - expand fdt if value doesn't fit
 321                 */
 322                switch (c) {
 323                case 'c':
 324                        disp.oper = OPER_CREATE_NODE;
 325                        break;
 326                case 'h':
 327                case '?':
 328                        usage(NULL);
 329                case 'p':
 330                        disp.auto_path = 1;
 331                        break;
 332                case 't':
 333                        if (utilfdt_decode_type(optarg, &disp.type,
 334                                        &disp.size))
 335                                usage("Invalid type string");
 336                        break;
 337
 338                case 'v':
 339                        disp.verbose = 1;
 340                        break;
 341                }
 342        }
 343
 344        if (optind < argc)
 345                filename = argv[optind++];
 346        if (!filename)
 347                usage("Missing filename");
 348
 349        argv += optind;
 350        argc -= optind;
 351
 352        if (disp.oper == OPER_WRITE_PROP) {
 353                if (argc < 1)
 354                        usage("Missing node");
 355                if (argc < 2)
 356                        usage("Missing property");
 357        }
 358
 359        if (do_fdtput(&disp, filename, argv, argc))
 360                return 1;
 361        return 0;
 362}
 363