^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Portions from U-Boot cmd_fdt.c (C) Copyright 2007
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Gerald Van Baren, Custom IDEAS, vanbaren@cideas.com
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Based on code written by:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * Pantelis Antoniou <pantelis.antoniou@gmail.com> and
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * Matthew McClintock <msm@freescale.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <assert.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <ctype.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <getopt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <stdio.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <stdlib.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <libfdt.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include "util.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) enum display_mode {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) MODE_SHOW_VALUE, /* show values for node properties */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) MODE_LIST_PROPS, /* list the properties for a node */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) MODE_LIST_SUBNODES, /* list the subnodes of a node */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) /* Holds information which controls our output and options */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) struct display_info {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) int type; /* data type (s/i/u/x or 0 for default) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) int size; /* data size (1/2/4) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) enum display_mode mode; /* display mode that we are using */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) const char *default_val; /* default value if node/property not found */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) static void report_error(const char *where, int err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) fprintf(stderr, "Error at '%s': %s\n", where, fdt_strerror(err));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) * Displays data of a given length according to selected options
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) * If a specific data type is provided in disp, then this is used. Otherwise
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) * we try to guess the data type / size from the contents.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) * @param disp Display information / options
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) * @param data Data to display
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) * @param len Maximum length of buffer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) * @return 0 if ok, -1 if data does not match format
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) static int show_data(struct display_info *disp, const char *data, int len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) int i, size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) const uint8_t *p = (const uint8_t *)data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) const char *s;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) int value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) int is_string;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) char fmt[3];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) /* no data, don't print */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) if (len == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) is_string = (disp->type) == 's' ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) (!disp->type && util_is_printable_string(data, len));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) if (is_string) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) if (data[len - 1] != '\0') {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) fprintf(stderr, "Unterminated string\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) for (s = data; s - data < len; s += strlen(s) + 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) if (s != data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) printf(" ");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) printf("%s", (const char *)s);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) size = disp->size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) if (size == -1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) size = (len % 4) == 0 ? 4 : 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) } else if (len % size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) fprintf(stderr, "Property length must be a multiple of "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) "selected data size\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) fmt[0] = '%';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) fmt[1] = disp->type ? disp->type : 'd';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) fmt[2] = '\0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) for (i = 0; i < len; i += size, p += size) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) if (i)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) printf(" ");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) value = size == 4 ? fdt32_to_cpu(*(const uint32_t *)p) :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) size == 2 ? (*p << 8) | p[1] : *p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) printf(fmt, value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) * List all properties in a node, one per line.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) * @param blob FDT blob
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) * @param node Node to display
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) * @return 0 if ok, or FDT_ERR... if not.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) static int list_properties(const void *blob, int node)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) const struct fdt_property *data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) const char *name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) int prop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) prop = fdt_first_property_offset(blob, node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) do {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) /* Stop silently when there are no more properties */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) if (prop < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) return prop == -FDT_ERR_NOTFOUND ? 0 : prop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) data = fdt_get_property_by_offset(blob, prop, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) name = fdt_string(blob, fdt32_to_cpu(data->nameoff));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) if (name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) puts(name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) prop = fdt_next_property_offset(blob, prop);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) } while (1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) #define MAX_LEVEL 32 /* how deeply nested we will go */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) * List all subnodes in a node, one per line
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) * @param blob FDT blob
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) * @param node Node to display
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) * @return 0 if ok, or FDT_ERR... if not.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) static int list_subnodes(const void *blob, int node)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) int nextoffset; /* next node offset from libfdt */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) uint32_t tag; /* current tag */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) int level = 0; /* keep track of nesting level */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) const char *pathp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) int depth = 1; /* the assumed depth of this node */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) while (level >= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) tag = fdt_next_tag(blob, node, &nextoffset);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) switch (tag) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) case FDT_BEGIN_NODE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) pathp = fdt_get_name(blob, node, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) if (level <= depth) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) if (pathp == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) pathp = "/* NULL pointer error */";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) if (*pathp == '\0')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) pathp = "/"; /* root is nameless */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) if (level == 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) puts(pathp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) level++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) if (level >= MAX_LEVEL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) printf("Nested too deep, aborting.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) case FDT_END_NODE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) level--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) if (level == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) level = -1; /* exit the loop */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) case FDT_END:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) case FDT_PROP:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) if (level <= depth)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) printf("Unknown tag 0x%08X\n", tag);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) node = nextoffset;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) * Show the data for a given node (and perhaps property) according to the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) * display option provided.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) * @param blob FDT blob
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) * @param disp Display information / options
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) * @param node Node to display
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) * @param property Name of property to display, or NULL if none
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) * @return 0 if ok, -ve on error
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) static int show_data_for_item(const void *blob, struct display_info *disp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) int node, const char *property)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) const void *value = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) int len, err = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) switch (disp->mode) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) case MODE_LIST_PROPS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) err = list_properties(blob, node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) case MODE_LIST_SUBNODES:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) err = list_subnodes(blob, node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) assert(property);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) value = fdt_getprop(blob, node, property, &len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) if (value) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) if (show_data(disp, value, len))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) err = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) printf("\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) } else if (disp->default_val) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) puts(disp->default_val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) report_error(property, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) err = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) * Run the main fdtget operation, given a filename and valid arguments
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) * @param disp Display information / options
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) * @param filename Filename of blob file
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) * @param arg List of arguments to process
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) * @param arg_count Number of arguments
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) * @param return 0 if ok, -ve on error
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) static int do_fdtget(struct display_info *disp, const char *filename,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) char **arg, int arg_count, int args_per_step)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) char *blob;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) const char *prop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) int i, node;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) blob = utilfdt_read(filename);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) if (!blob)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) for (i = 0; i + args_per_step <= arg_count; i += args_per_step) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) node = fdt_path_offset(blob, arg[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) if (node < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) if (disp->default_val) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) puts(disp->default_val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) report_error(arg[i], node);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) prop = args_per_step == 1 ? NULL : arg[i + 1];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) if (show_data_for_item(blob, disp, node, prop))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) static const char *usage_msg =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) "fdtget - read values from device tree\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) "\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) "Each value is printed on a new line.\n\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) "Usage:\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) " fdtget <options> <dt file> [<node> <property>]...\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) " fdtget -p <options> <dt file> [<node> ]...\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) "Options:\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) "\t-t <type>\tType of data\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) "\t-p\t\tList properties for each node\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) "\t-l\t\tList subnodes for each node\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) "\t-d\t\tDefault value to display when the property is "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) "missing\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) "\t-h\t\tPrint this help\n\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) USAGE_TYPE_MSG;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) static void usage(const char *msg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) if (msg)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) fprintf(stderr, "Error: %s\n\n", msg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) fprintf(stderr, "%s", usage_msg);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) exit(2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) int main(int argc, char *argv[])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) char *filename = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) struct display_info disp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) int args_per_step = 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) /* set defaults */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) memset(&disp, '\0', sizeof(disp));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) disp.size = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) disp.mode = MODE_SHOW_VALUE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) for (;;) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) int c = getopt(argc, argv, "d:hlpt:");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) if (c == -1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) switch (c) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) case 'h':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) case '?':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) usage(NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) case 't':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) if (utilfdt_decode_type(optarg, &disp.type,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) &disp.size))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) usage("Invalid type string");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) case 'p':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) disp.mode = MODE_LIST_PROPS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) args_per_step = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) case 'l':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) disp.mode = MODE_LIST_SUBNODES;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) args_per_step = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) case 'd':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) disp.default_val = optarg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) if (optind < argc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) filename = argv[optind++];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) if (!filename)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) usage("Missing filename");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) argv += optind;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) argc -= optind;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) /* Allow no arguments, and silently succeed */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) if (!argc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) /* Check for node, property arguments */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) if (args_per_step == 2 && (argc % 2))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) usage("Must have an even number of arguments");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) if (do_fdtget(&disp, filename, argv, argc, args_per_step))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) }