diff options
Diffstat (limited to 'modules/devices')
| -rw-r--r-- | modules/devices/devicetree.c | 282 | ||||
| -rw-r--r-- | modules/devices/devicetree/rpi_data.c | 1 | 
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, | 
