diff options
Diffstat (limited to 'modules/devices/devicetree.c')
| -rw-r--r-- | modules/devices/devicetree.c | 643 | 
1 files changed, 51 insertions, 592 deletions
| diff --git a/modules/devices/devicetree.c b/modules/devices/devicetree.c index 6c2a6071..b3a9d621 100644 --- a/modules/devices/devicetree.c +++ b/modules/devices/devicetree.c @@ -24,56 +24,8 @@  #include <unistd.h>  #include <sys/types.h>  #include <stdint.h> -#include <endian.h>  #include "devices.h" - -/* some not-quite-working stuff that can be disabled */ -#define DTEX_INH_PROPS 0 -#define DTEX_PHREFS 0 -#define DTEX_GROUP_TUPS 0 - -enum { -    DT_NODE, -    DT_PROPERTY, -}; -enum { -    DTP_UNK, -    DTP_STR, /* null-delimited list of strings */ -    DTP_INT, -    DTP_UINT, -    DTP_HEX, /* list of 32-bit values displayed in hex */ -    DTP_PH,  /* phandle */ -    DTP_PH_REF,  /* reference to phandle */ -}; - -typedef struct { -    char *path; -    char *name; -    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 }, -    { "reg", DTP_HEX }, -    { "clocks", DTP_HEX }, -    { "gpios", DTP_HEX }, -    { "phandle", DTP_PH }, -    { "interrupts", DTP_HEX }, -    { "interrupt-parent", DTP_PH_REF }, -    { "regulator-min-microvolt", DTP_UINT }, -    { "regulator-max-microvolt", DTP_UINT }, -    { "clock-frequency", DTP_UINT }, -    { NULL, 0 }, -}; - -static dt_raw *get_dt_raw(char *); -static void dt_raw_free(dt_raw *); +#include "dt_util.h"  /* Hardinfo labels that have # are truncated and/or hidden.   * Labels can't have $ because that is the delimiter in @@ -131,575 +83,84 @@ gchar *hardinfo_clean_value(const gchar *v, int replacing) {      return clean;  } -struct _dt_phandle { -    uint32_t v; -    char *path; -    struct _dt_phandle *next; -}; -typedef struct _dt_phandle dt_phandle; - -dt_phandle *phandles = NULL; - -dt_phandle *dt_phandle_add(uint32_t v, const char *path) { -    dt_phandle *phi = phandles; -    dt_phandle *ph = malloc(sizeof(dt_phandle)); -    memset(ph, 0, sizeof(dt_phandle)); -    ph->v = v; ph->path = strdup(path); -    if (phi == NULL) { -        phandles = ph; -    } else { -        while(phi->next != NULL) phi = phi->next; -        phi->next = ph; -    } -    return ph; -} - -void dt_phandle_free(dt_phandle *ph) { -    if (ph) { -        free(ph->path); -    } -    free(ph); -} - -void dt_phandles_free() { -    dt_phandle *phi; -    while(phandles != NULL) { -        phi = phandles->next; -        dt_phandle_free(phandles); -        phandles = phi; -    } -    phandles = NULL; -} - -char *dt_phandle_lookup(uint32_t v) { -    dt_phandle *phi = phandles; -    while(phi != NULL) { -        if (phi->v == v) -            return phi->path; -        phi = phi->next; -    } -    return NULL; -} - -struct _dt_alias { -    char *label; -    char *path; -    struct _dt_alias *next; -}; -typedef struct _dt_alias dt_alias; - -dt_alias *aliases; - -dt_alias *dt_alias_add(const char *label, const char *path) { -    dt_alias *ali = aliases; -    dt_alias *al = malloc(sizeof(dt_alias)); -    memset(al, 0, sizeof(dt_alias)); -    al->label = strdup(label); al->path = strdup(path); -    if (ali == NULL) { -        aliases = al; -    } else { -        while(ali->next != NULL) ali = ali->next; -        ali->next = al; -    } -    return al; -} - -void dt_alias_free(dt_alias *al) { -    if (al) { -        free(al->label); -        free(al->path); -    } -    free(al); -} -void dt_aliases_free() { -    dt_alias *ali; -    while(aliases != NULL) { -        ali = aliases->next; -        dt_alias_free(aliases); -        aliases = ali; -    } -    aliases = NULL; -} - -char *dt_alias_lookup_by_path(const char* path) { -    dt_alias *ali = aliases; -    while(ali != NULL) { -        if (strcmp(ali->path, path) == 0) -            return ali->label; -        ali = ali->next; -    } -    return NULL; -} - -void dt_map_phandles(char *np) { -    gchar *dir_path; -    gchar *ftmp, *ntmp, *ptmp; -    const gchar *fn; -    GDir *dir; -    dt_raw *prop, *ph_prop; -    uint32_t phandle; - -    if (np == NULL) np = ""; -    dir_path = g_strdup_printf("/proc/device-tree/%s", np); - -    prop = get_dt_raw(np); -    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/phandle", ntmp); -                ph_prop = get_dt_raw(ptmp); -                if (ph_prop != NULL) { -                    phandle = be32toh(*(uint32_t*)ph_prop->data); -                    dt_phandle_add(phandle, ntmp); -                } -                dt_map_phandles(ntmp); -                g_free(ptmp); -                g_free(ntmp); -                dt_raw_free(ph_prop); -            } -            g_free(ftmp); -        } -    } -    g_dir_close(dir); -    dt_raw_free(prop); -} - -void dt_read_aliases() { -    gchar *dir_path = g_strdup_printf("/proc/device-tree/aliases"); -    gchar *ftmp, *ntmp, *ptmp; -    const gchar *fn; -    GDir *dir; -    dt_raw *prop; - -    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) ) -                continue; - -            ntmp = g_strdup_printf("aliases/%s", fn); -            prop = get_dt_raw(ntmp); -            dt_alias_add(prop->name, (char*)prop->data); -            g_free(ntmp); -            g_free(ftmp); -        } -    } -    g_dir_close(dir); -} - -#define DT_CHECK_NAME(prop, nm) (strcmp(prop->name, nm) == 0) - -/*cstd*/ -static int dt_guess_type(dt_raw *prop) { -    char *tmp, *dash; -    int i = 0, anc = 0, might_be_str = 1; - -    /* special #(.*)-cells names are UINT */ -    if (*prop->name == '#') { -        dash = strrchr(prop->name, '-'); -        if (dash != NULL) { -            if (strcmp(dash, "-cells") == 0) -                return DTP_UINT; -        } -    } - -    /* lookup known type */ -    while (prop_types[i].name != NULL) { -        if (strcmp(prop->name, 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; -        break; -    } -    if (might_be_str && -        ( anc >= prop->length - 2 /* all alpha-nums but ^/ and \0$ */ -          || anc >= 5 ) /*arbitrary*/) -        return DTP_STR; - -    if (!(prop->length % 4)) /* multiple of 4 bytes, try list of hex values */ -        return DTP_HEX; - -    return DTP_UNK; -} - -/*cstd*/ -static char* dt_hex_list(uint32_t *list, unsigned long count, unsigned long tup_len) { -    char *ret, *dest; -    char buff[15] = "";  /* max element: ">, <0x00000000\0" */ -    unsigned long i, l, tc; -    l = count * 15 + 1; -    dest = ret = malloc(l); -    memset(ret, 0, l); -    if (tup_len) { -        strcpy(dest, "<"); -        dest++; -    } -    tc = 0; -    for (i = 0; i < count; i++) { -        if (tup_len) { -            if (tc == tup_len) { -                sprintf(buff, ">, <0x%x", be32toh(list[i])); -                tc = 1; -            } else { -                sprintf(buff, "%s0x%x", (i) ? " " : "", be32toh(list[i])); -                tc++; -            } -        } else -            sprintf(buff, "%s0x%x", (i) ? " " : "", be32toh(list[i])); -        l = strlen(buff); -        strncpy(dest, buff, l); -        dest += l; -    } -    if (tup_len) -        strcpy(dest, ">"); -    return ret; -} - -/*cstd*/ -static char* dt_byte_list(uint8_t *bytes, unsigned long count) { -    char *ret, *dest; -    char buff[4] = "";  /* max element: " 00\0" */ -    uint32_t v; -    unsigned long i, l; -    l = count * 4 + 1; -    ret = malloc(l); -    memset(ret, 0, l); -    strcpy(ret, "["); -    dest = ret + 1; -    for (i = 0; i < count; i++) { -        v = bytes[i]; -        sprintf(buff, "%s%02x", (i) ? " " : "", v); -        l = strlen(buff); -        strncpy(dest, buff, l); -        dest += l; -    } -    strcpy(dest, "]"); -    return ret; -} - -struct { -    const char *name; -    uint32_t def_value; -} inherited_props[] = { -    { "#address-cells", 1 }, -    { "#size-cells",    0 }, -    { "#clock-cells",   1 }, -    { "#gpio-cells",    1 }, -    { NULL, 0 }, -}; -#define INHERITED_PROPS_N 5  /* including term null */ -/* requires an un-used int i */ -#define INHERITED_PROPS_I(pnm) \ -    { i = 0; while (inherited_props[i].name != NULL) { if (strcmp(inherited_props[i].name, pnm) == 0) break; i++; } } - -/* find an inherited property by climbing the path */ -/*cstd*/ -static uint32_t dt_inh_find(dt_raw *prop, const char *inh_prop) { -    char *slash, *tmp, *parent; -    char buff[1024] = ""; -    dt_raw *tprop; -    uint32_t ret = 0; -    int found = 0, i; - -    if (prop == NULL) -        return 0; - -    parent = strdup(prop->path); -    while ( slash = strrchr(parent, '/') ) { -        *slash = 0; -        sprintf(buff, "%s/%s", parent, inh_prop); -        tprop = get_dt_raw(buff); -        if (tprop != NULL) { -            ret = be32toh(*(uint32_t*)tprop->data); -            dt_raw_free(tprop); -            found = 1; -            break; -        } -    } - -    if (!found) { -        INHERITED_PROPS_I(inh_prop); /* sets i */ -        ret = inherited_props[i].def_value; -    } - -    free(parent); -    return ret; -} - -/*cstd*/ -static int dt_tup_len(dt_raw *prop) { -    uint32_t address_cells, size_cells, -        clock_cells, gpio_cells; - -#if !(DTEX_GROUP_TUPS) -    return 0; -#endif - -    if (prop == NULL) -        return 0; - -    if DT_CHECK_NAME(prop, "reg") { -        address_cells = dt_inh_find(prop, "#address-cells"); -        size_cells = dt_inh_find(prop, "#size-cells"); -        return address_cells + size_cells; -    } - -    if DT_CHECK_NAME(prop, "gpios") { -        gpio_cells = dt_inh_find(prop, "#gpio-cells"); -        if (gpio_cells == 0) gpio_cells = 1; -        return gpio_cells; -    } - -    if DT_CHECK_NAME(prop, "clocks") { -        clock_cells = dt_inh_find(prop, "#clock-cells"); -        return 1 + clock_cells; -    } - -    return 0; -} - -/*cstd, except for g_strescape()*/ -static char* dt_str(dt_raw *prop) { -    char *tmp, *esc, *next_str; -    char ret[1024] = ""; -    unsigned long i, l, tl; -    uint32_t phandle; -    char *ph_path, *al_label; - -    if (prop == NULL) return NULL; - -    if (prop->type == DT_NODE) -        strcpy(ret, "{node}"); -    else if (prop->data == NULL) -        strcpy(ret, "{null}"); -    else if (prop->length == 0) -        strcpy(ret, "{empty}"); -    else { -        i = dt_guess_type(prop); - -#if !(DTEX_PHREFS) -        if (i == DTP_PH_REF) i = DTP_HEX; -#endif - -        if (i == DTP_STR) { -            /* treat as null-separated string list */ -            tl = 0; -            strcpy(ret, ""); -            tmp = ret; -            next_str = prop->data; -            while(next_str != NULL) { -                l = strlen(next_str); -                esc = g_strescape(next_str, NULL); -                sprintf(tmp, "%s\"%s\"", -                        strlen(ret) ? ", " : "", esc); -                free(esc); -                tmp += strlen(tmp); -                tl += l + 1; next_str += l + 1; -                if (tl >= prop->length) break; -            } -        } else if (i == DTP_INT && prop->length == 4) { -            /* still use uint32_t for the byte-order conversion */ -            sprintf(ret, "%d", be32toh(*(uint32_t*)prop->data) ); -        } else if (i == DTP_UINT && prop->length == 4) { -            sprintf(ret, "%u", be32toh(*(uint32_t*)prop->data) ); -        } else if (i == DTP_HEX && !(prop->length % 4)) { -            l = prop->length / 4; -            tmp = dt_hex_list((uint32_t*)prop->data, l, dt_tup_len(prop)); -            strcpy(ret, tmp); -            free(tmp); -        } else if (i == DTP_PH && prop->length == 4) { -            phandle = be32toh(*(uint32_t*)prop->data); -            ph_path = dt_phandle_lookup(phandle); -            al_label = dt_alias_lookup_by_path(ph_path); -            if (al_label != NULL) -                sprintf(ret, "0x%x (&%s)", phandle, al_label); -            else -                sprintf(ret, "0x%x", phandle); -        } else if (i == DTP_PH_REF && prop->length == 4) { -            phandle = be32toh(*(uint32_t*)prop->data); -            ph_path = dt_phandle_lookup(phandle); -            if (ph_path != NULL) { -                al_label = dt_alias_lookup_by_path(ph_path); -                if (al_label != NULL) -                    sprintf(ret, "&%s (%s)", al_label, ph_path); -                else -                    sprintf(ret, "0x%x (%s)", phandle, ph_path); -            } else -                sprintf(ret, "<0x%x>", phandle); -        } else { -            if (prop->length > 64) { /* maybe should use #define at the top */ -                sprintf(ret, "{data} (%lu bytes)", prop->length); -            } else { -                tmp = dt_byte_list((uint8_t*)prop->data, prop->length); -                strcpy(ret, tmp); -                free(tmp); -            } -        } -    } -    return strdup(ret); -} - -/*glib, but dt_raw *prop uses malloc() and std types */ -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 = strdup( p != NULL && strcmp(p, "") ? p : "/" ); -        if ( g_file_test(full_path, G_FILE_TEST_IS_DIR) ) { -            prop->type = DT_NODE; -        } else { -            prop->type = DT_PROPERTY; -            if (!g_file_get_contents(full_path, (gchar**)&prop->data, (gsize*)&prop->length, NULL)) { -                dt_raw_free(prop); -                return NULL; -            } -        } - -        /* find name after last slash, or start */ -        char *slash = strrchr(prop->path, '/'); -        if (slash != NULL) -            prop->name = strdup(slash + 1); -        else -            prop->name = strdup(prop->path); - -        return prop; -    } -    return NULL; -} - -/*cstd*/ -void dt_raw_free(dt_raw *s) { -    if (s != NULL) { -        free(s->path); -        free(s->name); -        free(s->data); -    } -    free(s); -} - -/*cstd*/ -static char *get_dt_string(char *p, int decode) { -    dt_raw *prop; -    char *ret, *rep; -    prop = get_dt_raw(p); -    if (prop != NULL) { -        if (decode) -            ret = dt_str(prop); -        else { -            ret = strdup(prop->data); -            if (ret) -                while((rep = strchr(ret, '\n'))) *rep = ' '; -        } -        dt_raw_free(prop); -        return ret; -    } -    return NULL; -} -  #include "devicetree/rpi_data.c" +dtr *dt;  gchar *dtree_info = NULL;  gchar *get_node(char *np) { -    gchar *nodes = NULL, *props = NULL, *inh_props = NULL, *ret = NULL; +    gchar *nodes = NULL, *props = NULL, *ret = NULL;      gchar *tmp = NULL, *pstr = NULL, *lstr = NULL; -    gchar *dir_path = g_strdup_printf("/proc/device-tree/%s", np); +    gchar *dir_path;      gchar *node_path;      const gchar *fn;      GDir *dir; -    dt_raw *prop; -    int inh[INHERITED_PROPS_N]; -    memset(inh, 0, sizeof(int) * INHERITED_PROPS_N); -    int i; -    uint32_t v; +    dtr_obj *node, *child;      props = g_strdup_printf("[%s]\n", _("Properties") ); -    inh_props = g_strdup_printf("[%s]\n", _("Inherited Properties") );      nodes = g_strdup_printf("[%s]\n", _("Children") ); +    node = dtr_obj_read(dt, np); +    dir_path = dtr_obj_full_path(node);      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 = hardinfo_clean_value(dt_str(prop), 1); +            child = dtr_get_prop_obj(dt, node, fn); +            pstr = hardinfo_clean_value(dtr_str(dt, child), 1);              lstr = hardinfo_clean_label(fn, 0); -            INHERITED_PROPS_I(prop->name); inh[i] = 1; -            if (prop->type == DT_NODE) { +            if (dtr_obj_type(child) == DT_NODE) {                  tmp = g_strdup_printf("%s%s=%s\n",                      nodes, lstr, pstr);                  g_free(nodes);                  nodes = tmp; -            } else if (prop->type == DT_PROPERTY) { +            } else {                  tmp = g_strdup_printf("%s%s=%s\n",                      props, lstr, pstr);                  g_free(props);                  props = tmp;              } -            dt_raw_free(prop); +            dtr_obj_free(child);              g_free(pstr);              g_free(lstr); -            g_free(node_path);          }      }      g_dir_close(dir);      g_free(dir_path); -    prop = get_dt_raw(np); -    for (i = 0; i < INHERITED_PROPS_N - 1; i++) -        if (!inh[i]) { -            v = dt_inh_find(prop, inherited_props[i].name); -            pstr = g_strdup_printf("%u", v); -            lstr = hardinfo_clean_label(inherited_props[i].name, 0); -            tmp = g_strdup_printf("%s%s=%s\n", -                inh_props, lstr, pstr); -            g_free(inh_props); -            inh_props = tmp; -            g_free(pstr); -            g_free(lstr); -        } - -#if !(DTEX_INH_PROPS) -    g_free(inh_props); inh_props = g_strdup(""); -#endif - -    lstr = dt_alias_lookup_by_path(prop->path); +    lstr = dtr_obj_alias(node);      ret = g_strdup_printf("[%s]\n"                      "%s=%s\n"                      "%s=%s\n" -                    "%s%s%s", +                    "%s%s",                      _("Node"), -                    _("Node Path"), prop->path, +                    _("Node Path"), dtr_obj_path(node),                      _("Alias"), (lstr != NULL) ? lstr : _("(None)"), -                    props, inh_props, nodes); +                    props, nodes); -    dt_raw_free(prop); +    dtr_obj_free(node);      g_free(props); -    g_free(inh_props);      g_free(nodes);      return ret;  } +char *get_dt_string(char *path, int decode) { +    dtr_obj *obj; +    char *ret = NULL; +    if (decode) { +        obj = dtr_get_prop_obj(dt, NULL, path); +        ret = dtr_str(dt, obj); +        dtr_obj_free(obj); +    } else +        ret = dtr_get_prop_str(dt, NULL, path); +    return ret; +} +  gchar *get_summary() {      char *model = NULL, *serial = NULL, *compat = NULL, *ret = NULL; -    model = get_dt_string("model", 0); -    serial = get_dt_string("serial-number", 0); -    compat = get_dt_string("compatible", 1); + +    model = get_dt_string("/model", 0); +    serial = get_dt_string("/serial-number", 0); +    compat = get_dt_string("/compatible", 1);      /* Expand on the DT information from known machines, like RPi.       * RPi stores a revision value in /proc/cpuinfo that can be used @@ -741,26 +202,29 @@ void mi_add(const char *key, const char *value) {  }  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; +    gchar *dir_path, *dt_path; +    gchar *ftmp, *ntmp; +    gchar *n_info;      const gchar *fn;      GDir *dir; +    dtr_obj *obj; +    /* add self */ +    obj = dtr_obj_read(dt, np); +    dt_path = dtr_obj_path(obj); +    n_info = get_node(dt_path); +    mi_add(dt_path, n_info); + +    dir_path = g_strdup_printf("%s/%s", dtr_base_path(dt), np);      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); -                n_name = get_dt_string(ptmp, 0); -                n_info = get_node(ntmp); -                mi_add(ntmp, n_info); -                g_free(n_name); -                g_free(n_info); -                g_free(ptmp); - +                if (strcmp(np, "/") == 0) +                    ntmp = g_strdup_printf("/%s", fn); +                else +                    ntmp = g_strdup_printf("%s/%s", np, fn);                  add_keys(ntmp);                  g_free(ntmp);              } @@ -772,19 +236,14 @@ void add_keys(char *np) {  void __scan_dtree()  { +    dt = dtr_new(NULL);      gchar *summary = get_summary(); -    gchar *root_node = get_node(""); - -    dt_read_aliases(); -    dt_map_phandles(NULL);      dtree_info = g_strdup("[Device Tree]\n");      mi_add("Summary", summary); -    mi_add("/", root_node); -    add_keys(""); +    add_keys("/");      //printf("%s\n", dtree_info); -    dt_aliases_free(); -    dt_phandles_free(); +    dtr_free(dt);  } | 
