aboutsummaryrefslogtreecommitdiff
path: root/modules/devices
diff options
context:
space:
mode:
authorBurt P <pburt0@gmail.com>2017-07-15 15:18:30 -0500
committerLeandro Pereira <leandro@hardinfo.org>2017-07-19 07:20:40 -0700
commit9f6a082af753af22b426dfa1b31e524998fe0dea (patch)
tree3d251833f62476a1eb79a9df35fbdd4e47909328 /modules/devices
parentae4750fb3f5f40522bcfadac2d13c28d7d3d7879 (diff)
Expand device tree support
The complete tree is now available to view. There are some bugs, mostly to do with hardinfo protocol quirks. Signed-off-by: Burt P <pburt0@gmail.com>
Diffstat (limited to 'modules/devices')
-rw-r--r--modules/devices/devicetree.c282
-rw-r--r--modules/devices/devicetree/rpi_data.c1
2 files changed, 255 insertions, 28 deletions
diff --git a/modules/devices/devicetree.c b/modules/devices/devicetree.c
index 76f57526..5f473d8e 100644
--- a/modules/devices/devicetree.c
+++ b/modules/devices/devicetree.c
@@ -16,52 +16,278 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
- * Device Tree support
+ * Device Tree support by Burt P. <pburt0@gmail.com>
*/
#include <unistd.h>
#include <sys/types.h>
#include "devices.h"
-static char *get_dt_string(char *p) {
- char fn[256];
- char *ret = NULL, *rep = NULL;
- snprintf(fn, 256, "/proc/device-tree/%s", p);
- g_file_get_contents(fn, &ret, NULL, NULL);
- if (ret) {
- while((rep = strchr(ret, '\n'))) *rep = ' ';
+enum {
+ DT_NODE,
+ DT_PROPERTY,
+};
+enum {
+ DTP_UNK,
+ DTP_STR,
+};
+
+typedef struct {
+ char *path;
+ int type;
+ unsigned long length;
+ void *data;
+} dt_raw;
+
+static struct {
+ char *name; int type;
+} prop_types[] = {
+ { "name", DTP_STR },
+ { "compatible", DTP_STR },
+ { "model", DTP_STR },
+ { "phandle", DTP_UNK },
+ { "reg", DTP_UNK },
+ { "#address-cells", DTP_UNK },
+ { "#size-cells", DTP_UNK },
+ { NULL, 0 },
+};
+
+static int dt_guess_type(dt_raw *prop) {
+ char *tmp, *slash;
+ int i = 0, anc = 0, might_be_str = 1;
+
+ /* lookup known type */
+ while (prop_types[i].name != NULL) {
+ slash = strrchr(prop->path, '/');
+ if (slash != NULL)
+ slash++;
+ else
+ slash = prop->path;
+ if (strcmp(slash, prop_types[i].name) == 0)
+ return prop_types[i].type;
+ i++;
+ }
+
+ /* maybe a string? */
+ for (i = 0; i < prop->length; i++) {
+ tmp = (char*)prop->data + i;
+ if ( isalnum(*tmp) ) anc++; /* count the alpha-nums */
+ if ( isprint(*tmp) || *tmp == 0 )
+ continue;
+ might_be_str = 0;
+ return DTP_UNK;
+ }
+ if (might_be_str &&
+ ( anc >= prop->length - 2 /* all alpha-nums but ^/ and \0$ */
+ || anc >= 5 ) /*arbitrary*/)
+ return DTP_STR;
+
+ return DTP_UNK;
+}
+
+static char* dt_str(dt_raw *prop) {
+ char *tmp, *next_str, *ret = NULL;
+ int i, l, tl;
+
+ if (prop == NULL) return NULL;
+
+ if (prop->type == DT_NODE)
+ ret = strdup("{node}");
+ else if (prop->data == NULL)
+ ret = strdup("{null}");
+ else if (prop->length == 0)
+ ret = strdup("{empty}");
+ else {
+ i = dt_guess_type(prop);
+ if (i == DTP_STR) {
+ /* treat as null-separated string list */
+ tl = 0;
+ ret = g_strdup("");
+ next_str = prop->data;
+ while(next_str != NULL) {
+ l = strlen(next_str);
+ tmp = g_strdup_printf("%s%s\"%s\"",
+ ret, strlen(ret) ? ", " : "", next_str);
+ g_free(ret);
+ ret = tmp;
+ tl += l + 1; next_str += l + 1;
+ if (tl >= prop->length) break;
+ }
+ } else {
+ ret = g_strdup_printf("{data} (%d bytes)", prop->length);
+ }
}
return ret;
}
+static dt_raw *get_dt_raw(char *p) {
+ gchar *full_path;
+ dt_raw *prop;
+ prop = malloc(sizeof(dt_raw));
+ if (prop != NULL) {
+ memset(prop, 0, sizeof(dt_raw));
+ full_path = g_strdup_printf("/proc/device-tree/%s", p);
+ prop->path = g_strdup(p);
+ if ( g_file_test(full_path, G_FILE_TEST_IS_DIR) ) {
+ prop->type = DT_NODE;
+ } else {
+ prop->type = DT_PROPERTY;
+ g_file_get_contents(full_path, (gchar**)&prop->data, (gsize*)&prop->length, NULL);
+ }
+ return prop;
+ }
+ return NULL;
+}
+
+void dt_raw_free(dt_raw *s) {
+ if (s != NULL) {
+ free(s->path);
+ free(s->data);
+ }
+ free(s);
+}
+
+static char *get_dt_string(char *p) {
+ dt_raw *prop;
+ char *ret, *rep;
+ prop = get_dt_raw(p);
+ if (prop != NULL) {
+ ret = g_strdup(prop->data);
+ if (ret) {
+ while((rep = strchr(ret, '\n'))) *rep = ' ';
+ }
+ dt_raw_free(prop);
+ return ret;
+ }
+ return NULL;
+}
+
#include "devicetree/rpi_data.c"
gchar *dtree_info = NULL;
-static void add_to_moreinfo(const char *group, const char *key, char *value)
-{
- char *new_key = g_strconcat("DTREE:", group, ":", key, NULL);
- moreinfo_add_with_prefix("DEV", new_key, g_strdup(g_strstrip(value)));
+gchar *get_node(char *np) {
+ gchar *nodes = NULL, *props = NULL, *ret = NULL;
+ gchar *tmp = NULL, *pstr = NULL;
+ gchar *dir_path = g_strdup_printf("/proc/device-tree/%s", np);
+ gchar *node_path;
+ const gchar *fn;
+ GDir *dir;
+ dt_raw *prop;
+
+ props = g_strdup_printf("[%s]\n", _("Properties") );
+ nodes = g_strdup_printf("[%s]\n", _("Children") );
+
+ dir = g_dir_open(dir_path, 0 , NULL);
+ if (dir) {
+ while((fn = g_dir_read_name(dir)) != NULL) {
+ node_path = g_strdup_printf("%s/%s", np, fn);
+ prop = get_dt_raw(node_path);
+ pstr = dt_str(prop);
+ if (prop->type == DT_NODE) {
+ tmp = g_strdup_printf("%s%s=%s\n",
+ nodes, fn, pstr);
+ g_free(nodes);
+ nodes = tmp;
+ } else if (prop->type == DT_PROPERTY) {
+ tmp = g_strdup_printf("%s%s=%s\n",
+ props, fn, pstr);
+ g_free(props);
+ props = tmp;
+ }
+ dt_raw_free(prop);
+ g_free(pstr);
+ g_free(node_path);
+ }
+ }
+ g_dir_close(dir);
+ g_free(dir_path);
+ ret = g_strdup_printf("[Node]\n"
+ "%s=%s\n"
+ "%s%s",
+ _("Node Path"), strcmp(np, "") ? np : "/",
+ props, nodes);
+ g_free(props);
+ g_free(nodes);
+ return ret;
}
-void __scan_dtree()
-{
- char *model = NULL, *serial = NULL, *special = NULL;
+gchar *get_summary() {
+ char *model = NULL, *serial = NULL, *ret = NULL;
model = get_dt_string("model");
serial = get_dt_string("serial-number");
+ /* Expand on the DT information from known machines, like RPi.
+ * RPi stores a revision value in /proc/cpuinfo that can be used
+ * to look up details. This is just a nice place to pull it all
+ * together for DT machines, with a nice fallback.
+ * PPC Macs could be handled this way too. They store
+ * machine identifiers in /proc/cpuinfo. */
if ( strstr(model, "Raspberry Pi") != NULL )
- special = rpi_board_details();
+ ret = rpi_board_details();
else
- special = "";
-
- dtree_info = g_strdup_printf(
- "[%s]\n"
- "%s=%s\n"
- "%s=%s\n"
- "%s",
- _("Device Tree"),
- _("Model"), model,
- _("Serial Number"), serial,
- special
- );
+ ret = g_strdup_printf(
+ "[%s]\n"
+ "%s=%s\n"
+ "%s=%s\n",
+ _("Board"),
+ _("Model"), model,
+ _("Serial Number"), serial);
+
+ free(model);
+ free(serial);
+ return ret;
+}
+
+void mi_add(const char *key, const char *value) {
+ gchar *rkey;
+ rkey = g_strdup_printf("%s:%s", "DTREE", key);
+
+ dtree_info = g_strdup_printf("%s$%s$%s=\n", dtree_info, rkey, key);
+ moreinfo_add_with_prefix("DEV", rkey, g_strdup(value));
+
+ g_free(rkey);
+}
+
+void add_keys(char *np) {
+ gchar *dir_path = g_strdup_printf("/proc/device-tree/%s", np);
+ gchar *ftmp, *ntmp, *ptmp;
+ gchar *n_name, *n_info;
+ const gchar *fn;
+ GDir *dir;
+
+ dir = g_dir_open(dir_path, 0 , NULL);
+ if (dir) {
+ while((fn = g_dir_read_name(dir)) != NULL) {
+ ftmp = g_strdup_printf("%s/%s", dir_path, fn);
+ if ( g_file_test(ftmp, G_FILE_TEST_IS_DIR) ) {
+ ntmp = g_strdup_printf("%s/%s", np, fn);
+ ptmp = g_strdup_printf("%s/name", ntmp, fn);
+ n_name = get_dt_string(ptmp);
+ n_info = get_node(ntmp);
+ mi_add(ntmp, n_info);
+ g_free(n_name);
+ g_free(n_info);
+ g_free(ptmp);
+
+ add_keys(ntmp);
+ g_free(ntmp);
+ }
+ g_free(ftmp);
+ }
+ }
+ g_dir_close(dir);
+}
+
+void __scan_dtree()
+{
+ gchar *summary = get_summary();
+ gchar *root_node = get_node("");
+
+ dtree_info = g_strdup("[Device Tree]\n");
+ mi_add("Summary", summary);
+
+ mi_add("/", root_node);
+ add_keys("");
+
+ //printf("%s\n", dtree_info);
}
diff --git a/modules/devices/devicetree/rpi_data.c b/modules/devices/devicetree/rpi_data.c
index 354423f0..83991d28 100644
--- a/modules/devices/devicetree/rpi_data.c
+++ b/modules/devices/devicetree/rpi_data.c
@@ -149,6 +149,7 @@ static gchar *rpi_board_details(void) {
_("PCB Revision"), rpi_boardinfo[i].pcb,
_("Introduction"), rpi_boardinfo[i].intro,
_("Manufacturer"), rpi_boardinfo[i].mfg,
+ _("RCode"), rpi_boardinfo[i].value,
_("SOC (spec)"), rpi_boardinfo[i].soc,
_("Memory (spec)"), rpi_boardinfo[i].mem,
_("Serial Number"), serial,