diff options
| author | Simon Quigley <tsimonq2@ubuntu.com> | 2017-08-16 04:32:39 -0500 | 
|---|---|---|
| committer | Simon Quigley <tsimonq2@ubuntu.com> | 2017-08-16 04:32:39 -0500 | 
| commit | 82306ca849c0710209e5a39754f446d0335a276d (patch) | |
| tree | 8d297400e5c36357b9147401631e653e035283d3 /modules/devices | |
| parent | 21a53faf18b01a65a341115000e97d70b37c750c (diff) | |
| parent | 9a9db98089717990cd5e0eef529f6bb0819ebe46 (diff) | |
Updated version 0.5.1+git20170815 from 'upstream/0.5.1+git20170815'
with Debian dir 36bf8e7e43d9f6621a63c79a597af2f4f76271b7
Diffstat (limited to 'modules/devices')
31 files changed, 4548 insertions, 1314 deletions
| diff --git a/modules/devices/alpha/processor.c b/modules/devices/alpha/processor.c index f55526f7..c7862232 100644 --- a/modules/devices/alpha/processor.c +++ b/modules/devices/alpha/processor.c @@ -18,6 +18,7 @@  #include "hardinfo.h"  #include "devices.h" +#include "cpu_util.h"  GSList *  processor_scan(void) @@ -25,54 +26,69 @@ processor_scan(void)      Processor *processor;      FILE *cpuinfo;      gchar buffer[128]; +    long long hz = 0; -    cpuinfo = fopen("/proc/cpuinfo", "r"); +    cpuinfo = fopen(PROC_CPUINFO, "r");      if (!cpuinfo) -	return NULL; +        return NULL;      processor = g_new0(Processor, 1);      while (fgets(buffer, 128, cpuinfo)) { -	gchar **tmp = g_strsplit(buffer, ":", 2); +        gchar **tmp = g_strsplit(buffer, ":", 2); -	if (tmp[0] && tmp[1]) { -	    tmp[0] = g_strstrip(tmp[0]); -	    tmp[1] = g_strstrip(tmp[1]); +        if (tmp[0] && tmp[1]) { +            tmp[0] = g_strstrip(tmp[0]); +            tmp[1] = g_strstrip(tmp[1]); -	    get_str("cpu model", processor->model_name); -	    get_float("BogoMIPS", processor->bogomips); -	    get_str("platform string", processor->strmodel); +            get_str("cpu model", processor->model_name); +            get_float("BogoMIPS", processor->bogomips); +            get_str("platform string", processor->strmodel); +            get_str("cycle frequency [Hz]", processor->cycle_frequency_hz_str); -	} -	g_strfreev(tmp); +        } +        g_strfreev(tmp);      } -     + +    fclose(cpuinfo); +      gchar *tmp = g_strconcat("Alpha ", processor->model_name, NULL);      g_free(processor->model_name);      processor->model_name = tmp; -    processor->cpu_mhz = 0.0f; -    fclose(cpuinfo); +    if (processor->cycle_frequency_hz_str) { +        hz = atoll(processor->cycle_frequency_hz_str); +        processor->cpu_mhz = hz; +        processor->cpu_mhz /= 1000000; +    } else +        processor->cpu_mhz = 0.0f;      return g_slist_append(NULL, processor);  } +gchar *processor_name(GSList * processors) { +    return processor_name_default(processors); +} + +gchar *processor_describe(GSList * processors) { +    return processor_describe_default(processors); +} +  gchar *  processor_get_info(GSList *processors)  { -        Processor *processor = (Processor *)processors->data; +    Processor *processor = (Processor *)processors->data; -	return g_strdup_printf("[Processor]\n" -                               "Model=%s\n" -	                       "Platform String=%s\n" -	                       "BogoMIPS=%.2f" -	                       "Byte Order=%s\n", -			       processor->model_name, -			       processor->strmodel, -			       processor->bogomips, -#if G_BYTE_ORDER == G_LITTLE_ENDIAN -                               "Little Endian" -#else -                               "Big Endian" -#endif -                              ); +    return g_strdup_printf("[%s]\n" +                        "%s=%s\n" +                        "%s=%s\n" +                        "%s=%.2f %s\n" /* frequency */ +                        "%s=%.2f\n"    /* bogomips */ +                        "%s=%s\n",     /* byte order */ +                    _("Processor"), +                    _("Model"), processor->model_name, +                    _("Platform String"), processor->strmodel, +                    _("Frequency"), processor->cpu_mhz, _("MHz"), +                    _("BogoMips"), processor->bogomips, +                    _("Byte Order"), byte_order_str() +                    );  } diff --git a/modules/devices/arm/arm_data.c b/modules/devices/arm/arm_data.c index 2e2cbe60..60e8ea34 100644 --- a/modules/devices/arm/arm_data.c +++ b/modules/devices/arm/arm_data.c @@ -23,6 +23,13 @@  #include <string.h>  #include "arm_data.h" +#ifndef C_ +#define C_(Ctx, String) String +#endif +#ifndef NC_ +#define NC_(Ctx, String) String +#endif +  /* sources:   *   https://unix.stackexchange.com/a/43563   *   git:linux/arch/arm/kernel/setup.c @@ -32,47 +39,46 @@ static struct {      char *name, *meaning;  } tab_flag_meaning[] = {      /* arm/hw_cap */ -    { "swp",	"SWP instruction (atomic read-modify-write)" }, -    { "half",	"Half-word loads and stores" }, -    { "thumb",	"Thumb (16-bit instruction set)" }, -    { "26bit",	"26-Bit Model (Processor status register folded into program counter)" }, -    { "fastmult",	"32x32->64-bit multiplication" }, -    { "fpa",	"Floating point accelerator" }, -    { "vfp",	"VFP (early SIMD vector floating point instructions)" }, -    { "edsp",	"DSP extensions (the 'e' variant of the ARM9 CPUs, and all others above)" }, -    { "java",	"Jazelle (Java bytecode accelerator)" }, -    { "iwmmxt",	"SIMD instructions similar to Intel MMX" }, -    { "crunch",	"MaverickCrunch coprocessor (if kernel support enabled)" }, -    { "thumbee",	"ThumbEE" }, -    { "neon",	"Advanced SIMD/NEON on AArch32" }, -    { "evtstrm",	"kernel event stream using generic architected timer" }, -    { "vfpv3",	"VFP version 3" }, -    { "vfpv3d16",	"VFP version 3 with 16 D-registers" }, -    { "vfpv4",	"VFP version 4 with fast context switching" }, -    { "vfpd32",	"VFP with 32 D-registers" }, -    { "tls",	"TLS register" }, -    { "idiva",	"SDIV and UDIV hardware division in ARM mode" }, -    { "idivt",	"SDIV and UDIV hardware division in Thumb mode" }, -    { "lpae",	"40-bit Large Physical Address Extension" }, +    { "swp",      NC_("arm-flag", /*/flag:swp*/      "SWP instruction (atomic read-modify-write)") }, +    { "half",     NC_("arm-flag", /*/flag:half*/     "Half-word loads and stores") }, +    { "thumb",    NC_("arm-flag", /*/flag:thumb*/    "Thumb (16-bit instruction set)") }, +    { "26bit",    NC_("arm-flag", /*/flag:26bit*/    "26-Bit Model (Processor status register folded into program counter)") }, +    { "fastmult", NC_("arm-flag", /*/flag:fastmult*/ "32x32->64-bit multiplication") }, +    { "fpa",      NC_("arm-flag", /*/flag:fpa*/      "Floating point accelerator") }, +    { "vfp",      NC_("arm-flag", /*/flag:vfp*/      "VFP (early SIMD vector floating point instructions)") }, +    { "edsp",     NC_("arm-flag", /*/flag:edsp*/     "DSP extensions (the 'e' variant of the ARM9 CPUs, and all others above)") }, +    { "java",     NC_("arm-flag", /*/flag:java*/     "Jazelle (Java bytecode accelerator)") }, +    { "iwmmxt",   NC_("arm-flag", /*/flag:iwmmxt*/   "SIMD instructions similar to Intel MMX") }, +    { "crunch",   NC_("arm-flag", /*/flag:crunch*/   "MaverickCrunch coprocessor (if kernel support enabled)") }, +    { "thumbee",  NC_("arm-flag", /*/flag:thumbee*/  "ThumbEE") }, +    { "neon",     NC_("arm-flag", /*/flag:neon*/     "Advanced SIMD/NEON on AArch32") }, +    { "evtstrm",  NC_("arm-flag", /*/flag:evtstrm*/  "Kernel event stream using generic architected timer") }, +    { "vfpv3",    NC_("arm-flag", /*/flag:vfpv3*/    "VFP version 3") }, +    { "vfpv3d16", NC_("arm-flag", /*/flag:vfpv3d16*/ "VFP version 3 with 16 D-registers") }, +    { "vfpv4",    NC_("arm-flag", /*/flag:vfpv4*/    "VFP version 4 with fast context switching") }, +    { "vfpd32",   NC_("arm-flag", /*/flag:vfpd32*/   "VFP with 32 D-registers") }, +    { "tls",      NC_("arm-flag", /*/flag:tls*/      "TLS register") }, +    { "idiva",    NC_("arm-flag", /*/flag:idiva*/    "SDIV and UDIV hardware division in ARM mode") }, +    { "idivt",    NC_("arm-flag", /*/flag:idivt*/    "SDIV and UDIV hardware division in Thumb mode") }, +    { "lpae",     NC_("arm-flag", /*/flag:lpae*/     "40-bit Large Physical Address Extension") },      /* arm/hw_cap2 */ -    { "pmull",	"64x64->128-bit F2m multiplication (arch>8)" }, -    { "aes",	"Crypto:AES (arch>8)" }, -    { "sha1",	"Crypto:SHA1 (arch>8)" }, -    { "sha2",	"Crypto:SHA2 (arch>8)" }, -    { "crc32",	"CRC32 checksum instructions (arch>8)" }, +    { "pmull",    NC_("arm-flag", /*/flag:pmull*/    "64x64->128-bit F2m multiplication (arch>8)") }, +    { "aes",      NC_("arm-flag", /*/flag:aes*/      "Crypto:AES (arch>8)") }, +    { "sha1",     NC_("arm-flag", /*/flag:sha1*/     "Crypto:SHA1 (arch>8)") }, +    { "sha2",     NC_("arm-flag", /*/flag:sha2*/     "Crypto:SHA2 (arch>8)") }, +    { "crc32",    NC_("arm-flag", /*/flag:crc32*/    "CRC32 checksum instructions (arch>8)") },      /* arm64/hw_cap */ -    { "fp",	"" }, -    { "asimd",	"Advanced SIMD/NEON on AArch64 (arch>8)" }, -    { "atomics",	"" }, -    { "fphp",	"" }, -    { "asimdhp",	"" }, -    { "cpuid",	"" }, -    { "asimdrdm",	"" }, -    { "jscvt",	"" }, -    { "fcma",	"" }, -    { "lrcpc",	"" }, - -    { NULL, NULL}, +    { "fp",       NULL }, +    { "asimd",    NC_("arm-flag", /*/flag:asimd*/    "Advanced SIMD/NEON on AArch64 (arch>8)") }, +    { "atomics",  NULL }, +    { "fphp",     NULL }, +    { "asimdhp",  NULL }, +    { "cpuid",    NULL }, +    { "asimdrdm", NULL }, +    { "jscvt",    NULL }, +    { "fcma",     NULL }, +    { "lrcpc",    NULL }, +    { NULL, NULL }  };  static struct { @@ -108,9 +114,11 @@ static struct {      /*d */ { 0xd01,	"Cortex-A32" },      /*dt*/ { 0xd03,	"Cortex-A53" },      /*d */ { 0xd04,	"Cortex-A35" }, +    /*d */ { 0xd05,	"Cortex-A55" },      /*d */ { 0xd07,	"Cortex-A57 MPCore" },      /*d */ { 0xd08,	"Cortex-A72" },      /*d */ { 0xd09,	"Cortex-A73" }, +    /*d */ { 0xd0a,	"Cortex-A75" },             { 0, NULL},  }; @@ -143,8 +151,11 @@ const char *arm_flag_meaning(const char *flag) {      int i = 0;      if (flag)      while(tab_flag_meaning[i].name != NULL) { -        if (strcmp(tab_flag_meaning[i].name, flag) == 0) -            return tab_flag_meaning[i].meaning; +        if (strcmp(tab_flag_meaning[i].name, flag) == 0) { +            if (tab_flag_meaning[i].meaning != NULL) +                return C_("arm-flag", tab_flag_meaning[i].meaning); +            else return NULL; +        }          i++;      }      return NULL; @@ -220,7 +231,7 @@ char *arm_decoded_name(const char *imp, const char *part, const char *var, const              p = strtol(rev, NULL, 0);              imp_name = (char*) arm_implementer(imp);              part_desc = (char*) arm_part(imp, part); -            arch_name = (char *) arm_arch(arch); +            arch_name = (char*) arm_arch(arch);              if (imp_name || part_desc) {                  if (arch_name != arch)                      sprintf(dnbuff, "%s %s r%dp%d (%s)", diff --git a/modules/devices/arm/processor.c b/modules/devices/arm/processor.c index ad7adf7f..e9446229 100644 --- a/modules/devices/arm/processor.c +++ b/modules/devices/arm/processor.c @@ -18,6 +18,8 @@  #include "hardinfo.h"  #include "devices.h" +#include "cpu_util.h" +#include "dt_util.h"  #include "arm_data.h"  #include "arm_data.c" @@ -34,34 +36,6 @@ static const gchar *arm_mode_str[] = {      "A32 on A64",  }; -static gint get_cpu_int(const gchar* file, gint cpuid) { -    gchar *tmp0 = NULL; -    gchar *tmp1 = NULL; -    gint ret = 0; - -    tmp0 = g_strdup_printf("/sys/devices/system/cpu/cpu%d/%s", cpuid, file); -    g_file_get_contents(tmp0, &tmp1, NULL, NULL); -    if (tmp1) -        ret = atol(tmp1); -    g_free(tmp0); -    g_free(tmp1); -    return ret; -} - -int processor_has_flag(gchar * strflags, gchar * strflag) -{ -    gchar **flags; -    gint ret = 0; -    if (strflags == NULL || strflag == NULL) -        return 0; -    flags = g_strsplit(strflags, " ", 0); -    ret = g_strv_contains((const gchar * const *)flags, strflag); -    g_strfreev(flags); -    return ret; -} - -#define PROC_CPUINFO "/proc/cpuinfo" -  GSList *  processor_scan(void)  { @@ -70,7 +44,6 @@ processor_scan(void)      FILE *cpuinfo;      gchar buffer[128];      gchar *rep_pname = NULL; -    gchar *tmpfreq_str = NULL;      GSList *pi = NULL;      cpuinfo = fopen(PROC_CPUINFO, "r"); @@ -101,7 +74,7 @@ processor_scan(void)              processor->id = atol(tmp[1]);              if (rep_pname) -                processor->model_name = g_strdup(rep_pname); +                processor->linux_name = g_strdup(rep_pname);              g_strfreev(tmp);              continue; @@ -117,11 +90,11 @@ processor_scan(void)              processor->id = 0;              if (rep_pname) -                processor->model_name = g_strdup(rep_pname); +                processor->linux_name = g_strdup(rep_pname);          }          if (processor) { -            get_str("model name", processor->model_name); +            get_str("model name", processor->linux_name);              get_str("Features", processor->flags);              get_float("BogoMIPS", processor->bogomips); @@ -166,29 +139,26 @@ processor_scan(void)          processor = (Processor *) pi->data;          /* strings can't be null or segfault later */ -#define STRIFNULL(f,cs) if (processor->f == NULL) processor->f = g_strdup(cs); -#define UNKIFNULL(f) STRIFNULL(f, "(Unknown)") -#define EMPIFNULL(f) STRIFNULL(f, "") -        STRIFNULL(model_name, "ARM Processor"); -        EMPIFNULL(flags); -        UNKIFNULL(cpu_implementer); -        UNKIFNULL(cpu_architecture); -        UNKIFNULL(cpu_variant); -        UNKIFNULL(cpu_part); -        UNKIFNULL(cpu_revision); - -        processor->decoded_name = arm_decoded_name( +        STRIFNULL(processor->linux_name, _("ARM Processor") ); +        EMPIFNULL(processor->flags); +        UNKIFNULL(processor->cpu_implementer); +        UNKIFNULL(processor->cpu_architecture); +        UNKIFNULL(processor->cpu_variant); +        UNKIFNULL(processor->cpu_part); +        UNKIFNULL(processor->cpu_revision); + +        processor->model_name = arm_decoded_name(              processor->cpu_implementer, processor->cpu_part,              processor->cpu_variant, processor->cpu_revision, -            processor->cpu_architecture, processor->model_name); -        UNKIFNULL(decoded_name); - -        /* freq */ -        processor->cpukhz_cur = get_cpu_int("cpufreq/scaling_cur_freq", processor->id); -        processor->cpukhz_min = get_cpu_int("cpufreq/scaling_min_freq", processor->id); -        processor->cpukhz_max = get_cpu_int("cpufreq/scaling_max_freq", processor->id); -        if (processor->cpukhz_max) -            processor->cpu_mhz = processor->cpukhz_max / 1000; +            processor->cpu_architecture, processor->linux_name); +        UNKIFNULL(processor->model_name); + +        /* topo & freq */ +        processor->cpufreq = cpufreq_new(processor->id); +        processor->cputopo = cputopo_new(processor->id); + +        if (processor->cpufreq->cpukhz_max) +            processor->cpu_mhz = processor->cpufreq->cpukhz_max / 1000;          else              processor->cpu_mhz = 0.0f; @@ -236,78 +206,168 @@ gchar *processor_get_capabilities_from_flags(gchar * strflags)  gchar *  processor_get_detailed_info(Processor *processor)  { -    gchar *tmp_flags, *tmp_imp, *tmp_part, *tmp_arch, *ret; +    gchar *tmp_flags, *tmp_imp, *tmp_part, *tmp_arch, *tmp_cpufreq, *tmp_topology, *ret;      tmp_flags = processor_get_capabilities_from_flags(processor->flags);      tmp_imp = (char*)arm_implementer(processor->cpu_implementer);      tmp_part = (char*)arm_part(processor->cpu_implementer, processor->cpu_part);      tmp_arch = (char*)arm_arch_more(processor->cpu_architecture); -    ret = g_strdup_printf("[Processor]\n" -                           "Linux Name=%s\n" -                           "Decoded Name=%s\n" -                           "Mode=%s\n" -                   "BogoMips=%.2f\n" -                   "Endianesss=" -#if G_BYTE_ORDER == G_LITTLE_ENDIAN -                       "Little Endian" -#else -                       "Big Endian" -#endif -                       "\n" -                       "[Frequency Scaling]\n" -                       "Minimum=%d kHz\n" -                       "Maximum=%d kHz\n" -                       "Current=%d kHz\n" -                       "[ARM]\n" -                       "Implementer=[%s] %s\n" -                       "Part=[%s] %s\n" -                       "Architecture=[%s] %s\n" -                       "Variant=%s\n" -                       "Revision=%s\n" -                       "[Capabilities]\n" +    tmp_topology = cputopo_section_str(processor->cputopo); +    tmp_cpufreq = cpufreq_section_str(processor->cpufreq); + +    ret = g_strdup_printf("[%s]\n" +                       "%s=%s\n"       /* linux name */ +                       "%s=%s\n"       /* decoded name */ +                       "%s=%s\n"       /* mode */ +                       "%s=%.2f %s\n"  /* frequency */ +                       "%s=%.2f\n"     /* bogomips */ +                       "%s=%s\n"       /* byte order */ +                       "%s" /* topology */ +                       "%s" /* frequency scaling */ +                       "[%s]\n"    /* ARM */ +                       "%s=[%s] %s\n"  /* implementer */ +                       "%s=[%s] %s\n"  /* part */ +                       "%s=[%s] %s\n"  /* architecture */ +                       "%s=%s\n"       /* variant */ +                       "%s=%s\n"       /* revision */ +                       "[%s]\n" /* flags */                         "%s" -                       "%s", -                   processor->model_name, -                   processor->decoded_name, -                   arm_mode_str[processor->mode], -                   processor->bogomips, -                   processor->cpukhz_min, -                   processor->cpukhz_max, -                   processor->cpukhz_cur, -                   processor->cpu_implementer, (tmp_imp) ? tmp_imp : "", -                   processor->cpu_part, (tmp_part) ? tmp_part : "", -                   processor->cpu_architecture, (tmp_arch) ? tmp_arch : "", -                   processor->cpu_variant, -                   processor->cpu_revision, -                   tmp_flags, +                       "%s",    /* empty */ +                   _("Processor"), +                   _("Linux Name"), processor->linux_name, +                   _("Decoded Name"), processor->model_name, +                   _("Mode"), arm_mode_str[processor->mode], +                   _("Frequency"), processor->cpu_mhz, _("MHz"), +                   _("BogoMips"), processor->bogomips, +                   _("Byte Order"), byte_order_str(), +                   tmp_topology, +                   tmp_cpufreq, +                   _("ARM"), +                   _("Implementer"), processor->cpu_implementer, (tmp_imp) ? tmp_imp : "", +                   _("Part"), processor->cpu_part, (tmp_part) ? tmp_part : "", +                   _("Architecture"), processor->cpu_architecture, (tmp_arch) ? tmp_arch : "", +                   _("Variant"), processor->cpu_variant, +                   _("Revision"), processor->cpu_revision, +                   _("Capabilities"), tmp_flags,                      "");      g_free(tmp_flags); +    g_free(tmp_cpufreq); +    g_free(tmp_topology); +    return ret; +} +gchar *processor_name(GSList *processors) { +    /* compatible contains a list of compatible hardware, so be careful +     * with matching order. +     * ex: "ti,omap3-beagleboard-xm", "ti,omap3450", "ti,omap3"; +     * matches "omap3 family" first. +     * ex: "brcm,bcm2837", "brcm,bcm2836"; +     * would match 2836 when it is a 2837. +     */ +#define UNKSOC "(Unknown)" +    const struct { +        char *search_str; +        char *vendor; +        char *soc; +    } dt_compat_searches[] = { +        { "brcm,bcm2837", "Broadcom", "BCM2837" }, +        { "brcm,bcm2836", "Broadcom", "BCM2836" }, +        { "brcm,bcm2835", "Broadcom", "BCM2835" }, +        { "ti,omap5432", "Texas Instruments", "OMAP5432" }, +        { "ti,omap5430", "Texas Instruments", "OMAP5430" }, +        { "ti,omap4470", "Texas Instruments", "OMAP4470" }, +        { "ti,omap4460", "Texas Instruments", "OMAP4460" }, +        { "ti,omap4430", "Texas Instruments", "OMAP4430" }, +        { "ti,omap3620", "Texas Instruments", "OMAP3620" }, +        { "ti,omap3450", "Texas Instruments", "OMAP3450" }, +        { "ti,omap5", "Texas Instruments", "OMAP5-family" }, +        { "ti,omap4", "Texas Instruments", "OMAP4-family" }, +        { "ti,omap3", "Texas Instruments", "OMAP3-family" }, +        { "ti,omap2", "Texas Instruments", "OMAP2-family" }, +        { "ti,omap1", "Texas Instruments", "OMAP1-family" }, +        { "qcom,msm8939", "Qualcomm", "Snapdragon 615"}, +        { "qcom,msm", "Qualcomm", "Snapdragon-family"}, +        { "nvidia,tegra" "nVidia", "Tegra-family" }, +        { "bcm,", "Broadcom", UNKSOC }, +        { "nvidia," "nVidia", UNKSOC }, +        { "rockchip," "Rockchip", UNKSOC }, +        { "ti,", "Texas Instruments", UNKSOC }, +        { "qcom,", "Qualcom", UNKSOC }, +        { NULL, NULL } +    }; +    gchar *ret = NULL; +    gchar *compat = NULL; +    int i; + +    compat = dtr_get_string("/compatible", 1); + +    if (compat != NULL) { +        i = 0; +        while(dt_compat_searches[i].search_str != NULL) { +            if (strstr(compat, dt_compat_searches[i].search_str) != NULL) { +                ret = g_strdup_printf("%s %s", dt_compat_searches[i].vendor, dt_compat_searches[i].soc); +                break; +            } +            i++; +        } +    } +    g_free(compat); +    UNKIFNULL(ret); +    return ret; +} + +gchar *processor_describe(GSList * processors) { +    return processor_describe_by_counting_names(processors); +} + +gchar *processor_meta(GSList * processors) { +    gchar *meta_soc = processor_name(processors); +    gchar *meta_cpu_desc = processor_describe(processors); +    gchar *meta_cpu_topo = processor_describe_default(processors); +    gchar *meta_clocks = processor_frequency_desc(processors); +    gchar *ret = NULL; +    UNKIFNULL(meta_cpu_desc); +    ret = g_strdup_printf("[%s]\n" +                            "%s=%s\n" +                            "%s=%s\n" +                            "%s=%s\n" +                            "%s=%s\n", +                            _("SOC/Package"), +                            _("Name"), meta_soc, +                            _("Description"), meta_cpu_desc, +                            _("Topology"), meta_cpu_topo, +                            _("Clocks"), meta_clocks ); +    g_free(meta_soc); +    g_free(meta_cpu_desc); +    g_free(meta_cpu_topo); +    g_free(meta_clocks);      return ret;  }  gchar *processor_get_info(GSList * processors)  {      Processor *processor; - -    if (g_slist_length(processors) > 1) {      gchar *ret, *tmp, *hashkey; +    gchar *meta; /* becomes owned by more_info? no need to free? */      GSList *l; -    tmp = g_strdup(""); +    tmp = g_strdup_printf("$CPU_META$%s=\n", _("SOC/Package Information") ); + +    meta = processor_meta(processors); +    moreinfo_add_with_prefix("DEV", "CPU_META", meta);      for (l = processors; l; l = l->next) {          processor = (Processor *) l->data; -        tmp = g_strdup_printf(_("%s$CPU%d$%s=%.2fMHz\n"), +        tmp = g_strdup_printf("%s$CPU%d$%s=%.2f %s\n",                    tmp, processor->id,                    processor->model_name, -                  processor->cpu_mhz); +                  processor->cpu_mhz, _("MHz"));          hashkey = g_strdup_printf("CPU%d", processor->id);          moreinfo_add_with_prefix("DEV", hashkey,                  processor_get_detailed_info(processor)); -           g_free(hashkey); +        g_free(hashkey);      }      ret = g_strdup_printf("[$ShellParam$]\n" @@ -317,8 +377,4 @@ gchar *processor_get_info(GSList * processors)      g_free(tmp);      return ret; -    } - -    processor = (Processor *) processors->data; -    return processor_get_detailed_info(processor);  } diff --git a/modules/devices/cpu_util.c b/modules/devices/cpu_util.c new file mode 100644 index 00000000..f5bddd5c --- /dev/null +++ b/modules/devices/cpu_util.c @@ -0,0 +1,225 @@ +/* + *    HardInfo - Displays System Information + *    Copyright (C) 2003-2006 Leandro A. F. Pereira <leandro@hardinfo.org> + *    This file by Burt P. <pburt0@gmail.com> + * + *    This program is free software; you can redistribute it and/or modify + *    it under the terms of the GNU General Public License as published by + *    the Free Software Foundation, version 2. + * + *    This program is distributed in the hope that it will be useful, + *    but WITHOUT ANY WARRANTY; without even the implied warranty of + *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *    GNU General Public License for more details. + * + *    You should have received a copy of the GNU General Public License + *    along with this program; if not, write to the Free Software + *    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA + */ + +#include <string.h> +#include "hardinfo.h" +#include "cpu_util.h" + +#include "cpubits.c" + +#define CPU_TOPO_NULL -9877 + +const gchar *byte_order_str() { +#if G_BYTE_ORDER == G_LITTLE_ENDIAN +    return _("Little Endian"); +#else +    return _("Big Endian"); +#endif +} + +int processor_has_flag(gchar * strflags, gchar * strflag) +{ +    gchar **flags; +    gint ret = 0; +    if (strflags == NULL || strflag == NULL) +        return 0; +    flags = g_strsplit(strflags, " ", 0); +    ret = g_strv_contains((const gchar * const *)flags, strflag); +    g_strfreev(flags); +    return ret; +} + +gchar* get_cpu_str(const gchar* file, gint cpuid) { +    gchar *tmp0 = NULL; +    gchar *tmp1 = NULL; +    tmp0 = g_strdup_printf("/sys/devices/system/cpu/cpu%d/%s", cpuid, file); +    g_file_get_contents(tmp0, &tmp1, NULL, NULL); +    g_free(tmp0); +    return tmp1; +} + +gint get_cpu_int(const char* item, int cpuid, int null_val) { +    gchar *fc = NULL; +    int ret = null_val; +    fc = get_cpu_str(item, cpuid); +    if (fc) { +        ret = atol(fc); +        g_free(fc); +    } +    return ret; +} + +/* cpubits is 32768 bits long + * core_ids are not unique among physical_ids + * hack up cpubits into 128 packs of 256 cores + * to make cores unique in cpubits */ +#define MAX_CORES_PER_PACK 256 +#define MAX_PACKS 128 + +int cpu_procs_cores_threads(int *p, int *c, int *t) { +    cpubits *threads, *cores, *packs; +    char *tmp; +    int i, m, pack_id, core_id; +    g_file_get_contents("/sys/devices/system/cpu/present", &tmp, NULL, NULL); +    if (tmp != NULL) { +        threads = cpubits_from_str(tmp); +        cores = cpubits_from_str(""); +        packs = cpubits_from_str(""); +        m = cpubits_max(threads); +        for (i = 0; i <= m; i++) { +            pack_id = get_cpu_int("topology/physical_package_id", i, CPU_TOPO_NULL); +            core_id = get_cpu_int("topology/core_id", i, CPU_TOPO_NULL); +            if (pack_id >= 0) { CPUBIT_SET(packs, pack_id); } +            if (core_id >= 0) { CPUBIT_SET(cores, (pack_id * MAX_CORES_PER_PACK) + core_id ); } +        } +        *t = cpubits_count(threads); +        *c = cpubits_count(cores); +        *p = cpubits_count(packs); +        if (!*c) *c = 1; +        if (!*p) *p = 1; +        free(threads); +        free(cores); +        free(packs); +        free(tmp); +        return 1; +    } else { +        *p = *c = *t = -1; +        return 0; +    } +} + +cpufreq_data *cpufreq_new(gint id) +{ +    cpufreq_data *cpufd; +    cpufd = malloc(sizeof(cpufreq_data)); +    if (cpufd) { +        memset(cpufd, 0, sizeof(cpufreq_data)); +        cpufd->id = id; +        cpufreq_update(cpufd, 0); +    } +    return cpufd; +} + +void cpufreq_update(cpufreq_data *cpufd, int cur_only) +{ +    if (cpufd) { +        cpufd->cpukhz_cur = get_cpu_int("cpufreq/scaling_cur_freq", cpufd->id, 0); +        if (cur_only) return; +        cpufd->scaling_driver = get_cpu_str("cpufreq/scaling_driver", cpufd->id); +        cpufd->scaling_governor = get_cpu_str("cpufreq/scaling_governor", cpufd->id); +        cpufd->transition_latency = get_cpu_int("cpufreq/cpuinfo_transition_latency", cpufd->id, 0); +        cpufd->cpukhz_min = get_cpu_int("cpufreq/scaling_min_freq", cpufd->id, 0); +        cpufd->cpukhz_max = get_cpu_int("cpufreq/scaling_max_freq", cpufd->id, 0); +        if (cpufd->scaling_driver == NULL) cpufd->scaling_driver = g_strdup("(Unknown)"); +        if (cpufd->scaling_governor == NULL) cpufd->scaling_governor = g_strdup("(Unknown)"); +    } +} + +void cpufreq_free(cpufreq_data *cpufd) +{ +    if (cpufd) { +        g_free(cpufd->scaling_driver); +        g_free(cpufd->scaling_governor); +    } +    g_free(cpufd); +} + +cpu_topology_data *cputopo_new(gint id) +{ +    cpu_topology_data *cputd; +    cputd = malloc(sizeof(cpu_topology_data)); +    if (cputd) { +        memset(cputd, 0, sizeof(cpu_topology_data)); +        cputd->id = id; +        cputd->socket_id = get_cpu_int("topology/physical_package_id", id, CPU_TOPO_NULL); +        cputd->core_id = get_cpu_int("topology/core_id", id, CPU_TOPO_NULL); +        cputd->book_id = get_cpu_int("topology/book_id", id, CPU_TOPO_NULL); +        cputd->drawer_id = get_cpu_int("topology/drawer_id", id, CPU_TOPO_NULL); +    } +    return cputd; + +} + +void cputopo_free(cpu_topology_data *cputd) +{ +    g_free(cputd); +} + +gchar *cpufreq_section_str(cpufreq_data *cpufd) +{ +    if (cpufd == NULL) +        return g_strdup(""); + +    if (cpufd->cpukhz_min || cpufd->cpukhz_max || cpufd->cpukhz_cur) { +        return g_strdup_printf( +                    "[%s]\n" +                    "%s=%d %s\n" +                    "%s=%d %s\n" +                    "%s=%d %s\n" +                    "%s=%d %s\n" +                    "%s=%s\n" +                    "%s=%s\n", +                   _("Frequency Scaling"), +                   _("Minimum"), cpufd->cpukhz_min, _("kHz"), +                   _("Maximum"), cpufd->cpukhz_max, _("kHz"), +                   _("Current"), cpufd->cpukhz_cur, _("kHz"), +                   _("Transition Latency"), cpufd->transition_latency, _("ns"), +                   _("Governor"), cpufd->scaling_governor, +                   _("Driver"), cpufd->scaling_driver); +    } else { +        return g_strdup_printf( +                    "[%s]\n" +                    "%s=%s\n", +                   _("Frequency Scaling"), +                   _("Driver"), cpufd->scaling_driver); +    } +} + +gchar *cputopo_section_str(cpu_topology_data *cputd) +{ +    static const char na[] = N_("(Not Available)"); +    char sock_str[64] = "", core_str[64] = ""; +    char book_str[64] = "", drawer_str[64] = ""; + +    if (cputd == NULL) +        return g_strdup(""); + +    if (cputd->socket_id != CPU_TOPO_NULL && cputd->socket_id != -1) +        sprintf(sock_str, "%s=%d\n", _("Socket"), cputd->socket_id); +    else +        sprintf(sock_str, "%s=%s\n", _("Socket"), na); + +    if (cputd->core_id != CPU_TOPO_NULL) +        sprintf(core_str, "%s=%d\n", _("Core"), cputd->core_id); +    else +        sprintf(core_str, "%s=%s\n", _("Core"), na); + +    if (cputd->book_id != CPU_TOPO_NULL) +        sprintf(core_str, "%s=%d\n", _("Book"), cputd->book_id); +    if (cputd->book_id != CPU_TOPO_NULL) +        sprintf(core_str, "%s=%d\n", _("Drawer"), cputd->drawer_id); + +    return g_strdup_printf( +                    "[%s]\n" +                    "%s=%d\n" +                    "%s%s%s%s", +                   _("Topology"), +                   _("ID"), cputd->id, +                   sock_str, core_str, book_str, drawer_str ); +} diff --git a/modules/devices/cpubits.c b/modules/devices/cpubits.c new file mode 100644 index 00000000..ba9bffc7 --- /dev/null +++ b/modules/devices/cpubits.c @@ -0,0 +1,113 @@ +/* + * rpiz - https://github.com/bp0/rpiz + * Copyright (C) 2017  Burt P. <pburt0@gmail.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. + * + */ + +#include <stdint.h> + +typedef uint32_t cpubits; +uint32_t cpubits_count(cpubits *b); +cpubits *cpubits_from_str(char *str); +char *cpubits_to_str(cpubits *bits, char *str, int max_len); + +#define CPUBITS_SIZE 4096 /* bytes, multiple of sizeof(uint32_t) */ +#define CPUBIT_SET(BITS, BIT) (BITS[BIT/32] |= (1 << BIT%32)) +#define CPUBIT_GET(BITS, BIT) ((BITS[BIT/32] & (1 << BIT%32)) >> BIT%32) +#define CPUBITS_CLEAR(BITS) memset(BITS, 0, CPUBITS_SIZE) + +uint32_t cpubits_count(cpubits *b) { +    static const uint32_t max = CPUBITS_SIZE * 8; +    uint32_t count = 0, i = 0; +    while (i < max) { +        count += CPUBIT_GET(b, i); +        i++; +    } +    return count; +} + +int cpubits_max(cpubits *b) { +    int i = CPUBITS_SIZE * 8; +    while (i >= 0) { +        if (CPUBIT_GET(b, i)) +            break; +        i--; +    } +    return i; +} + +cpubits *cpubits_from_str(char *str) { +    char *v, *nv, *hy; +    int r0, r1; +    cpubits *newbits = malloc(CPUBITS_SIZE); +    if (newbits) { +        memset(newbits, 0, CPUBITS_SIZE); +        if (str != NULL) { +            v = (char*)str; +            while ( *v != 0 ) { +                nv = strchr(v, ',');                /* strchrnul() */ +                if (nv == NULL) nv = strchr(v, 0);  /* equivalent  */ +                hy = strchr(v, '-'); +                if (hy && hy < nv) { +                    r0 = strtol(v, NULL, 0); +                    r1 = strtol(hy + 1, NULL, 0); +                } else { +                    r0 = r1 = strtol(v, NULL, 0); +                } +                for (; r0 <= r1; r0++) { +                    CPUBIT_SET(newbits, r0); +                } +                v = (*nv == ',') ? nv + 1 : nv; +            } +        } +    } +    return newbits; +} + +char *cpubits_to_str(cpubits *bits, char *str, int max_len) { +    static const uint32_t max = CPUBITS_SIZE * 8; +    uint32_t i = 1, seq_start = 0, seq_last = 0, seq = 0, l = 0; +    char buffer[65536] = ""; +    if (CPUBIT_GET(bits, 0)) { +        seq = 1; +        strcpy(buffer, "0"); +    } +    while (i < max) { +        if (CPUBIT_GET(bits, i) ) { +            seq_last = i; +            if (!seq) { +                seq = 1; +                seq_start = i; +                l = strlen(buffer); +                sprintf(buffer + l, "%s%d", l ? "," : "", i); +            } +        } else { +            if (seq && seq_last != seq_start) { +                l = strlen(buffer); +                sprintf(buffer + l, "-%d", seq_last); +            } +            seq = 0; +        } +        i++; +    } +    if (str == NULL) +        return strdup(buffer); +    else { +        strncpy(str, buffer, max_len); +        return str; +    } +} diff --git a/modules/devices/devicetree.c b/modules/devices/devicetree.c new file mode 100644 index 00000000..6fce066a --- /dev/null +++ b/modules/devices/devicetree.c @@ -0,0 +1,272 @@ +/* + *    HardInfo - Displays System Information + *    Copyright (C) 2003-2007 Leandro A. F. Pereira <leandro@hardinfo.org> + * + *    This program is free software; you can redistribute it and/or modify + *    it under the terms of the GNU General Public License as published by + *    the Free Software Foundation, version 2. + * + *    This program is distributed in the hope that it will be useful, + *    but WITHOUT ANY WARRANTY; without even the implied warranty of + *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *    GNU General Public License for more details. + * + *    You should have received a copy of the GNU General Public License + *    along with this program; if not, write to the Free Software + *    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA + */ +/* + * Device Tree support by Burt P. <pburt0@gmail.com> + * Sources: + *   http://elinux.org/Device_Tree_Usage + *   http://elinux.org/Device_Tree_Mysteries + */ +#include <unistd.h> +#include <sys/types.h> +#include <stdint.h> +#include "hardinfo.h" +#include "devices.h" +#include "cpu_util.h" +#include "dt_util.h" + +#include "devicetree/rpi_data.c" +#include "devicetree/pmac_data.c" + +dtr *dt; +gchar *dtree_info = NULL; + +gchar *get_node(char *np) { +    gchar *nodes = NULL, *props = NULL, *ret = NULL; +    gchar *tmp = NULL, *pstr = NULL, *lstr = NULL; +    gchar *dir_path; +    gchar *node_path; +    const gchar *fn; +    GDir *dir; +    dtr_obj *node, *child; + +    props = g_strdup_printf("[%s]\n", _("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) { +            child = dtr_get_prop_obj(dt, node, fn); +            pstr = hardinfo_clean_value(dtr_str(child), 1); +            lstr = hardinfo_clean_label(fn, 0); +            if (dtr_obj_type(child) == DT_NODE) { +                tmp = g_strdup_printf("%s%s=%s\n", +                    nodes, lstr, pstr); +                g_free(nodes); +                nodes = tmp; +            } else { +                tmp = g_strdup_printf("%s%s=%s\n", +                    props, lstr, pstr); +                g_free(props); +                props = tmp; +            } +            dtr_obj_free(child); +            g_free(pstr); +            g_free(lstr); +        } +    } +    g_dir_close(dir); +    g_free(dir_path); + +    lstr = dtr_obj_alias(node); +    pstr = dtr_obj_symbol(node); +    ret = g_strdup_printf("[%s]\n" +                    "%s=%s\n" +                    "%s=%s\n" +                    "%s=%s\n" +                    "%s%s", +                    _("Node"), +                    _("Node Path"), dtr_obj_path(node), +                    _("Alias"), (lstr != NULL) ? lstr : _("(None)"), +                    _("Symbol"), (pstr != NULL) ? pstr : _("(None)"), +                    props, nodes); + +    dtr_obj_free(node); +    g_free(props); +    g_free(nodes); +    return ret; +} + +/* different from  dtr_get_string() in that it re-uses the existing dt */ +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(obj); +        dtr_obj_free(obj); +    } else +        ret = dtr_get_prop_str(dt, NULL, path); +    return ret; +} + +gchar *get_summary() { +    char *model = NULL, *compat = NULL; +    char *tmp[10]; +    char *ret = NULL; + +    model = get_dt_string("/model", 0); +    compat = get_dt_string("/compatible", 1); +    UNKIFNULL(model); +    EMPIFNULL(compat); + +    /* 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 +        || strstr(compat, "raspberrypi") != NULL ) { +        tmp[0] = get_dt_string("/serial-number", 1); +        tmp[1] = get_dt_string("/soc/gpu/compatible", 1); +        tmp[9] = rpi_board_details(); +        tmp[8] = g_strdup_printf( +                "[%s]\n" "%s=%s\n" "%s=%s\n", +                _("Platform"), +                _("Compatible"), compat, +                _("GPU-compatible"), tmp[1] ); +        if (tmp[9] != NULL) { +            ret = g_strdup_printf("%s%s", tmp[9], tmp[8]); +        } else { +            ret = g_strdup_printf( +                "[%s]\n" "%s=%s\n" "%s=%s\n" "%s=%s\n" "%s", +                _("Raspberry Pi or Compatible"), +                _("Model"), model, +                _("Serial Number"), tmp[0], +                _("RCode"), _("No revision code available; unable to lookup model details."), +                tmp[8]); +        } +        free(tmp[0]); free(tmp[1]); +        free(tmp[9]); free(tmp[8]); +    } + +    /* Power Macintosh */ +    if (strstr(compat, "PowerBook") != NULL +         || strstr(compat, "MacRISC") != NULL +         || strstr(compat, "Power Macintosh") != NULL) { +        tmp[9] =  ppc_mac_details(); +        if (tmp[9] != NULL) { +            tmp[0] = get_dt_string("/serial-number", 1); +            ret = g_strdup_printf( +                "%s[%s]\n" "%s=%s\n", tmp[9], +                _("More"), +                _("Serial Number"), tmp[0] ); +            free(tmp[0]); +        } +        free(tmp[9]); +    } + +    /* fallback */ +    if (ret == NULL) { +        tmp[0] = get_dt_string("/serial-number", 1); +        EMPIFNULL(tmp[0]); +        ret = g_strdup_printf( +                "[%s]\n" +                "%s=%s\n" +                "%s=%s\n" +                "%s=%s\n", +                _("Board"), +                _("Model"), model, +                _("Serial Number"), tmp[0], +                _("Compatible"), compat); +        free(tmp[0]); +    } +    free(model); +    return ret; +} + +void mi_add(const char *key, const char *value) { +    gchar *ckey, *rkey; + +    ckey = hardinfo_clean_label(key, 0); +    rkey = g_strdup_printf("%s:%s", "DTREE", ckey); + +    dtree_info = h_strdup_cprintf("$%s$%s=\n", dtree_info, rkey, ckey); +    moreinfo_add_with_prefix("DEV", rkey, g_strdup(value)); + +    g_free(ckey); +    g_free(rkey); +} + +void add_keys(char *np) { +    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) ) { +                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); +            } +            g_free(ftmp); +        } +    } +    g_dir_close(dir); +} + +char *msg_section(int dump) { +    gchar *aslbl = NULL; +    gchar *messages = dtr_messages(dt); +    gchar *ret = g_strdup_printf("[%s]\n", _("Messages")); +    gchar **lines = g_strsplit(messages, "\n", 0); +    int i = 0; +    while(lines[i] != NULL) { +        aslbl = hardinfo_clean_label(lines[i], 0); +        ret = appf(ret, "%s=\n", aslbl); +        g_free(aslbl); +        i++; +    } +    g_strfreev(lines); +    if (dump) +        printf("%s", messages); +    g_free(messages); +    return ret; +} + +void __scan_dtree() +{ +    dt = dtr_new(NULL); +    gchar *summary = get_summary(); +    gchar *maps = dtr_maps_info(dt); +    gchar *messages = NULL; + +    dtree_info = g_strdup("[Device Tree]\n"); +    mi_add("Summary", summary); +    mi_add("Maps", maps); + +    if(dtr_was_found(dt)) +        add_keys("/"); +    messages = msg_section(0); +    mi_add("Messages", messages); + +    //printf("%s\n", dtree_info); + +    g_free(summary); +    g_free(maps); +    g_free(messages); +    dtr_free(dt); +} diff --git a/modules/devices/devicetree/dt_util.c b/modules/devices/devicetree/dt_util.c new file mode 100644 index 00000000..9678042d --- /dev/null +++ b/modules/devices/devicetree/dt_util.c @@ -0,0 +1,1040 @@ +/* + *    HardInfo - Displays System Information + *    Copyright (C) 2003-2007 Leandro A. F. Pereira <leandro@hardinfo.org> + * + *    This program is free software; you can redistribute it and/or modify + *    it under the terms of the GNU General Public License as published by + *    the Free Software Foundation, version 2. + * + *    This program is distributed in the hope that it will be useful, + *    but WITHOUT ANY WARRANTY; without even the implied warranty of + *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *    GNU General Public License for more details. + * + *    You should have received a copy of the GNU General Public License + *    along with this program; if not, write to the Free Software + *    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA + */ +/* + * Device Tree support by Burt P. <pburt0@gmail.com> + * Sources: + *   http://elinux.org/Device_Tree_Usage + *   http://elinux.org/Device_Tree_Mysteries + */ +#include <unistd.h> +#include <sys/types.h> +#include <endian.h> +#include "hardinfo.h" +#include "dt_util.h" + +static struct { +    char *name; int type; +} prop_types[] = { +    { "name", DTP_STR }, +    { "compatible", DTP_STR }, +    { "model", DTP_STR }, +    { "reg", DTP_REG }, +    { "clocks", DTP_CLOCKS }, +    { "gpios", DTP_GPIOS }, +    { "cs-gpios", DTP_GPIOS }, +    { "phandle", DTP_PH }, +    { "interrupts", DTP_INTRUPT }, +    { "interrupts-extended", DTP_INTRUPT_EX }, +    { "interrupt-parent", DTP_PH_REF }, +    { "interrupt-controller", DTP_EMPTY }, +    { "regulator-min-microvolt", DTP_UINT }, +    { "regulator-max-microvolt", DTP_UINT }, +    { "clock-frequency", DTP_UINT }, +    { "dmas", DTP_DMAS }, +    { "dma-channels", DTP_UINT }, +    { "dma-requests", DTP_UINT }, +    { NULL, 0 }, +}; + +static struct { +    char *name; uint32_t v; +} default_values[] = { +    { "#address-cells", 2 }, +    { "#size-cells", 1 }, +    { "#dma-cells", 1 }, +    { NULL, 0 }, +}; + +struct _dtr_map { +    uint32_t v;  /* phandle */ +    char *label;  /* alias */ +    char *path; +    struct _dtr_map *next; +}; +typedef struct _dtr_map dtr_map; + +struct _dtr { +    dtr_map *aliases; +    dtr_map *symbols; +    dtr_map *phandles; +    char *base_path; +    char *log; +}; + +struct _dtr_obj { +    char *path; +    union { +        void *data; +        char *data_str; +        dt_uint *data_int; +    }; +    char *name; +    uint32_t length; +    int type; +    char *prefix;        /* if the name has a manufacturer's prefix or null */ +    char *np_name;       /* the name without any prefix. points into .prefix or .name, do not free */ +    const char *alias;  /* null until first dtr_obj_alias(). do not free */ +    const char *symbol; /* null until first dtr_obj_symbol(). do not free */ +    dtr *dt; +}; + +dtr_map *dtr_map_add(dtr_map *map, uint32_t v, const char *label, const char *path) { +    dtr_map *it; +    dtr_map *nmap = malloc(sizeof(dtr_map)); +    memset(nmap, 0, sizeof(dtr_map)); +    nmap->v = v; + +    if (label != NULL) nmap->label = strdup(label); +    if (path != NULL) nmap->path = strdup(path); +    if (map == NULL) +        return nmap; + +    it = map; +    while(it->next != NULL) +        it = it->next; +    it->next = nmap; + +    return nmap; +} + +void dtr_map_free(dtr_map *map) { +    dtr_map *it; +    while(map != NULL) { +        it = map->next; +        free(map->label); +        free(map->path); +        free(map); +        map = it; +    } +} + +/* simple sort for maps + * sv: 1 = sort by v, 0 = sort by label */ +void dtr_map_sort(dtr_map *map, int sv) +{ +    int done = 0, cmp; +    dtr_map *this, *next, *top, *next_top; +    uint32_t tmp_v; +    char *tmp_l, *tmp_p; +    if (map == NULL) return; +    do { +        this = map; +        next_top = NULL; +        while(this != NULL) { +            next = this->next; +            if (this == top) +                break; +            if (next == NULL) +                break; +            if (sv) +                cmp = (this->v > next->v) ? 1 : 0; +            else +                cmp = strcmp(this->label, next->label); +            if (cmp > 0) { +                tmp_v = this->v; this->v = next->v; next->v = tmp_v; +                tmp_l = this->label; this->label = next->label; next->label = tmp_l; +                tmp_p = this->path; this->path = next->path; next->path = tmp_p; +                next_top = this; +            } +            this = next; +        } +        if (next_top == NULL) +            done = 1; +        else +            top = next_top; +    } while (!done); +} + +const char *dtr_phandle_lookup(dtr *s, uint32_t v) { +    dtr_map *phi = s->phandles; +    /* 0 and 0xffffffff are invalid phandle values */ +    /* TODO: perhaps "INVALID" or something */ +    if (v == 0 || v == 0xffffffff) +        return NULL; +    while(phi != NULL) { +        if (phi->v == v) +            return phi->path; +        phi = phi->next; +    } +    return NULL; +} + +const char *dtr_alias_lookup(dtr *s, const char* label) { +    dtr_map *ali = s->aliases; +    while(ali != NULL) { +        if (strcmp(ali->label, label) == 0) +            return ali->path; +        ali = ali->next; +    } +    return NULL; +} + +const char *dtr_alias_lookup_by_path(dtr *s, const char* path) { +    dtr_map *ali = s->aliases; +    while(ali != NULL) { +        if (strcmp(ali->path, path) == 0) +            return ali->label; +        ali = ali->next; +    } +    return NULL; +} + +const char *dtr_symbol_lookup_by_path(dtr *s, const char* path) { +    dtr_map *ali = s->symbols; +    while(ali != NULL) { +        if (strcmp(ali->path, path) == 0) +            return ali->label; +        ali = ali->next; +    } +    return NULL; +} + +void _dtr_read_aliases(dtr *); +void _dtr_read_symbols(dtr *); +void _dtr_map_phandles(dtr *, char *np); + +const char *dtr_find_device_tree_root() { +    char *candidates[] = { +        "/proc/device-tree", +        "/sys/firmware/devicetree/base", +        /* others? */ +        NULL +    }; +    int i = 0; +    while (candidates[i] != NULL) { +        if(access(candidates[i], F_OK) != -1) +            return candidates[i]; +        i++; +    } +    return NULL; +} + +dtr *dtr_new_x(const char *base_path, int fast) { +    dtr *dt = malloc(sizeof(dtr)); +    if (dt != NULL) { +        memset(dt, 0, sizeof(dtr)); +        dt->log = strdup(""); + +        if (base_path == NULL) +            base_path = DTR_ROOT; + +        if (base_path != NULL) +            dt->base_path = strdup(base_path); +        else { +            dtr_msg(dt, "%s", "Device Tree not found."); +            return dt; +        } + +        /* build alias and phandle lists */ +        dt->aliases = NULL; +        dt->symbols = NULL; +        dt->phandles = NULL; +        if (!fast) { +            _dtr_read_aliases(dt); +            _dtr_read_symbols(dt); +            _dtr_map_phandles(dt, ""); +        } +    } +    return dt; +} + +dtr *dtr_new(const char *base_path) { +    return dtr_new_x(base_path, 0); +} + +void dtr_free(dtr *s) { +    if (s != NULL) { +        dtr_map_free(s->aliases); +        dtr_map_free(s->symbols); +        dtr_map_free(s->phandles); +        free(s->base_path); +        free(s->log); +        free(s); +    } +} + +int dtr_was_found(dtr *s) { +    if (s != NULL) { +        if (s->base_path != NULL) +            return 1; +    } +    return 0; +} + +void dtr_msg(dtr *s, char *fmt, ...) { +    gchar *buf, *tmp; +    va_list args; + +    va_start(args, fmt); +    buf = g_strdup_vprintf(fmt, args); +    va_end(args); + +    tmp = g_strdup_printf("%s%s", s->log, buf); +    g_free(s->log); +    s->log = tmp; +} + +char *dtr_messages(dtr *s) { +    if (s != NULL) +        return strdup(s->log); +    else +        return NULL; +} + +const char *dtr_base_path(dtr *s) { +    if (s) +        return s->base_path; +    return NULL; +} + +/*glib, but _dt_obj *prop uses malloc() and std types */ +dtr_obj *dtr_obj_read(dtr *s, const char *dtp) { +    char *full_path; +    char *slash, *coma; +    dtr_obj *obj; + +    if (dtp == NULL) +        return NULL; + +    obj = malloc(sizeof(dtr_obj)); +    if (obj != NULL) { +        memset(obj, 0, sizeof(dtr_obj)); + +        obj->dt = s; +        if (*dtp != '/') { +            /* doesn't start with slash, use alias */ +            obj->path = (char*)dtr_alias_lookup(s, dtp); +            if (obj->path != NULL) +                obj->path = strdup(obj->path); +            else { +                dtr_obj_free(obj); +                return NULL; +            } +        } else +            obj->path = strdup(dtp); + +        /* find name after last slash, or start */ +        slash = strrchr(obj->path, '/'); +        if (slash != NULL) +            obj->name = strdup(slash + 1); +        else +            obj->name = strdup(obj->path); + +        /* find manufacturer prefix */ +        obj->prefix = strdup(obj->name); +        coma = strchr(obj->prefix, ','); +        if (coma != NULL) { +            /* coma -> null; .np_name starts after */ +            *coma = 0; +            obj->np_name = coma + 1; +        } else { +            obj->np_name = obj->name; +            free(obj->prefix); +            obj->prefix = NULL; +        } + +        /* read data */ +        full_path = g_strdup_printf("%s%s", s->base_path, obj->path); +        if ( g_file_test(full_path, G_FILE_TEST_IS_DIR) ) { +            obj->type = DT_NODE; +        } else { +            if (!g_file_get_contents(full_path, (gchar**)&obj->data, (gsize*)&obj->length, NULL)) { +                dtr_obj_free(obj); +                g_free(full_path); +                return NULL; +            } +            obj->type = dtr_guess_type(obj); +        } +        g_free(full_path); + +        return obj; +    } +    return NULL; +} + +void dtr_obj_free(dtr_obj *s) { +    if (s != NULL) { +        free(s->path); +        free(s->name); +        free(s->prefix); +        free(s->data); +        free(s); +    } +} + +int dtr_obj_type(dtr_obj *s) { +    if (s) +        return s->type; +    return DT_TYPE_ERR; +} + +char *dtr_obj_alias(dtr_obj *s) { +    if (s) { +        if (s->alias == NULL) +            s->alias = dtr_alias_lookup_by_path(s->dt, s->path); +        return (char*)s->alias; +    } +    return NULL; +} + +char *dtr_obj_symbol(dtr_obj *s) { +    if (s) { +        if (s->symbol == NULL) +            s->symbol = dtr_symbol_lookup_by_path(s->dt, s->path); +        return (char*)s->symbol; +    } +    return NULL; +} + +char *dtr_obj_path(dtr_obj *s) { +    if (s) +        return s->path; +    return NULL; +} + +char *dtr_obj_full_path(dtr_obj *s) { +    if (s) { +        if (strcmp(s->path, "/") == 0) +            return g_strdup_printf("%s", s->dt->base_path); +        else +            return g_strdup_printf("%s%s", s->dt->base_path, s->path); +    } +    return NULL; +} + +dtr_obj *dtr_get_prop_obj(dtr *s, dtr_obj *node, const char *name) { +    dtr_obj *prop; +    char *ptmp; +    ptmp = g_strdup_printf("%s/%s", (node == NULL) ? "" : node->path, name); +    prop = dtr_obj_read(s, ptmp); +    g_free(ptmp); +    return prop; +} + +char *dtr_get_prop_str(dtr *s, dtr_obj *node, const char *name) { +    dtr_obj *prop; +    char *ptmp; +    char *ret = NULL; + +    ptmp = g_strdup_printf("%s/%s", (node == NULL) ? "" : node->path, name); +    prop = dtr_obj_read(s, ptmp); +    if (prop != NULL && prop->data != NULL) { +        ret = strdup(prop->data_str); +        dtr_obj_free(prop); +    } +    g_free(ptmp); +    return ret; +} + +char *dtr_get_string(const char *p, int decode) { +    dtr *dt = dtr_new_x(NULL, 1); +    dtr_obj *obj; +    char *ret = NULL; +    if (decode) { +        obj = dtr_get_prop_obj(dt, NULL, p); +        ret = dtr_str(obj); +        dtr_obj_free(obj); +    } else +        ret = dtr_get_prop_str(dt, NULL, p); +    dtr_free(dt); +    return ret; +} + +uint32_t dtr_get_prop_u32(dtr *s, dtr_obj *node, const char *name) { +    dtr_obj *prop; +    char *ptmp; +    uint32_t ret = 0; + +    ptmp = g_strdup_printf("%s/%s", (node == NULL) ? "" : node->path, name); +    prop = dtr_obj_read(s, ptmp); +    if (prop != NULL && prop->data != NULL) { +        ret = be32toh(*prop->data_int); +        dtr_obj_free(prop); +    } +    g_free(ptmp); +    return ret; +} + +int dtr_guess_type(dtr_obj *obj) { +    char *tmp, *dash; +    int i = 0, anc = 0, might_be_str = 1; + +    if (obj->length == 0) +        return DTP_EMPTY; + +    /* special #(.*)-cells names are UINT */ +    if (*obj->name == '#') { +        dash = strrchr(obj->name, '-'); +        if (dash != NULL) { +            if (strcmp(dash, "-cells") == 0) +                return DTP_UINT; +        } +    } + +    /* /aliases/* and /__symbols__/* are always strings */ +    if (strncmp(obj->path, "/aliases/", strlen("/aliases/") ) == 0) +        return DTP_STR; +    if (strncmp(obj->path, "/__symbols__/", strlen("/__symbols__/") ) == 0) +        return DTP_STR; + +    /* /__overrides__/* */ +    if (strncmp(obj->path, "/__overrides__/", strlen("/__overrides__/") ) == 0) +        if (strcmp(obj->name, "name") != 0) +            return DTP_OVR; + +    /* lookup known type */ +    while (prop_types[i].name != NULL) { +        if (strcmp(obj->name, prop_types[i].name) == 0) +            return prop_types[i].type; +        i++; +    } + +    /* maybe a string? */ +    for (i = 0; i < obj->length; i++) { +        tmp = obj->data_str + 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 >= obj->length - 2 /* all alpha-nums but ^/ and \0$ */ +          || anc >= 5 ) /*arbitrary*/) +        return DTP_STR; + +    /* multiple of 4 bytes, try list of hex values */ +    if (!(obj->length % 4)) +        return DTP_HEX; + +    return DTP_UNK; +} + +char *dtr_elem_phref(dtr *s, dt_uint e, int show_path) { +    const char *ph_path, *al_label; +    char *ret = NULL; +    ph_path = dtr_phandle_lookup(s, be32toh(e)); +    if (ph_path != NULL) { +        /* TODO: alias or symbol? */ +        al_label = dtr_symbol_lookup_by_path(s, ph_path); +        if (al_label != NULL) { +            if (show_path) +                ret = g_strdup_printf("&%s (%s)", al_label, ph_path); +            else +                ret = g_strdup_printf("&%s", al_label); +        } else { +            if (show_path) +                ret = g_strdup_printf("0x%x (%s)", be32toh(e), ph_path); +        } +    } +    if (ret == NULL) +        ret = dtr_elem_hex(e); +    return ret; +} + +char *dtr_elem_hex(dt_uint e) { +    return g_strdup_printf("0x%x", be32toh(e) ); +} + +char *dtr_elem_byte(uint8_t e) { +    return g_strdup_printf("%x", e); +} + +char *dtr_elem_uint(dt_uint e) { +    return g_strdup_printf("%u", be32toh(e) ); +} + +char *dtr_list_byte(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; +} + +char *dtr_list_hex(dt_uint *list, unsigned long count) { +    char *ret, *dest; +    char buff[12] = "";  /* max element: " 0x00000000\0" */ +    unsigned long i, l; +    l = count * 12 + 1; +    dest = ret = malloc(l); +    memset(ret, 0, l); +    for (i = 0; i < count; i++) { +        sprintf(buff, "%s0x%x", (i) ? " " : "", be32toh(list[i])); +        l = strlen(buff); +        strncpy(dest, buff, l); +        dest += l; +    } +    return ret; +} + +/*cstd, except for g_strescape()*/ +char *dtr_list_str0(const char *data, uint32_t length) { +    char *tmp, *esc, *next_str; +    char ret[1024] = ""; +    uint32_t l, tl; + +    /* treat as null-separated string list */ +    tl = 0; +    strcpy(ret, ""); +    tmp = ret; +    next_str = (char*)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 >= length) break; +    } + +    return strdup(ret); +} + +char *dtr_list_override(dtr_obj *obj) { +    /* <phref, string "property:value"> ... */ +    char *ret = NULL; +    char *ph, *str; +    char *src; +    int l, consumed = 0; +    src = obj->data_str; +    while (consumed + 5 <= obj->length) { +        ph = dtr_elem_phref(obj->dt, *(dt_uint*)src, 1); +        src += 4; consumed += 4; +        l = strlen(src) + 1; /* consume the null */ +        str = dtr_list_str0(src, l); +        ret = appf(ret, "<%s -> %s>", ph, str); +        src += l; consumed += l; +        free(ph); +        free(str); +    } +    if (consumed < obj->length) { +        str = dtr_list_byte(src, obj->length - consumed); +        ret = appf(ret, "%s", str); +        free(str); +    } +    return ret; +} + +uint32_t dtr_get_phref_prop(dtr *s, uint32_t phandle, char *prop) { +    const char *ph_path; +    char *tmp; +    uint32_t ret; +    ph_path = dtr_phandle_lookup(s, phandle); +    tmp = g_strdup_printf("%s/%s", ph_path, prop); +    ret = dtr_get_prop_u32(s, NULL, tmp); +    free(tmp); +    return ret; +} + +char *dtr_list_phref(dtr_obj *obj, char *ext_cell_prop) { +    /* <phref, #XXX-cells> */ +    int count = obj->length / 4; +    int i = 0, ext_cells = 0; +    char *ph_path; +    char *ph, *ext, *ret = NULL; +    while (i < count) { +        if (ext_cell_prop == NULL) +            ext_cells = 0; +        else +            ext_cells = dtr_get_phref_prop(obj->dt, be32toh(obj->data_int[i]), ext_cell_prop); +        ph = dtr_elem_phref(obj->dt, obj->data_int[i], 0); i++; +        if (ext_cells > count - i) ext_cells = count - i; +        ext = dtr_list_hex((obj->data_int + i), ext_cells); i+=ext_cells; +        ret = appf(ret, "<%s%s%s>", +            ph, (ext_cells) ? " " : "", ext); +        g_free(ph); +        g_free(ext); +    } +    return ret; +} + +char *dtr_list_interrupts(dtr_obj *obj) { +    char *ext, *ret = NULL; +    uint32_t iparent, icells; +    int count, i = 0; + +    iparent = dtr_inh_find(obj, "interrupt-parent", 0); +    if (!iparent) { +        dtr_msg(obj->dt, "Did not find an interrupt-parent for %s", obj->path); +        goto intr_err; +    } +    icells = dtr_get_phref_prop(obj->dt, iparent, "#interrupt-cells"); +    if (!icells) { +        dtr_msg(obj->dt, "Invalid #interrupt-cells value %d for %s", icells, obj->path); +        goto intr_err; +    } + +    count = obj->length / 4; +    while (i < count) { +        icells = MIN(icells, count - i); +        ext = dtr_list_hex((obj->data_int + i), icells); i+=icells; +        ret = appf(ret, "<%s>", ext); +    } +    return ret; + +intr_err: +    return dtr_list_hex(obj->data_int, obj->length); + +} + +char *dtr_list_reg(dtr_obj *obj) { +    char *tup_str, *ret = NULL; +    uint32_t acells, scells, tup_len; +    uint32_t tups, extra, consumed; /* extra and consumed are bytes */ +    uint32_t *next; + +    acells = dtr_inh_find(obj, "#address-cells", 2); +    scells = dtr_inh_find(obj, "#size-cells", 2); +    tup_len = acells + scells; +    tups = obj->length / (tup_len * 4); +    extra = obj->length % (tup_len * 4); +    consumed = 0; /* bytes */ + +    //printf("list reg: %s\n ... acells: %u, scells: %u, extra: %u\n", obj->path, acells, scells, extra); + +    if (extra) { +        /* error: length is not a multiple of tuples */ +        dtr_msg(obj->dt, "Data length (%u) is not a multiple of (#address-cells:%u + #size-cells:%u) for %s\n", +            obj->length, acells, scells, obj->path); +        return dtr_list_hex(obj->data, obj->length / 4); +    } + +    next = obj->data_int; +    consumed = 0; +    while (consumed + (tup_len * 4) <= obj->length) { +        tup_str = dtr_list_hex(next, tup_len); +        ret = appf(ret, "<%s>", tup_str); +        free(tup_str); +        consumed += (tup_len * 4); +        next += tup_len; +    } + +    //printf(" ... %s\n", ret); +    return ret; +} + +char* dtr_str(dtr_obj *obj) { +    char *ret; +    int type; + +    if (obj == NULL) return NULL; +    type = obj->type; + +    if (type == DTP_PH_REF) { +        if (!DTEX_PHREFS || obj->length != 4) +            type = DTP_HEX; +    } + +    switch(type) { +        case DT_NODE: +            ret = strdup("{node}"); +            break; +        case DTP_EMPTY: +            ret = strdup("{empty}"); +            break; +        case DTP_STR: +            ret = dtr_list_str0(obj->data_str, obj->length); +            break; +        case DTP_OVR: +            ret = dtr_list_override(obj); +            break; +        case DTP_REG: +            /* <#address-cells #size-cells> */ +            ret = dtr_list_reg(obj); +            break; +        case DTP_INTRUPT: +            ret = dtr_list_interrupts(obj); +            break; +        case DTP_INTRUPT_EX: +            /* <phref, #interrupt-cells"> */ +            ret = dtr_list_phref(obj, "#interrupt-cells"); +            break; +        case DTP_CLOCKS: +            /* <phref, #clock-cells"> */ +            ret = dtr_list_phref(obj, "#clock-cells"); +            break; +        case DTP_GPIOS: +            /* <phref, #gpio-cells"> */ +            ret = dtr_list_phref(obj, "#gpio-cells"); +            break; +        case DTP_DMAS: +            /* <phref, #dma-cells"> */ +            ret = dtr_list_phref(obj, "#dma-cells"); +            break; +        case DTP_PH: +        case DTP_HEX: +            if (obj->length % 4) +                ret = dtr_list_byte((uint8_t*)obj->data, obj->length); +            else +                ret = dtr_list_hex(obj->data, obj->length / 4); +            break; +        case DTP_PH_REF: +            ret = dtr_elem_phref(obj->dt, *obj->data_int, 1); +            break; +        case DTP_UINT: +            ret = dtr_elem_uint(*obj->data_int); +            break; +        case DTP_UNK: +        default: +            if (obj->length > 64) /* maybe should use #define at the top */ +                ret = g_strdup_printf(ret, "{data} (%lu bytes)", obj->length); +            else +                ret = dtr_list_byte((uint8_t*)obj->data, obj->length); +            break; +    } + +    return ret; +} + +dtr_obj *dtr_get_parent_obj(dtr_obj *obj) { +    char *slash, *parent; +    dtr_obj *ret = NULL; + +    if (obj == NULL) +        return NULL; + +    parent = strdup(obj->path); +    slash = strrchr(parent, '/'); +    if (slash != NULL) { +        *slash = 0; +        if (strlen(parent) > 0) +            ret = dtr_obj_read(obj->dt, parent); +        else +            ret = dtr_obj_read(obj->dt, "/"); +    } +    free(parent); +    return ret; +} + +/* find the value of a path-inherited property by climbing the path */ +int dtr_inh_find(dtr_obj *obj, char *qprop, int limit) { +    dtr_obj *tobj, *pobj, *qobj; +    uint32_t ret = 0; +    int i, found = 0; + +    if (!limit) limit = 1000; + +    tobj = obj; +    while (tobj != NULL) { +        pobj = dtr_get_parent_obj(tobj); +        if (tobj != obj) +            dtr_obj_free(tobj); +        if (!limit || pobj == NULL) break; +        qobj = dtr_get_prop_obj(obj->dt, pobj, qprop); +        if (qobj != NULL) { +            ret = be32toh(*qobj->data_int); +            found = 1; +            dtr_obj_free(qobj); +            break; +        } +        tobj = pobj; +        limit--; +    } +    dtr_obj_free(pobj); + +    if (!found) { +        i = 0; +        while(default_values[i].name != NULL) { +            if (strcmp(default_values[i].name, qprop) == 0) { +                ret = default_values[i].v; +                dtr_msg(obj->dt, "Using default value %d for %s in %s\n", ret, qprop, obj->path); +                break; +            } +            i++; +        } +    } + +    return ret; +} + +void _dtr_read_aliases(dtr *s) { +    gchar *dir_path; +    GDir *dir; +    const gchar *fn; +    dtr_obj *anode, *prop; +    dtr_map *al; +    anode = dtr_obj_read(s, "/aliases"); + +    dir_path = g_strdup_printf("%s/aliases", s->base_path); +    dir = g_dir_open(dir_path, 0 , NULL); +    if (dir) { +        while((fn = g_dir_read_name(dir)) != NULL) { +            prop = dtr_get_prop_obj(s, anode, fn); +            if (prop->type == DTP_STR) { +                if (*prop->data_str == '/') { +                    al = dtr_map_add(s->aliases, 0, prop->name, prop->data_str); +                    if (s->aliases == NULL) +                        s->aliases = al; +                } +            } +            dtr_obj_free(prop); +        } +    } +    g_dir_close(dir); +    g_free(dir_path); +    dtr_obj_free(anode); +    dtr_map_sort(s->aliases, 0); +} + +void _dtr_read_symbols(dtr *s) { +    gchar *dir_path; +    GDir *dir; +    const gchar *fn; +    dtr_obj *anode, *prop; +    dtr_map *al; +    anode = dtr_obj_read(s, "/__symbols__"); + +    dir_path = g_strdup_printf("%s/__symbols__", s->base_path); +    dir = g_dir_open(dir_path, 0 , NULL); +    if (dir) { +        while((fn = g_dir_read_name(dir)) != NULL) { +            prop = dtr_get_prop_obj(s, anode, fn); +            if (prop->type == DTP_STR) { +                if (*prop->data_str == '/') { +                    al = dtr_map_add(s->symbols, 0, prop->name, prop->data_str); +                    if (s->symbols == NULL) +                        s->symbols = al; +                } +            } +            dtr_obj_free(prop); +        } +    } +    g_dir_close(dir); +    g_free(dir_path); +    dtr_obj_free(anode); +    dtr_map_sort(s->symbols, 0); +} + +/* TODO: rewrite */ +void _dtr_map_phandles(dtr *s, char *np) { +    gchar *dir_path; +    gchar *ftmp, *ntmp, *ptmp; +    const gchar *fn; +    GDir *dir; +    dtr_obj *prop, *ph_prop; +    dtr_map *ph; +    uint32_t phandle; + +    if (np == NULL) np = ""; +    dir_path = g_strdup_printf("%s/%s", s->base_path, np); + +    prop = dtr_obj_read(s, 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 = dtr_obj_read(s, ptmp); +                if (ph_prop != NULL) { +                    ph = dtr_map_add(s->phandles, be32toh(*ph_prop->data_int), NULL, ntmp); +                    if (s->phandles == NULL) +                        s->phandles = ph; +                } +                _dtr_map_phandles(s, ntmp); +                g_free(ptmp); +                g_free(ntmp); +                dtr_obj_free(ph_prop); +            } +            g_free(ftmp); +        } +    } +    g_dir_close(dir); +    dtr_obj_free(prop); +    dtr_map_sort(s->phandles, 1); +} + +/* + * Maybe these should move to devicetree.c, but would have to expose + * struct internals. + */ + +/* kvl: 0 = key is label, 1 = key is v */ +char *dtr_map_info_section(dtr *s, dtr_map *map, char *title, int kvl) { +    gchar *tmp, *ret; +    const gchar *sym; +    ret = g_strdup_printf("[%s]\n", _(title)); +    dtr_map *it = map; +    while(it != NULL) { +        if (kvl) { +            sym = dtr_symbol_lookup_by_path(s, it->path); +            if (sym != NULL) +                tmp = g_strdup_printf("%s0x%x (%s)=%s\n", ret, +                    it->v, sym, it->path); +            else +                tmp = g_strdup_printf("%s0x%x=%s\n", ret, +                    it->v, it->path); +        } else +            tmp = g_strdup_printf("%s%s=%s\n", ret, +                it->label, it->path); +        g_free(ret); +        ret = tmp; +        it = it->next; +    } + +    return ret; +} + +char *dtr_maps_info(dtr *s) { +    gchar *ph_map, *al_map, *sy_map, *ret; + +    ph_map = dtr_map_info_section(s, s->phandles, _("phandle Map"), 1); +    al_map = dtr_map_info_section(s, s->aliases, _("Alias Map"), 0); +    sy_map = dtr_map_info_section(s, s->symbols, _("Symbol Map"), 0); +    ret = g_strdup_printf("%s%s%s", ph_map, sy_map, al_map); +    g_free(ph_map); +    g_free(al_map); +    g_free(sy_map); +    return ret; +} + +char *appf(char *src, char *fmt, ...) { +    gchar *buf, *ret; +    va_list args; + +    va_start(args, fmt); +    buf = g_strdup_vprintf(fmt, args); +    va_end(args); + +    if (src != NULL) { +        ret = g_strdup_printf("%s%s%s", src, sp_sep(src), buf); +        g_free(buf); +        g_free(src); +    } else +        ret = buf; + +    return ret; +} + diff --git a/modules/devices/devicetree/pmac_data.c b/modules/devices/devicetree/pmac_data.c new file mode 100644 index 00000000..b236aef1 --- /dev/null +++ b/modules/devices/devicetree/pmac_data.c @@ -0,0 +1,98 @@ +/* + *    HardInfo - Displays System Information + *    Copyright (C) 2003-2007 Leandro A. F. Pereira <leandro@hardinfo.org> + * + *    This program is free software; you can redistribute it and/or modify + *    it under the terms of the GNU General Public License as published by + *    the Free Software Foundation, version 2. + * + *    This program is distributed in the hope that it will be useful, + *    but WITHOUT ANY WARRANTY; without even the implied warranty of + *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *    GNU General Public License for more details. + * + *    You should have received a copy of the GNU General Public License + *    along with this program; if not, write to the Free Software + *    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA + */ + +#include "cpu_util.h" /* for PROC_CPUINFO */ + +static gchar *ppc_mac_details(void) { +    int i = 0; +    gchar *ret = NULL; +    gchar *platform = NULL; +    gchar *model = NULL; +    gchar *machine = NULL; +    gchar *motherboard = NULL; +    gchar *detected_as = NULL; +    gchar *pmac_flags = NULL; +    gchar *l2_cache = NULL; +    gchar *pmac_gen = NULL; + +    FILE *cpuinfo; +    gchar buffer[128]; + +    cpuinfo = fopen(PROC_CPUINFO, "r"); +    if (!cpuinfo) +        return NULL; +    while (fgets(buffer, 128, cpuinfo)) { +        gchar **tmp = g_strsplit(buffer, ":", 2); +        if (tmp[1] == NULL) { +            g_strfreev(tmp); +            continue; +        } +        tmp[0] = g_strstrip(tmp[0]); +        tmp[1] = g_strstrip(tmp[1]); +        get_str("platform", platform); +        get_str("model", model); +        get_str("machine", machine); +        get_str("motherboard", motherboard); +        get_str("detected as", detected_as); +        get_str("pmac flags", pmac_flags); +        get_str("L2 cache", l2_cache); +        get_str("pmac-generation", pmac_gen); +    } +    fclose(cpuinfo); + +    if (machine == NULL) +        goto pmd_exit; + +    UNKIFNULL(platform); +    UNKIFNULL(model); +    UNKIFNULL(motherboard); +    UNKIFNULL(detected_as); +    UNKIFNULL(pmac_flags); +    UNKIFNULL(l2_cache); +    UNKIFNULL(pmac_gen); + +    ret = g_strdup_printf("[%s]\n" +                "%s=%s\n" +                "%s=%s\n" +                "%s=%s\n" +                "%s=%s\n" +                "%s=%s\n" +                "%s=%s\n" +                "%s=%s\n" +                "%s=%s\n", +                _("Apple Power Macintosh"), +                _("Platform"), platform, +                _("Model"), model, +                _("Machine"), machine, +                _("Motherboard"), motherboard, +                _("Detected as"), detected_as, +                _("PMAC Flags"), pmac_flags, +                _("L2 Cache"), l2_cache, +                _("PMAC Generation"), pmac_gen ); + +pmd_exit: +    g_free(platform); +    g_free(model); +    g_free(machine); +    g_free(motherboard); +    g_free(detected_as); +    g_free(pmac_flags); +    g_free(l2_cache); +    g_free(pmac_gen); +    return ret; +} diff --git a/modules/devices/devicetree/rpi_data.c b/modules/devices/devicetree/rpi_data.c new file mode 100644 index 00000000..d0132e3a --- /dev/null +++ b/modules/devices/devicetree/rpi_data.c @@ -0,0 +1,166 @@ +/* + *    HardInfo - Displays System Information + *    Copyright (C) 2003-2007 Leandro A. F. Pereira <leandro@hardinfo.org> + *    This file from: rpiz - https://github.com/bp0/rpiz + *    Copyright (C) 2017  Burt P. <pburt0@gmail.com> + * + *    This program is free software; you can redistribute it and/or modify + *    it under the terms of the GNU General Public License as published by + *    the Free Software Foundation, version 2. + * + *    This program is distributed in the hope that it will be useful, + *    but WITHOUT ANY WARRANTY; without even the implied warranty of + *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *    GNU General Public License for more details. + * + *    You should have received a copy of the GNU General Public License + *    along with this program; if not, write to the Free Software + *    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA + */ + +static char unk[] = "(Unknown)"; + +/* information table from: http://elinux.org/RPi_HardwareHistory */ +static struct { +    char *value, *intro, *model, *pcb, *mem, *mfg, *soc; +} rpi_boardinfo[] = { +/*  Value        Introduction  Model Name             PCB rev.  Memory(spec)   Manufacturer  SOC(spec) * + *                             Raspberry Pi %s                                                         */ +  { unk,         unk,          unk,                   unk,      unk,        unk,             NULL }, +  { "Beta",      "Q1 2012",    "B (Beta)",            unk,      "256MB",    "(Beta board)",  NULL }, +  { "0002",      "Q1 2012",    "B",                   "1.0",    "256MB",    unk,             "BCM2835" }, +  { "0003",      "Q3 2012",    "B (ECN0001)",         "1.0",    "256MB",    "(Fuses mod and D14 removed)",   NULL }, +  { "0004",      "Q3 2012",    "B",                   "2.0",    "256MB",    "Sony",          NULL }, +  { "0005",      "Q4 2012",    "B",                   "2.0",    "256MB",    "Qisda",         NULL }, +  { "0006",      "Q4 2012",    "B",                   "2.0",    "256MB",    "Egoman",        NULL }, +  { "0007",      "Q1 2013",    "A",                   "2.0",    "256MB",    "Egoman",        NULL }, +  { "0008",      "Q1 2013",    "A",                   "2.0",    "256MB",    "Sony",          NULL }, +  { "0009",      "Q1 2013",    "A",                   "2.0",    "256MB",    "Qisda",         NULL }, +  { "000d",      "Q4 2012",    "B",                   "2.0",    "512MB",    "Egoman",        NULL }, +  { "000e",      "Q4 2012",    "B",                   "2.0",    "512MB",    "Sony",          NULL }, +  { "000f",      "Q4 2012",    "B",                   "2.0",    "512MB",    "Qisda",         NULL }, +  { "0010",      "Q3 2014",    "B+",                  "1.0",    "512MB",    "Sony",          NULL }, +  { "0011",      "Q2 2014",    "Compute Module 1",    "1.0",    "512MB",    "Sony",          NULL }, +  { "0012",      "Q4 2014",    "A+",                  "1.1",    "256MB",    "Sony",          NULL }, +  { "0013",      "Q1 2015",    "B+",                  "1.2",    "512MB",    unk,             NULL }, +  { "0014",      "Q2 2014",    "Compute Module 1",    "1.0",    "512MB",    "Embest",        NULL }, +  { "0015",      unk,          "A+",                  "1.1",    "256MB/512MB",    "Embest",      NULL  }, +  { "a01040",    unk,          "2 Model B",           "1.0",    "1GB",      "Sony",          "BCM2836" }, +  { "a01041",    "Q1 2015",    "2 Model B",           "1.1",    "1GB",      "Sony",          "BCM2836" }, +  { "a21041",    "Q1 2015",    "2 Model B",           "1.1",    "1GB",      "Embest",        "BCM2836" }, +  { "a22042",    "Q3 2016",    "2 Model B",           "1.2",    "1GB",      "Embest",        "BCM2837" },  /* (with BCM2837) */ +  { "900021",    "Q3 2016",    "A+",                  "1.1",    "512MB",    "Sony",          NULL }, +  { "900032",    "Q2 2016?",    "B+",                 "1.2",    "512MB",    "Sony",          NULL }, +  { "900092",    "Q4 2015",    "Zero",                "1.2",    "512MB",    "Sony",          NULL }, +  { "900093",    "Q2 2016",    "Zero",                "1.3",    "512MB",    "Sony",          NULL }, +  { "920093",    "Q4 2016?",   "Zero",                "1.3",    "512MB",    "Embest",        NULL }, +  { "9000c1",    "Q1 2017",    "Zero W",              "1.1",    "512MB",    "Sony",          NULL }, +  { "a02082",    "Q1 2016",    "3 Model B",           "1.2",    "1GB",      "Sony",          "BCM2837" }, +  { "a020a0",    "Q1 2017",    "Compute Module 3 or CM3 Lite",  "1.0",    "1GB",    "Sony",          NULL }, +  { "a22082",    "Q1 2016",    "3 Model B",           "1.2",    "1GB",      "Embest",        "BCM2837" }, +  { "a32082",    "Q4 2016",    "3 Model B",           "1.2",    "1GB",      "Sony Japan",    NULL  }, +  { NULL, NULL, NULL, NULL, NULL, NULL, NULL } +}; + + +/* return number of chars to skip */ +static int rpi_ov_check(const char *r_code) { +    /* sources differ. prefix is either 1000... or just 1... */ +    //if (strncmp(r, "1000", 4) == 0) +    //    return 4; +    if (strncmp(r_code, "1", 1) == 0) +        return 1; +    return 0; +} + +static int rpi_code_match(const char* code0, const char* code1) { +    int c0, c1; +    if (code0 == NULL || code1 == NULL) return 0; +    c0 = strtol(code0, NULL, 16); +    c1 = strtol(code1, NULL, 16); +    if (c0 && c1) +        return (c0 == c1) ? 1 : 0; +    else +        return (strcmp(code0, code1) == 0) ? 1 : 0; +} + +static int rpi_find_board(const char *r_code) { +    int i = 0; +    char *r = (char*)r_code; +    if (r_code == NULL) +        return 0; +    /* ignore the overvolt prefix */ +    r += rpi_ov_check(r_code); +    while (rpi_boardinfo[i].value != NULL) { +        if (rpi_code_match(r, rpi_boardinfo[i].value)) +            return i; + +        i++; +    } +    return 0; +} + +/* ------------------------- */ + +#include "cpu_util.h" /* for PROC_CPUINFO */ + +static gchar *rpi_board_details(void) { +    int i = 0; +    gchar *ret = NULL; +    gchar *soc = NULL; +    gchar *serial = NULL; +    gchar *revision = NULL; +    int ov = 0; +    FILE *cpuinfo; +    gchar buffer[128]; + +    cpuinfo = fopen(PROC_CPUINFO, "r"); +    if (!cpuinfo) +        return NULL; +    while (fgets(buffer, 128, cpuinfo)) { +        gchar **tmp = g_strsplit(buffer, ":", 2); +        if (tmp[1] == NULL) { +            g_strfreev(tmp); +            continue; +        } +        tmp[0] = g_strstrip(tmp[0]); +        tmp[1] = g_strstrip(tmp[1]); +        get_str("Revision", revision); +        get_str("Hardware", soc); +        get_str("Serial", serial); +    } +    fclose(cpuinfo); + +    if (revision == NULL || soc == NULL) { +        g_free(soc); +        g_free(revision); +        return NULL; +    } + +    ov = rpi_ov_check(revision); +    i = rpi_find_board(revision); +    ret = g_strdup_printf("[%s]\n" +                "%s=%s %s\n" +                "%s=%s\n" +                "%s=%s\n" +                "%s=%s\n" +                "%s=%s\n" +                "%s=%s\n" +                "%s=%s\n" +                "%s=%s\n" +                "%s=%s\n", +                _("Raspberry Pi"), +                _("Board Name"), _("Raspberry Pi"), rpi_boardinfo[i].model, +                _("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, +                _("Permanent overvolt bit"), (ov) ? C_("rpi-ov-bit", "Set") : C_("rpi-ov-bit", "Not set") ); + +    g_free(soc); +    g_free(revision); +    return ret; +} diff --git a/modules/devices/devmemory.c b/modules/devices/devmemory.c index 7131536c..080e2bbe 100644 --- a/modules/devices/devmemory.c +++ b/modules/devices/devmemory.c @@ -23,10 +23,10 @@ GHashTable *memlabels = NULL;  void scan_memory_do(void)  { -    gchar **keys, *tmp; +    gchar **keys, *tmp, *tmp_label;      static gint offset = -1;      gint i; -     +      if (offset == -1) {          /* gah. linux 2.4 adds three lines of data we don't need in             /proc/meminfo */ @@ -38,38 +38,42 @@ void scan_memory_do(void)              offset = 0;          }      } -     +      g_file_get_contents("/proc/meminfo", &meminfo, NULL, NULL); -     +      keys = g_strsplit(meminfo, "\n", 0);      g_free(meminfo);      g_free(lginterval); -     +      meminfo = g_strdup("");      lginterval = g_strdup(""); -     +      for (i = offset; keys[i]; i++) {          gchar **newkeys = g_strsplit(keys[i], ":", 0); -         +          if (!newkeys[0]) {              g_strfreev(newkeys);              break;          } -         + +        g_strstrip(newkeys[0]);          g_strstrip(newkeys[1]); -         -        if ((tmp = g_hash_table_lookup(memlabels, newkeys[0]))) { -            g_free(newkeys[0]); -            newkeys[0] = g_strdup(tmp); -        } -         + +        /* try to find a localizable label */ +        tmp = g_hash_table_lookup(memlabels, newkeys[0]); +        if (tmp) +            tmp_label = _(tmp); +        else +            tmp_label = ""; /* or newkeys[0] */ +        /* although it doesn't matter... */ +          moreinfo_add_with_prefix("DEV", newkeys[0], g_strdup(newkeys[1])); -        tmp = g_strconcat(meminfo, newkeys[0], "=", newkeys[1], "\n", NULL); +        tmp = g_strconcat(meminfo, newkeys[0], "=", newkeys[1], "|", tmp_label, "\n", NULL);          g_free(meminfo);          meminfo = tmp; -         +          tmp = g_strconcat(lginterval,                            "UpdateInterval$", newkeys[0], "=1000\n", NULL);          g_free(lginterval); @@ -86,21 +90,21 @@ void init_memory_labels(void)          char *proc_label;          char *real_label;      } proc2real[] = { -        { "MemTotal", N_("Total Memory") }, -        { "MemFree", N_("Free Memory") }, -        { "SwapCached",	N_("Cached Swap") }, -        { "HighTotal", N_("High Memory") }, -        { "HighFree", N_("Free High Memory") }, -        { "LowTotal", N_("Low Memory") }, -        { "LowFree", N_("Free Low Memory") }, -        { "SwapTotal", N_("Virtual Memory") }, -        { "SwapFree", N_("Free Virtual Memory") }, +        { "MemTotal",   N_("Total Memory") }, +        { "MemFree",    N_("Free Memory") }, +        { "SwapCached", N_("Cached Swap") }, +        { "HighTotal",  N_("High Memory") }, +        { "HighFree",   N_("Free High Memory") }, +        { "LowTotal",   N_("Low Memory") }, +        { "LowFree",    N_("Free Low Memory") }, +        { "SwapTotal",  N_("Virtual Memory") }, +        { "SwapFree",   N_("Free Virtual Memory") },          { NULL },      };      gint i;      memlabels = g_hash_table_new(g_str_hash, g_str_equal); -     +      for (i = 0; proc2real[i].proc_label; i++) {          g_hash_table_insert(memlabels, proc2real[i].proc_label,              _(proc2real[i].real_label)); diff --git a/modules/devices/dmi.c b/modules/devices/dmi.c index 61cea65d..5f87df13 100644 --- a/modules/devices/dmi.c +++ b/modules/devices/dmi.c @@ -22,7 +22,7 @@  #include <sys/types.h>  #include "devices.h" -               +  typedef struct _DMIInfo		DMIInfo;  struct _DMIInfo { @@ -35,10 +35,14 @@ DMIInfo dmi_info_table[] = {    { "$BIOS",		NULL,					NULL },    { "Date",		"/sys/class/dmi/id/bios_date",		"bios-release-date" },    { "Vendor",		"/sys/class/dmi/id/bios_vendor",	"bios-vendor" }, -  { "Version",		"/sys/class/dmi/id/bios_version",	"bios-version" }, +  { "Version#0",	"/sys/class/dmi/id/bios_version",	"bios-version" },    { "$Board",		NULL,					NULL },    { "Name",		"/sys/class/dmi/id/board_name",		"baseboard-product-name" },    { "Vendor",		"/sys/class/dmi/id/board_vendor",	"baseboard-manufacturer" }, +  { "$Product",		NULL,					NULL }, +  { "Name",		"/sys/class/dmi/id/product_name",	"system-product-name" }, +  { "Family",		"/sys/class/dmi/id/product_family",     "system-product-family" }, +  { "Version#1",	"/sys/class/dmi/id/product_version",    "system-product-version" },  };  gchar *dmi_info = NULL; @@ -62,16 +66,16 @@ gboolean dmi_get_info_dmidecode()      g_free(dmi_info);      dmi_info = NULL;    } -   +    for (i = 0; i < G_N_ELEMENTS(dmi_info_table); i++) {      info = &dmi_info_table[i]; -     +      if (*(info->name) == '$') {        group = info->name + 1;        dmi_info = h_strdup_cprintf("[%s]\n", dmi_info, group);      } else {        gchar *temp; -       +        if (!info->param)          continue; @@ -84,7 +88,7 @@ gboolean dmi_get_info_dmidecode()            dmi_failed = TRUE;            break;          } -         +          add_to_moreinfo(group, info->name, buffer);          const gchar *url = vendor_get_url(buffer); @@ -115,14 +119,14 @@ gboolean dmi_get_info_dmidecode()          dmi_failed = TRUE;          break;        } -    }                                 +    }    } -   +    if (dmi_failed) {      g_free(dmi_info);      dmi_info = NULL;    } -   +    return !dmi_failed;  } @@ -132,17 +136,17 @@ gboolean dmi_get_info_sys()    gchar buffer[256];    const gchar *group = NULL;    DMIInfo *info; -  gboolean dmi_failed = FALSE; +  gboolean dmi_succeeded = FALSE;    gint i; -   +    if (dmi_info) {      g_free(dmi_info);      dmi_info = NULL;    } -   +    for (i = 0; i < G_N_ELEMENTS(dmi_info_table); i++) {      info = &dmi_info_table[i]; -     +      if (*(info->name) == '$') {        group = info->name + 1;        dmi_info = h_strdup_cprintf("[%s]\n", dmi_info, group); @@ -152,7 +156,7 @@ gboolean dmi_get_info_sys()          fclose(dmi_file);          add_to_moreinfo(group, info->name, buffer); -         +          const gchar *url = vendor_get_url(buffer);          if (url) {            const gchar *vendor = vendor_get_name(buffer); @@ -176,31 +180,34 @@ gboolean dmi_get_info_sys()                                        info->name,                                        g_strstrip(buffer));          } +        dmi_succeeded = TRUE;        } else { -        dmi_failed = TRUE; -        break; +        dmi_info = h_strdup_cprintf("%s=%s\n", +                                    dmi_info, +                                    info->name, +                                    _("(Not available; Perhaps try running HardInfo as root.)") );        } -    }                                 +    }    } -   -  if (dmi_failed) { + +  if (!dmi_succeeded) {      g_free(dmi_info);      dmi_info = NULL;    } -   -  return !dmi_failed; + +  return dmi_succeeded;  }  void __scan_dmi()  {    gboolean dmi_ok; -   +    dmi_ok = dmi_get_info_sys(); -   +    if (!dmi_ok) {      dmi_ok = dmi_get_info_dmidecode();    } -   +    if (!dmi_ok) {      dmi_info = g_strdup("[No DMI information]\n"                          "There was an error retrieving the information.=\n" diff --git a/modules/devices/ia64/processor.c b/modules/devices/ia64/processor.c index 55e5e3a8..c4d06a71 100644 --- a/modules/devices/ia64/processor.c +++ b/modules/devices/ia64/processor.c @@ -18,61 +18,198 @@  #include "hardinfo.h"  #include "devices.h" +#include "cpu_util.h"  GSList *  processor_scan(void)  { -    Processor *processor; +    GSList *procs = NULL; +    Processor *processor = NULL;      FILE *cpuinfo;      gchar buffer[128]; +    gchar *rep_pname = NULL; +    GSList *pi = NULL; -    cpuinfo = fopen("/proc/cpuinfo", "r"); +    cpuinfo = fopen(PROC_CPUINFO, "r");      if (!cpuinfo) -	return NULL; +        return NULL; -    processor = g_new0(Processor, 1); +#define CHECK_FOR(k) (g_str_has_prefix(tmp[0], k))      while (fgets(buffer, 128, cpuinfo)) { -	gchar **tmp = g_strsplit(buffer, ":", 2); +        gchar **tmp = g_strsplit(buffer, ":", 2); +        if (tmp[0] && tmp[1]) { +            tmp[0] = g_strstrip(tmp[0]); +            tmp[1] = g_strstrip(tmp[1]); +        } else { +            g_strfreev(tmp); +            continue; +        } + +        get_str("Processor", rep_pname); + +        if ( CHECK_FOR("processor") ) { +            /* finish previous */ +            if (processor) { +                procs = g_slist_append(procs, processor); +            } + +            /* start next */ +            processor = g_new0(Processor, 1); +            processor->id = atol(tmp[1]); + +            if (rep_pname) +                processor->model_name = g_strdup(rep_pname); -	if (tmp[0] && tmp[1]) { -	    tmp[0] = g_strstrip(tmp[0]); -	    tmp[1] = g_strstrip(tmp[1]); +            g_strfreev(tmp); +            continue; +        } -	    get_str("vendor", processor->model_name); -	    get_str("arch", processor->vendor_id); -	    get_str("family", processor->strmodel); -	    get_float("BogoMIPS", processor->bogomips); +        if (!processor && +            (  CHECK_FOR("vendor") +            || CHECK_FOR("arch") +            || CHECK_FOR("family") ) ) { -	} -	g_strfreev(tmp); +            /* single proc/core may not have "processor : n" */ +            processor = g_new0(Processor, 1); +            processor->id = 0; + +            if (rep_pname) +                processor->model_name = g_strdup(rep_pname); +        } + +        if (processor) { +            get_str("vendor", processor->vendor_id); +            get_str("archrev", processor->archrev); +            get_str("arch", processor->arch); +            get_str("family", processor->family); +            get_str("features", processor->features); +            get_int("model", processor->model); +            get_int("revision", processor->revision); +            get_float("BogoMIPS", processor->bogomips); +            get_float("cpu MHz", processor->cpu_mhz); +            get_int("cpu regs", processor->cpu_regs); +        } +        g_strfreev(tmp);      } -    processor->cpu_mhz = 0.0f; -     +    if (processor) +        procs = g_slist_append(procs, processor); + +    g_free(rep_pname);      fclose(cpuinfo); -    return g_slist_append(NULL, processor); +    /* TODO: redup */ + +    /* data not from /proc/cpuinfo */ +    for (pi = procs; pi; pi = pi->next) { +        processor = (Processor *) pi->data; + +        /* strings can't be null or segfault later */ +        STRIFNULL(processor->model_name, _("IA64 Processor") ); +        UNKIFNULL(processor->vendor_id); +        STRIFNULL(processor->arch, "IA-64"); +        STRIFNULL(processor->archrev, "0"); +        UNKIFNULL(processor->family); +        UNKIFNULL(processor->features); + +        /* topo & freq */ +        processor->cpufreq = cpufreq_new(processor->id); +        processor->cputopo = cputopo_new(processor->id); + +        if (processor->cpufreq->cpukhz_max) +            processor->cpu_mhz = processor->cpufreq->cpukhz_max / 1000; + +    } + +    return procs; +} + +gchar *processor_name(GSList * processors) { +    return processor_name_default(processors); +} + +gchar *processor_describe(GSList * processors) { +    return processor_describe_default(processors);  }  gchar * -processor_get_info(GSList *processors) +processor_get_detailed_info(Processor *processor)  { -        Processor *processor = (Processor *)processors->data; -         -	return g_strdup_printf("[Processor]\n" -                               "Model=%s\n" -	                       "Architecture=%s\n" -	                       "Family=%sMHz\n" -			       "BogoMIPS=%s\n" -	                       "Byte Order=%s\n", -			       processor->model_name, -			       processor->vendor_id, -			       processor->strmodel, -			       processor->bogomips, -#if G_BYTE_ORDER == G_LITTLE_ENDIAN -                               "Little Endian" -#else -                               "Big Endian" -#endif -                              ); +    gchar *tmp_cpufreq, *tmp_topology, *ret; + +    tmp_topology = cputopo_section_str(processor->cputopo); +    tmp_cpufreq = cpufreq_section_str(processor->cpufreq); + +    ret = g_strdup_printf("[%s]\n" +                        "%s=%s\n"      /* name */ +                        "%s=%s\n"      /* vendor */ +                        "%s=%s\n"      /* arch */ +                        "%s=%s\n"      /* archrev */ +                        "%s=%s\n"      /* family */ +                        "%s=%d\n"      /* model no. */ +                        "%s=%d\n"      /* revision */ +                        "%s=%.2f %s\n" /* frequency */ +                        "%s=%.2f\n"    /* bogomips */ +                        "%s=%s\n"      /* byte order */ +                        "%s=%d\n"      /* regs */ +                        "%s=%s\n"      /* features */ +                        "%s" /* topology */ +                        "%s" /* frequency scaling */ +                        "%s",/* empty */ +                    _("Processor"), +                    _("Name"), processor->model_name, +                    _("Vendor"), processor->vendor_id, +                    _("Architecture"), processor->arch, +                    _("Architecture Revision"), processor->archrev, +                    _("Family"), processor->family, +                    _("Model"), processor->model, +                    _("Revision"), processor->revision, +                    _("Frequency"), processor->cpu_mhz, _("MHz"), +                    _("BogoMips"), processor->bogomips, +                    _("Byte Order"), byte_order_str(), +                    _("CPU regs"), processor->cpu_regs, +                    _("Features"), processor->features, +                    tmp_topology, +                    tmp_cpufreq, +                    ""); +    g_free(tmp_cpufreq); +    g_free(tmp_topology); +    return ret; +} + +gchar *processor_get_info(GSList * processors) +{ +    Processor *processor; + +    if (g_slist_length(processors) > 1) { +    gchar *ret, *tmp, *hashkey; +    GSList *l; + +    tmp = g_strdup(""); + +    for (l = processors; l; l = l->next) { +        processor = (Processor *) l->data; + +        tmp = g_strdup_printf("%s$CPU%d$%s=%.2f %s\n", +                  tmp, processor->id, +                  processor->model_name, +                  processor->cpu_mhz, _("MHz")); + +        hashkey = g_strdup_printf("CPU%d", processor->id); +        moreinfo_add_with_prefix("DEV", hashkey, +                processor_get_detailed_info(processor)); +           g_free(hashkey); +    } + +    ret = g_strdup_printf("[$ShellParam$]\n" +                  "ViewType=1\n" +                  "[Processors]\n" +                  "%s", tmp); +    g_free(tmp); + +    return ret; +    } + +    processor = (Processor *) processors->data; +    return processor_get_detailed_info(processor);  } diff --git a/modules/devices/inputdevices.c b/modules/devices/inputdevices.c index d3f8847f..cf1728a9 100644 --- a/modules/devices/inputdevices.c +++ b/modules/devices/inputdevices.c @@ -85,55 +85,55 @@ __scan_input_devices(void)  	    if (name && strstr(name, "PC Speaker")) {  	      d = 3;		// INPUT_PCSPKR  	    } -	 -	    tmp = g_strdup_printf("INP%d", ++n); -	    input_list = h_strdup_cprintf("$%s$%s=\n", -					 input_list, -					 tmp, name); -	    input_icons = h_strdup_cprintf("Icon$%s$%s=%s\n", -				 	  input_icons, -					  tmp, name, -					  input_devices[d].icon); -	    gchar *strhash = g_strdup_printf("[Device Information]\n" -					     "Name=%s\n" -					     "Type=%s\n" -					     "Bus=0x%x\n", -					     name, -					     input_devices[d].name, -					     bus); - -	    const gchar *url = vendor_get_url(name); -	    if (url) { -	    	strhash = h_strdup_cprintf("Vendor=%s (%s)\n", -					  strhash, -					  vendor_get_name(name), -					  url); -	    } else { -	    	strhash = h_strdup_cprintf("Vendor=%x\n", -					  strhash, -					  vendor); -	    } -	    strhash = h_strdup_cprintf("Product=0x%x\n" -				      "Version=0x%x\n", -				      strhash, product, version); -	     -            if (phys && phys[1] != 0) { -                 strhash = h_strdup_cprintf("Connected to=%s\n", -                                            strhash, phys); -            } - -	    if (phys && strstr(phys, "ir")) { -		 strhash = h_strdup_cprintf("InfraRed port=yes\n", -				 	     strhash); -	    } -	     -	    moreinfo_add_with_prefix("DEV", tmp, strhash); -	    g_free(tmp); +        tmp = g_strdup_printf("INP%d", ++n); +        input_list = h_strdup_cprintf("$%s$%s=\n", +                     input_list, +                     tmp, name); +        input_icons = h_strdup_cprintf("Icon$%s$%s=%s\n", +                      input_icons, +                      tmp, name, +                      input_devices[d].icon); + +        const gchar *v_url = (gchar*)vendor_get_url(name); +        const gchar *v_name = (gchar*)vendor_get_name(name); +        gchar *v_str = NULL; +        if (v_url != NULL) +            v_str = g_strdup_printf("[0x%x] %s (%s)", vendor, v_name, v_url); +        else +            v_str = g_strdup_printf("0x%x", vendor); +        v_str = hardinfo_clean_value(v_str, 1); +        name = hardinfo_clean_value(name, 1); + +        gchar *strhash = g_strdup_printf("[%s]\n" +                /* Name */   "%s=%s\n" +                /* Type */   "%s=%s\n" +                /* Bus */    "%s=0x%x\n" +                /* Vendor */ "%s=%s\n" +                /* Product */"%s=0x%x\n" +                /* Version */"%s=0x%x\n", +                        _("Device Information"), +                        _("Name"), name, +                        _("Type"), input_devices[d].name, +                        _("Bus"), bus, +                        _("Vendor"), v_str, +                        _("Product"), product, +                        _("Version"), version ); -	    g_free(phys); -	    g_free(name); -	} +        if (phys && phys[1] != 0) { +             strhash = h_strdup_cprintf("%s=%s\n", strhash, _("Connected to"), phys); +        } + +        if (phys && strstr(phys, "ir")) { +            strhash = h_strdup_cprintf("%s=%s\n", strhash, _("InfraRed port"), _("Yes") ); +        } + +        moreinfo_add_with_prefix("DEV", tmp, strhash); +        g_free(tmp); +        g_free(v_str); +        g_free(phys); +        g_free(name); +    }      }      fclose(dev); diff --git a/modules/devices/m68k/processor.c b/modules/devices/m68k/processor.c index d9902428..e030732a 100644 --- a/modules/devices/m68k/processor.c +++ b/modules/devices/m68k/processor.c @@ -18,6 +18,7 @@  #include "hardinfo.h"  #include "devices.h" +#include "cpu_util.h"  GSList *  processor_scan(void) @@ -26,54 +27,66 @@ processor_scan(void)      FILE *cpuinfo;      gchar buffer[128]; -    cpuinfo = fopen("/proc/cpuinfo", "r"); +    cpuinfo = fopen(PROC_CPUINFO, "r");      if (!cpuinfo) -	return NULL; +        return NULL;      processor = g_new0(Processor, 1);      while (fgets(buffer, 128, cpuinfo)) { -	gchar **tmp = g_strsplit(buffer, ":", 2); +        gchar **tmp = g_strsplit(buffer, ":", 2); -	if (tmp[0] && tmp[1]) { -	    tmp[0] = g_strstrip(tmp[0]); -	    tmp[1] = g_strstrip(tmp[1]); +        if (tmp[0] && tmp[1]) { +            tmp[0] = g_strstrip(tmp[0]); +            tmp[1] = g_strstrip(tmp[1]); -	    get_str("CPU", processor->model_name); -	    get_float("Clocking", processor->cpu_mhz); -	    get_float("bogomips", processor->bogomips); - -	    get_str("FPU", processor->has_fpu); -	} -	g_strfreev(tmp); +            get_str("CPU", processor->model_name); +            get_str("MMU", processor->mmu_name); +            get_str("FPU", processor->fpu_name); +            get_float("Clocking", processor->cpu_mhz); +            get_float("BogoMips", processor->bogomips); +            get_str("Calibration", processor->calibration); +        } +        g_strfreev(tmp);      } -     +      gchar *tmp;      tmp = g_strconcat("Motorola ", processor->model_name, NULL);      g_free(processor->model_name);      processor->model_name = tmp; -     +      fclose(cpuinfo);      return g_slist_append(NULL, processor);  } +gchar *processor_name(GSList * processors) { +    return processor_name_default(processors); +} + +gchar *processor_describe(GSList * processors) { +    return processor_describe_default(processors); +} +  gchar *  processor_get_info(GSList *processors)  { -        Processor *processor = (Processor *)processors->data; -         -	return g_strdup_printf("[Processor]\n" -	                       "Name=%s\n" -			       "Frequency=%.2fMHz\n" -			       "BogoMips=%.2f\n" -			       "Byte Order=%s\n", -			       processor->model_name, -			       processor->cpu_mhz, -			       processor->bogomips, -#if G_BYTE_ORDER == G_LITTLE_ENDIAN -                               "Little Endian" -#else -                               "Big Endian" -#endif -                               ); +    Processor *processor = (Processor *)processors->data; + +    return g_strdup_printf("[%s]\n" +                        "%s=%s\n"      /* cpu */ +                        "%s=%s\n"      /* mmu */ +                        "%s=%s\n"      /* fpu */ +                        "%s=%.2f %s\n" /* frequency */ +                        "%s=%.2f\n"    /* bogomips */ +                        "%s=%s\n"      /* byte order */ +                        "%s=%s\n",     /* calibration */ +                    _("Processor"), +                    _("Model"), processor->model_name, +                    _("MMU"), processor->mmu_name, +                    _("FPU"), processor->fpu_name, +                    _("Frequency"), processor->cpu_mhz, _("MHz"), +                    _("BogoMips"), processor->bogomips, +                    _("Byte Order"), byte_order_str(), +                    _("Calibration"), processor->calibration +                        );  } diff --git a/modules/devices/mips/processor.c b/modules/devices/mips/processor.c index 86c9b958..b31af7dd 100644 --- a/modules/devices/mips/processor.c +++ b/modules/devices/mips/processor.c @@ -18,6 +18,7 @@  #include "hardinfo.h"  #include "devices.h" +#include "cpu_util.h"  GSList *  processor_scan(void) @@ -26,24 +27,24 @@ processor_scan(void)      FILE *cpuinfo;      gchar buffer[128]; -    cpuinfo = fopen("/proc/cpuinfo", "r"); +    cpuinfo = fopen(PROC_CPUINFO, "r");      if (!cpuinfo) -	return NULL; +        return NULL;      processor = g_new0(Processor, 1);      while (fgets(buffer, 128, cpuinfo)) { -	gchar **tmp = g_strsplit(buffer, ":", 2); +        gchar **tmp = g_strsplit(buffer, ":", 2); -	if (tmp[0] && tmp[1]) { -	    tmp[0] = g_strstrip(tmp[0]); -	    tmp[1] = g_strstrip(tmp[1]); +        if (tmp[0] && tmp[1]) { +            tmp[0] = g_strstrip(tmp[0]); +            tmp[1] = g_strstrip(tmp[1]); -	    get_str("system type", processor->model_name); -	    get_str("cpu model", processor->vendor_id); -	    get_float("cpu MHz", processor->cpu_mhz); -	    get_float("BogoMIPS", processor->bogomips); -	} -	g_strfreev(tmp); +            get_str("system type", processor->vendor_id); +            get_str("cpu model", processor->model_name); +            get_float("cpu MHz", processor->cpu_mhz); +            get_float("BogoMIPS", processor->bogomips); +        } +        g_strfreev(tmp);      }      fclose(cpuinfo); @@ -51,25 +52,30 @@ processor_scan(void)      return g_slist_append(NULL, processor);  } +gchar *processor_name(GSList * processors) { +    return processor_name_default(processors); +} + +gchar *processor_describe(GSList * processors) { +    return processor_describe_default(processors); +} +  gchar *  processor_get_info(GSList *processors)  { -        Processor *processor = (Processor *)processors->data; -         -	return g_strdup_printf("[Processor]\n" -	                       "System Type=%s\n" -	                       "CPU Model=%s\n" -                               "Frequency=%.2fMHz\n" -			       "BogoMIPS=%.2f\n" -			       "Byte Order=%s\n", -			       processor->model_name, -			       processor->vendor_id, -			       processor->cpu_mhz, -			       processor->bogomips, -#if G_BYTE_ORDER == G_LITTLE_ENDIAN -                               "Little Endian" -#else -                               "Big Endian" -#endif -			       ); +    Processor *processor = (Processor *)processors->data; + +    return g_strdup_printf("[%s]\n" +                        "%s=%s\n" +                        "%s=%s\n" +                        "%s=%.2f %s\n" /* frequency */ +                        "%s=%.2f\n"    /* bogomips */ +                        "%s=%s\n",     /* byte order */ +                    _("Processor"), +                    _("Model"), processor->model_name, +                    _("System Type"), processor->vendor_id, +                    _("Frequency"), processor->cpu_mhz, _("MHz"), +                    _("BogoMips"), processor->bogomips, +                    _("Byte Order"), byte_order_str() +                   );  } diff --git a/modules/devices/parisc/processor.c b/modules/devices/parisc/processor.c index 83672126..9ca38d12 100644 --- a/modules/devices/parisc/processor.c +++ b/modules/devices/parisc/processor.c @@ -18,70 +18,193 @@  #include "hardinfo.h"  #include "devices.h" +#include "cpu_util.h"  GSList * -processors_scan(void) +processor_scan(void)  { -    Processor *processor; +    GSList *procs = NULL; +    Processor *processor = NULL;      FILE *cpuinfo;      gchar buffer[128]; +    gchar *rep_pname = NULL; +    GSList *pi = NULL; -    cpuinfo = fopen("/proc/cpuinfo", "r"); +    cpuinfo = fopen(PROC_CPUINFO, "r");      if (!cpuinfo) -	return NULL; +        return NULL; -    processor = g_new0(Processor, 1); +#define CHECK_FOR(k) (g_str_has_prefix(tmp[0], k))      while (fgets(buffer, 128, cpuinfo)) { -	gchar **tmp = g_strsplit(buffer, ":", 2); - -	if (tmp[0] && tmp[1]) { -	    tmp[0] = g_strstrip(tmp[0]); -	    tmp[1] = g_strstrip(tmp[1]); - -	    get_str("cpu family", processor->model_name); -	    get_str("cpu", processor->vendor_id); -	    get_float("cpu MHz", processor->cpu_mhz); -	    get_float("bogomips", processor->bogomips); -	     -	    get_str("model name", processor->strmodel); -	     -	    get_int("I-cache", processor->has_fpu); -	    get_int("D-cache", processor->flags); - -	} -	g_strfreev(tmp); +        gchar **tmp = g_strsplit(buffer, ":", 2); +        if (tmp[0] && tmp[1]) { +            tmp[0] = g_strstrip(tmp[0]); +            tmp[1] = g_strstrip(tmp[1]); +        } else { +            g_strfreev(tmp); +            continue; +        } + +        get_str("Processor", rep_pname); + +        if ( CHECK_FOR("processor") ) { +            /* finish previous */ +            if (processor) { +                procs = g_slist_append(procs, processor); +            } + +            /* start next */ +            processor = g_new0(Processor, 1); +            processor->id = atol(tmp[1]); + +            if (rep_pname) +                processor->model_name = g_strdup(rep_pname); + +            g_strfreev(tmp); +            continue; +        } + +        if (!processor && +            (  CHECK_FOR("cpu family") +            || CHECK_FOR("cpu MHz") +            || CHECK_FOR("cpu") ) ) { + +            /* single proc/core may not have "processor : n" */ +            processor = g_new0(Processor, 1); +            processor->id = 0; + +            if (rep_pname) +                processor->model_name = g_strdup(rep_pname); +        } + +        if (processor) { +            get_str("cpu family", processor->cpu_family); +            get_float("cpu MHz", processor->cpu_mhz); +            get_str("cpu", processor->model_name); +            get_float("bogomips", processor->bogomips); +            get_str("model name", processor->strmodel); +            get_str("I-cache", processor->icache_str); +            get_str("D-cache", processor->dcache_str); +            get_str("hversion", processor->hversion); +            get_str("sversion", processor->sversion); +        } +        g_strfreev(tmp);      } +    if (processor) +        procs = g_slist_append(procs, processor); + +    g_free(rep_pname);      fclose(cpuinfo); -    return g_slist_append(NULL, processor); +    /* TODO: redup */ + +    /* data not from /proc/cpuinfo */ +    for (pi = procs; pi; pi = pi->next) { +        processor = (Processor *) pi->data; + +        /* strings can't be null or segfault later */ +        STRIFNULL(processor->model_name, _("PA-RISC Processor") ); +        STRIFNULL(processor->cpu_family, "PA-RISC"); +        UNKIFNULL(processor->strmodel); + +        /* topo & freq */ +        processor->cpufreq = cpufreq_new(processor->id); +        processor->cputopo = cputopo_new(processor->id); + +        if (processor->cpufreq->cpukhz_max) +            processor->cpu_mhz = processor->cpufreq->cpukhz_max / 1000; + +    } + +    return procs; +} + +gchar *processor_name(GSList * processors) { +    return processor_name_default(processors); +} + +gchar *processor_describe(GSList * processors) { +    return processor_describe_default(processors);  }  gchar * -processor_get_info(GSList *processors) +processor_get_detailed_info(Processor *processor) +{ +    gchar *tmp_cpufreq, *tmp_topology, *ret; + +    tmp_topology = cputopo_section_str(processor->cputopo); +    tmp_cpufreq = cpufreq_section_str(processor->cpufreq); + +    ret = g_strdup_printf("[%s]\n" +                        "%s=%s\n" +                        "%s=%s\n" +                        "%s=%s\n"      /* model name */ +                        "%s=%.2f %s\n" /* frequency */ +                        "%s=%.2f\n"    /* bogomips */ +                        "%s=%s\n"      /* byte order */ +                        "%s=%s\n"      /* hversion */ +                        "%s=%s\n"      /* sversion */ +                        "[%s]\n" +                        "I-Cache=%s\n" +                        "D-Cache=%s\n" +                        "%s" /* topology */ +                        "%s" /* frequency scaling */ +                        "%s",/* empty */ +                   _("Processor"), +                   _("Model"), processor->model_name, +                   _("Architecture"), processor->cpu_family, +                   _("System"), processor->strmodel, +                   _("Frequency"), processor->cpu_mhz, _("MHz"), +                   _("BogoMips"), processor->bogomips, +                   _("Byte Order"), byte_order_str(), +                   _("HVersion"), processor->hversion, +                   _("SVersion"), processor->sversion, +                   _("Cache"), +                   processor->icache_str, +                   processor->dcache_str, +                   tmp_topology, +                   tmp_cpufreq, +                    ""); + +    g_free(tmp_cpufreq); +    g_free(tmp_topology); +    return ret; +} + +gchar *processor_get_info(GSList * processors)  { -        Processor *processor = (Processor *)processors->data; -         -	return  g_strdup_printf("[Processor]\n" -	                       "CPU Family=%s\n" -	                       "CPU=%s\n" -                               "Frequency=%.2fMHz\n" -			       "Bogomips=%.2f\n" -			       "Model Name=%s\n" -			       "Byte Order=%s\n" -			       "[Cache]\n" -			       "I-Cache=%s\n" -			       "D-Cache=%s\n", -			       processor->model_name, -			       processor->vendor_id, -			       processor->cpu_mhz, -			       processor->bogomips, -			       processor->strmodel, -#if G_BYTE_ORDER == G_LITTLE_ENDIAN -                               "Little Endian", -#else -                               "Big Endian", -#endif -			       processor->has_fpu, -			       processor->flags); +    Processor *processor; + +    if (g_slist_length(processors) > 1) { +    gchar *ret, *tmp, *hashkey; +    GSList *l; + +    tmp = g_strdup(""); + +    for (l = processors; l; l = l->next) { +        processor = (Processor *) l->data; + +        tmp = g_strdup_printf("%s$CPU%d$%s=%.2f %s\n", +                  tmp, processor->id, +                  processor->model_name, +                  processor->cpu_mhz, _("MHz")); + +        hashkey = g_strdup_printf("CPU%d", processor->id); +        moreinfo_add_with_prefix("DEV", hashkey, +                processor_get_detailed_info(processor)); +           g_free(hashkey); +    } + +    ret = g_strdup_printf("[$ShellParam$]\n" +                  "ViewType=1\n" +                  "[Processors]\n" +                  "%s", tmp); +    g_free(tmp); + +    return ret; +    } + +    processor = (Processor *) processors->data; +    return processor_get_detailed_info(processor);  } diff --git a/modules/devices/pci.c b/modules/devices/pci.c index 91ff914d..c1965a63 100644 --- a/modules/devices/pci.c +++ b/modules/devices/pci.c @@ -40,13 +40,13 @@ scan_pci_do(void)      gchar buffer[256], *buf, *strhash = NULL, *strdevice = NULL;      gchar *category = NULL, *name = NULL, *icon, *lspci_path, *command_line = NULL;      gint n = 0, x = 0; -     +      if ((lspci_path = find_program("lspci")) == NULL) {        goto pci_error;      } else {        command_line = g_strdup_printf("%s -v", lspci_path);      } -     +      if (!_pci_devices) {        _pci_devices = g_hash_table_new(g_str_hash, g_str_equal);      } @@ -60,11 +60,11 @@ scan_pci_do(void)        }      } else {        gchar *tmp; -       +        tmp = g_strdup_printf("%s -i '%s'", command_line, buf);        g_free(buf);        buf = tmp; -       +        DEBUG("using updated PCI IDs (from %s)", buf);        if (!(lspci = popen(tmp, "r"))) {          g_free(buf); @@ -103,30 +103,31 @@ scan_pci_do(void)  	    g_strfreev(list);  	    if (irq) -		strdevice = h_strdup_cprintf("IRQ=%d\n", strdevice, irq); +		strdevice = h_strdup_cprintf("%s=%d\n", strdevice, _("IRQ"), irq);  	    if (freq) -		strdevice = h_strdup_cprintf("Frequency=%dMHz\n", strdevice, freq); +		strdevice = h_strdup_cprintf("%s=%d %s\n", strdevice, _("Frequency"), freq, _("MHz") );  	    if (latency) -		strdevice = h_strdup_cprintf("Latency=%d\n", strdevice, latency); +		strdevice = h_strdup_cprintf("%s=%d\n", strdevice, _("Latency"), latency); -	    strdevice = h_strdup_cprintf("Bus Master=%s\n", strdevice, bus_master ? "Yes" : "No"); +	    strdevice = h_strdup_cprintf("%s=%s\n", strdevice, _("Bus Master"), bus_master ? _("Yes") : _("No") );  	} else if (!strncmp(buf, "Kernel modules", 14)) {  	    WALK_UNTIL(' ');  	    WALK_UNTIL(':');  	    buf++; -	     -	    strdevice = h_strdup_cprintf("Kernel modules=%s\n", strdevice, buf); + +	    strdevice = h_strdup_cprintf("%s=%s\n", strdevice, _("Kernel modules"), buf);  	} else if (!strncmp(buf, "Subsystem", 9)) {  	    WALK_UNTIL(' ');  	    buf++;  	    const gchar *oem_vendor_url = vendor_get_url(buf); -            if (oem_vendor_url)  -                strdevice = h_strdup_cprintf("OEM Vendor=%s (%s)\n", +            if (oem_vendor_url) +                strdevice = h_strdup_cprintf(_("%s=%s (%s)\n"),                                              strdevice, +                                            _("OEM Vendor"),                                              vendor_get_name(buf),                                              oem_vendor_url);  	} else if (!strncmp(buf, "Capabilities", 12) -		   && !strstr(buf, "only to root") &&  +		   && !strstr(buf, "only to root") &&  		      !strstr(buf, "access denied")) {  	    WALK_UNTIL(' ');  	    WALK_UNTIL(']'); @@ -144,13 +145,13 @@ scan_pci_do(void)  	    WALK_UNTIL('[');  	    sscanf(buf, "[size=%d%c", &mem, &unit); -	    strdevice = h_strdup_cprintf("Memory#%d=%d%cB (%s%s)\n", -					strdevice, ++x, +	    strdevice = h_strdup_cprintf("%s#%d=%d%cB (%s%s)\n", +					strdevice, _("Memory"), ++x,  					mem,  					(unit == ']') ? ' ' : unit,  					_32bit ? "32-bit, " : "", -					prefetch ? "prefetchable" : -					"non-prefetchable"); +					prefetch ? _("prefetchable") : +					_("non-prefetchable") );  	} else if (!strncmp(buf, "I/O ports at", 12)) {  	    guint io_addr, io_size; @@ -158,8 +159,8 @@ scan_pci_do(void)  	    sscanf(buf, "I/O ports at %x [size=%d]", &io_addr, &io_size);  	    strdevice = -		h_strdup_cprintf("I/O ports at#%d=0x%x - 0x%x\n", -				strdevice, ++x, io_addr, +		h_strdup_cprintf("%s#%d=0x%x - 0x%x\n", +				strdevice, _("I/O ports at"), ++x, io_addr,  				io_addr + io_size - 1);  	} else if ((buf[0] >= '0' && buf[0] <= '9') && (buf[4] == ':' || buf[2] == ':')) {  	    gint bus, device, function, domain; @@ -197,51 +198,57 @@ scan_pci_do(void)              else if (strstr(category, "Multimedia")) icon = "media";              else if (strstr(category, "USB")) icon = "usb";              else icon = "pci"; -             +  	    name = g_strdup(buf);              g_hash_table_insert(_pci_devices,                                  g_strdup_printf("0000:%02x:%02x.%x", bus, device, function),                                  name); -	    strhash = g_strdup_printf("PCI%d", n); -	    strdevice = g_strdup_printf("[Device Information]\n" -					"Name=%s\n" -					"Class=%s\n" -					"Domain=%d\n" -					"Bus, device, function=%d, %d, %d\n", -					name, category, domain, bus, -					device, function); -             +        strhash = g_strdup_printf("PCI%d", n); +        strdevice = g_strdup_printf("[%s]\n" +               /* Name */   "%s=%s\n" +               /* Class */  "%s=%s\n" +               /* Domain */ "%s=%d\n" +               /* Bus, device, function */ +                            "%s=%d, %d, %d\n", +                    _("Device Information"), +                    _("Name"), name, +                    _("Class"), category, +                    _("Domain"), domain, +                    _("Bus, device, function"), +                    bus, device, function); +              const gchar *url = vendor_get_url(name);              if (url) { -                strdevice = h_strdup_cprintf("Vendor=%s (%s)\n", +                strdevice = h_strdup_cprintf("%s=%s (%s)\n",                                              strdevice, +                                            _("Vendor"),                                              vendor_get_name(name),                                              url);              } -             +              g_hash_table_insert(_pci_devices,                                  g_strdup_printf("0000:%02x:%02x.%x", bus, device, function),                                  g_strdup(name)); -             +  	    pci_list = h_strdup_cprintf("$PCI%d$%s=%s\n", pci_list, n, category, name);  	    n++;  	}      } -     +      if (pclose(lspci)) {  pci_error:          /* error (no pci, perhaps?) */ -        pci_list = g_strconcat(pci_list, "No PCI devices found=\n", NULL); +        pci_list = g_strconcat(pci_list, _("No PCI devices found"), "=\n", NULL);      } else if (strhash) { -	/* insert the last device */ +        /* insert the last device */          moreinfo_add_with_prefix("DEV", strhash, strdevice);          g_free(strhash);          g_free(category);          g_free(name);      } -     +      g_free(lspci_path);      g_free(command_line);  } diff --git a/modules/devices/ppc/processor.c b/modules/devices/ppc/processor.c index a7988f97..3360a136 100644 --- a/modules/devices/ppc/processor.c +++ b/modules/devices/ppc/processor.c @@ -18,68 +18,189 @@  #include "hardinfo.h"  #include "devices.h" +#include "cpu_util.h"  GSList *  processor_scan(void)  { -    Processor *processor; +    GSList *procs = NULL; +    Processor *processor = NULL;      FILE *cpuinfo;      gchar buffer[128]; +    gchar *rep_pname = NULL; +    GSList *pi = NULL; -    cpuinfo = fopen("/proc/cpuinfo", "r"); +    cpuinfo = fopen(PROC_CPUINFO, "r");      if (!cpuinfo) -	return NULL; +    return NULL; -    processor = g_new0(Processor, 1); +#define CHECK_FOR(k) (g_str_has_prefix(tmp[0], k))      while (fgets(buffer, 128, cpuinfo)) { -	gchar **tmp = g_strsplit(buffer, ":", 2); +        gchar **tmp = g_strsplit(buffer, ":", 2); +        if (tmp[0] && tmp[1]) { +            tmp[0] = g_strstrip(tmp[0]); +            tmp[1] = g_strstrip(tmp[1]); +        } else { +            g_strfreev(tmp); +            continue; +        } + +        get_str("Processor", rep_pname); + +        if ( CHECK_FOR("processor") ) { +            /* finish previous */ +            if (processor) { +                procs = g_slist_append(procs, processor); +            } + +            /* start next */ +            processor = g_new0(Processor, 1); +            processor->id = atol(tmp[1]); + +            if (rep_pname) +                processor->model_name = g_strdup(rep_pname); -	if (tmp[0] && tmp[1]) { -	    tmp[0] = g_strstrip(tmp[0]); -	    tmp[1] = g_strstrip(tmp[1]); +            g_strfreev(tmp); +            continue; +        } -	    get_str("cpu", processor->model_name); -	    get_str("machine", processor->vendor_id); -	    get_int("L2 cache", processor->cache_size); -	    get_float("clock", processor->cpu_mhz); -	    get_float("bogomips", processor->bogomips); +        if (!processor && +            (  CHECK_FOR("cpu") +            || CHECK_FOR("clock") +            || CHECK_FOR("revision") ) ) { -	} -	g_strfreev(tmp); +            /* single proc/core may not have "processor : n" */ +            processor = g_new0(Processor, 1); +            processor->id = 0; + +            if (rep_pname) +                processor->model_name = g_strdup(rep_pname); +        } + +        if (processor) { +            get_str("cpu", processor->model_name); +            get_str("revision", processor->revision); +            get_float("clock", processor->cpu_mhz); +            get_float("BogoMIPS", processor->bogomips); +        } +        g_strfreev(tmp);      } -     -    gchar *tmp = g_strdup_printf("PowerPC %s (%.2fMHz)", -                                 processor->model_name, -                                 processor->cpu_mhz); -    g_free(processor->model_name); -    processor->model_name = tmp; +    if (processor) +        procs = g_slist_append(procs, processor); + +    g_free(rep_pname);      fclose(cpuinfo); -    return g_slist_append(NULL, processor); +    /* re-duplicate missing data for /proc/cpuinfo variant that de-duplicated it */ +#define REDUP(f) if (dproc->f && !processor->f) processor->f = g_strdup(dproc->f); +    Processor *dproc; +    GSList *l; +    l = procs = g_slist_reverse(procs); +    while (l) { +        processor = l->data; +        if (processor->model_name) { +            dproc = processor; +        } else if (dproc) { +            REDUP(model_name); +            REDUP(revision); +        } +        l = g_slist_next(l); +    } +    procs = g_slist_reverse(procs); + +    /* data not from /proc/cpuinfo */ +    for (pi = procs; pi; pi = pi->next) { +        processor = (Processor *) pi->data; + +        /* strings can't be null or segfault later */ +        STRIFNULL(processor->model_name, _("POWER Processor") ); +        UNKIFNULL(processor->revision); + +        /* topo & freq */ +        processor->cpufreq = cpufreq_new(processor->id); +        processor->cputopo = cputopo_new(processor->id); + +        if (processor->cpufreq->cpukhz_max) +            processor->cpu_mhz = processor->cpufreq->cpukhz_max / 1000; + +    } + +    return procs; +} + +gchar *processor_name(GSList * processors) { +    return processor_name_default(processors); +} + +gchar *processor_describe(GSList * processors) { +    return processor_describe_default(processors);  }  gchar * -processor_get_info(GSList *processors) +processor_get_detailed_info(Processor *processor)  { -        Processor *processor = (Processor *)processors->data; -         -	return g_strdup_printf("[Processor]\n" -	                       "Machine=%s\n" -	                       "CPU=%s\n" -	                       "L2 Cache=%dkB\n" -	                       "Frequency=%.2fMHz\n" -	                       "BogoMips=%.2f\n" -	                       "Byte Order=%s\n", -			       processor->vendor_id, -			       processor->model_name, -			       processor->cache_size, -			       processor->cpu_mhz, -			       processor->bogomips, -#if G_BYTE_ORDER == G_LITTLE_ENDIAN -                               "Little Endian" -#else -                               "Big Endian" -#endif -                              ); +    gchar *tmp_cpufreq, *tmp_topology, *ret; + +    tmp_topology = cputopo_section_str(processor->cputopo); +    tmp_cpufreq = cpufreq_section_str(processor->cpufreq); + +    ret = g_strdup_printf("[%s]\n" +                   "%s=%s\n"  /* model */ +                   "%s=%s\n"  /* revision */ +                   "%s=%.2f %s\n" /* frequency */ +                   "%s=%.2f\n"    /* bogomips */ +                   "%s=%s\n"      /* byte order */ +                   "%s" /* topology */ +                   "%s" /* frequency scaling */ +                   "%s",/* empty */ +                   _("Processor"), +                   _("Model"), processor->model_name, +                   _("Revision"), processor->revision, +                   _("Frequency"), processor->cpu_mhz, _("MHz"), +                   _("BogoMips"), processor->bogomips, +                   _("Byte Order"), byte_order_str(), +                   tmp_topology, +                   tmp_cpufreq, +                    ""); +    g_free(tmp_cpufreq); +    g_free(tmp_topology); +    return ret; +} + +gchar *processor_get_info(GSList * processors) +{ +    Processor *processor; + +    if (g_slist_length(processors) > 1) { +    gchar *ret, *tmp, *hashkey; +    GSList *l; + +    tmp = g_strdup(""); + +    for (l = processors; l; l = l->next) { +        processor = (Processor *) l->data; + +        tmp = g_strdup_printf("%s$CPU%d$%s=%.2f %s\n", +                  tmp, processor->id, +                  processor->model_name, +                  processor->cpu_mhz, _("MHz")); + +        hashkey = g_strdup_printf("CPU%d", processor->id); +        moreinfo_add_with_prefix("DEV", hashkey, +                processor_get_detailed_info(processor)); +           g_free(hashkey); +    } + +    ret = g_strdup_printf("[$ShellParam$]\n" +                  "ViewType=1\n" +                  "[Processors]\n" +                  "%s", tmp); +    g_free(tmp); + +    return ret; +    } + +    processor = (Processor *) processors->data; +    return processor_get_detailed_info(processor);  } diff --git a/modules/devices/riscv/processor.c b/modules/devices/riscv/processor.c new file mode 100644 index 00000000..afddf89d --- /dev/null +++ b/modules/devices/riscv/processor.c @@ -0,0 +1,233 @@ +/* + *    HardInfo - Displays System Information + *    Copyright (C) 2003-2006 Leandro A. F. Pereira <leandro@hardinfo.org> + * + *    This program is free software; you can redistribute it and/or modify + *    it under the terms of the GNU General Public License as published by + *    the Free Software Foundation, version 2. + * + *    This program is distributed in the hope that it will be useful, + *    but WITHOUT ANY WARRANTY; without even the implied warranty of + *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + *    GNU General Public License for more details. + * + *    You should have received a copy of the GNU General Public License + *    along with this program; if not, write to the Free Software + *    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA + */ + +/* source: https://github.com/riscv/riscv-linux/blob/riscv-next/arch/riscv/kernel/cpu.c */ + +#include "hardinfo.h" +#include "devices.h" +#include "cpu_util.h" + +#include "riscv_data.h" +#include "riscv_data.c" + +GSList * +processor_scan(void) +{ +    GSList *procs = NULL; +    Processor *processor = NULL; +    FILE *cpuinfo; +    gchar buffer[128]; +    gchar *rep_pname = NULL; +    gchar *tmpfreq_str = NULL; +    GSList *pi = NULL; + +    cpuinfo = fopen(PROC_CPUINFO, "r"); +    if (!cpuinfo) +    return NULL; + +#define CHECK_FOR(k) (g_str_has_prefix(tmp[0], k)) +    while (fgets(buffer, 128, cpuinfo)) { +        gchar **tmp = g_strsplit(buffer, ":", 2); +        if (tmp[0] && tmp[1]) { +            tmp[0] = g_strstrip(tmp[0]); +            tmp[1] = g_strstrip(tmp[1]); +        } else { +            g_strfreev(tmp); +            continue; +        } + +        //get_str("Processor", rep_pname); + +        if ( CHECK_FOR("hart") ) { +            /* finish previous */ +            if (processor) { +                procs = g_slist_append(procs, processor); +            } + +            /* start next */ +            processor = g_new0(Processor, 1); +            processor->id = atol(tmp[1]); + +            if (rep_pname) +                processor->model_name = g_strdup(rep_pname); + +            g_strfreev(tmp); +            continue; +        } + +        if (!processor && +            (  CHECK_FOR("mmu") +            || CHECK_FOR("isa") +            || CHECK_FOR("uarch") ) ) { + +            /* single proc/core may not have "hart : n" */ +            processor = g_new0(Processor, 1); +            processor->id = 0; + +            if (rep_pname) +                processor->model_name = g_strdup(rep_pname); +        } + +        if (processor) { +            get_str("mmu", processor->mmu); +            get_str("isa", processor->isa); +            get_str("uarch", processor->uarch); +        } +        g_strfreev(tmp); +    } + +    if (processor) +        procs = g_slist_append(procs, processor); + +    g_free(rep_pname); +    fclose(cpuinfo); + +    /* TODO: redup */ + +    /* data not from /proc/cpuinfo */ +    for (pi = procs; pi; pi = pi->next) { +        processor = (Processor *) pi->data; + +        /* strings can't be null or segfault later */ +        STRIFNULL(processor->model_name, _("RISC-V Processor") ); +        UNKIFNULL(processor->mmu); +        UNKIFNULL(processor->isa); +        UNKIFNULL(processor->uarch); + +        processor->flags = riscv_isa_to_flags(processor->isa); + +        /* topo & freq */ +        processor->cpufreq = cpufreq_new(processor->id); +        processor->cputopo = cputopo_new(processor->id); + +        if (processor->cpufreq->cpukhz_max) +            processor->cpu_mhz = processor->cpufreq->cpukhz_max / 1000; +        else +            processor->cpu_mhz = 0.0f; +    } + +    return procs; +} + +gchar *processor_get_capabilities_from_flags(gchar * strflags) +{ +    gchar **flags, **old; +    gchar *tmp = NULL; +    gint j = 0; + +    flags = g_strsplit(strflags, " ", 0); +    old = flags; + +    while (flags[j]) { +        const gchar *meaning = riscv_ext_meaning( flags[j] ); + +        if (meaning) { +            tmp = h_strdup_cprintf("%s=%s\n", tmp, flags[j], meaning); +        } else { +            tmp = h_strdup_cprintf("%s=\n", tmp, flags[j]); +        } +        j++; +    } +    if (tmp == NULL || g_strcmp0(tmp, "") == 0) +        tmp = g_strdup_printf("%s=%s\n", "empty", _("Empty List")); + +    g_strfreev(old); +    return tmp; +} + +gchar *processor_name(GSList * processors) { +    return processor_name_default(processors); +} + +gchar *processor_describe(GSList * processors) { +    return processor_describe_default(processors); +} + +gchar * +processor_get_detailed_info(Processor *processor) +{ +    gchar *tmp_flags, *tmp_cpufreq, *tmp_topology, *ret; +    tmp_flags = processor_get_capabilities_from_flags(processor->flags); +    tmp_topology = cputopo_section_str(processor->cputopo); +    tmp_cpufreq = cpufreq_section_str(processor->cpufreq); + +    ret = g_strdup_printf("[%s]\n" +                   "%s=%s\n"  /* model */ +                   "%s=%s\n"  /* isa */ +                   "%s=%s\n"  /* uarch */ +                   "%s=%s\n"  /* mmu */ +                   "%s=%.2f %s\n" /* frequency */ +                   "%s=%s\n"      /* byte order */ +                   "%s" /* topology */ +                   "%s" /* frequency scaling */ +                   "[%s]\n" /* extensions */ +                   "%s" +                   "%s",/* empty */ +                   _("Processor"), +                   _("Model"), processor->model_name, +                   _("Architecture"), processor->isa, +                   _("uarch"), processor->uarch, +                   _("MMU"), processor->mmu, +                   _("Frequency"), processor->cpu_mhz, _("MHz"), +                   _("Byte Order"), byte_order_str(), +                   tmp_topology, +                   tmp_cpufreq, +                   _("Capabilities"), tmp_flags, +                    ""); +    g_free(tmp_flags); +    g_free(tmp_cpufreq); +    g_free(tmp_topology); +    return ret; +} + +gchar *processor_get_info(GSList * processors) +{ +    Processor *processor; + +    if (g_slist_length(processors) > 1) { +    gchar *ret, *tmp, *hashkey; +    GSList *l; + +    tmp = g_strdup(""); + +    for (l = processors; l; l = l->next) { +        processor = (Processor *) l->data; + +        tmp = g_strdup_printf("%s$CPU%d$%s=%.2f %s\n", +                  tmp, processor->id, +                  processor->model_name, +                  processor->cpu_mhz, _("MHz")); + +        hashkey = g_strdup_printf("CPU%d", processor->id); +        moreinfo_add_with_prefix("DEV", hashkey, +                processor_get_detailed_info(processor)); +           g_free(hashkey); +    } + +    ret = g_strdup_printf("[$ShellParam$]\n" +                  "ViewType=1\n" +                  "[Processors]\n" +                  "%s", tmp); +    g_free(tmp); + +    return ret; +    } + +    processor = (Processor *) processors->data; +    return processor_get_detailed_info(processor); +} diff --git a/modules/devices/riscv/riscv_data.c b/modules/devices/riscv/riscv_data.c new file mode 100644 index 00000000..4ae68ef4 --- /dev/null +++ b/modules/devices/riscv/riscv_data.c @@ -0,0 +1,212 @@ +/* + * rpiz - https://github.com/bp0/rpiz + * Copyright (C) 2017  Burt P. <pburt0@gmail.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. + * + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include "riscv_data.h" + +#ifndef C_ +#define C_(Ctx, String) String +#endif +#ifndef NC_ +#define NC_(Ctx, String) String +#endif + +static struct { +    char *name, *meaning; +} tab_ext_meaning[] = { +    { "RV32",  NC_("rv-ext", /*/ext:RV32*/  "RISC-V 32-bit") }, +    { "RV64",  NC_("rv-ext", /*/ext:RV64*/  "RISC-V 64-bit") }, +    { "RV128", NC_("rv-ext", /*/ext:RV128*/ "RISC-V 128-bit") }, +    { "E",     NC_("rv-ext", /*/ext:E*/ "Base embedded integer instructions (15 registers)") }, +    { "I",     NC_("rv-ext", /*/ext:I*/ "Base integer instructions (31 registers)") }, +    { "M",     NC_("rv-ext", /*/ext:M*/ "Hardware integer multiply and divide") }, +    { "A",     NC_("rv-ext", /*/ext:A*/ "Atomic memory operations") }, +    { "C",     NC_("rv-ext", /*/ext:C*/ "Compressed 16-bit instructions") }, +    { "F",     NC_("rv-ext", /*/ext:F*/ "Floating-point instructions, single-precision") }, +    { "D",     NC_("rv-ext", /*/ext:D*/ "Floating-point instructions, double-precision") }, +    { "Q",     NC_("rv-ext", /*/ext:Q*/ "Floating-point instructions, quad-precision") }, +    { "B",     NC_("rv-ext", /*/ext:B*/ "Bit manipulation instructions") }, +    { "V",     NC_("rv-ext", /*/ext:V*/ "Vector operations") }, +    { "T",     NC_("rv-ext", /*/ext:T*/ "Transactional memory") }, +    { "P",     NC_("rv-ext", /*/ext:P*/ "Packed SIMD instructions") }, +    { "L",     NC_("rv-ext", /*/ext:L*/ "Decimal floating-point instructions") }, +    { "J",     NC_("rv-ext", /*/ext:J*/ "Dynamically translated languages") }, +    { "N",     NC_("rv-ext", /*/ext:N*/ "User-level interrupts") }, +    { NULL, NULL } +}; + +static char all_extensions[1024] = ""; + +#define APPEND_EXT(f) strcat(all_extensions, f); strcat(all_extensions, " "); +const char *riscv_ext_list() { +    int i = 0, built = 0; +    built = strlen(all_extensions); +    if (!built) { +        while(tab_ext_meaning[i].name != NULL) { +            APPEND_EXT(tab_ext_meaning[i].name); +            i++; +        } +    } +    return all_extensions; +} + +const char *riscv_ext_meaning(const char *ext) { +    int i = 0, l = 0; +    char *c = NULL; +    if (ext) { +        c = strchr(ext, ':'); /* allow extension:version, ignore version */ +        if (c != NULL) +            l = c - ext; +        else +            l = strlen(ext); +        while(tab_ext_meaning[i].name != NULL) { +            if (strncasecmp(tab_ext_meaning[i].name, ext, l) == 0) { +                if (tab_ext_meaning[i].meaning != NULL) +                    return C_("rv-ext", tab_ext_meaning[i].meaning); +                else return NULL; +            } +            i++; +        } +    } +    return NULL; +} + +/* see RISC-V spec 2.2: Chapter 22: ISA Subset Naming Conventions */ + +/* Spec says case-insensitve, but I prefer single-letter extensions + * capped and version string (like "2p1") with a lowercase p. */ +#define RV_FIX_CASE(fstr,vo) \ +    p = fstr; while (*p != 0 && *p != ':') { if (!vo) *p = toupper(*p); p++; } \ +    if (*p == ':') while (*p != 0) { if (*p == 'P') *p = 'p'; p++; } + +static int riscv_isa_next(const char *isap, char *flag) { +    char *p = NULL, *start = NULL; +    char *next_sep = NULL, *next_digit = NULL; +    int skip_len = 0, tag_len = 0, ver_len = 0; +    char ext_str[32], ver_str[32]; + +    if (isap == NULL) +        return 0; + +    /* find start by skipping any '_' */ +    start = (char*)isap; +    while (*start != 0 && *start == '_') { start++; skip_len++; }; +    if (*start == 0) +        return 0; + +    /* find next '_' or \0 */ +    p = start; while (*p != 0 && *p != '_') { p++; }; next_sep = p; + +    /* find next digit that may be a version, find length of version */ +    p = start; while (*p != 0 && !isdigit(*p)) { p++; }; +    if (isdigit(*p)) next_digit = p; +    if (next_digit) { +        while (*p != 0 && (isdigit(*p) || *p == 'p' || *p == 'P') ) { +            if ((*p == 'p' || *p == 'P') && !isdigit(*(p+1)) ) +                break; +            ver_len++; +            p++; +        } +    } + +    /* is next version nearer than next separator */ +    p = start; +    if (next_digit && next_digit < next_sep) +        tag_len = next_digit - p; +    else { +        tag_len = next_sep - p; +        ver_len = 0; +    } + +    switch(*p) { +        case 'S': case 's': /* supervisor extension */ +        case 'X': case 'x': /* custom extension */ +            /* custom supervisor extension (SX..) handled by S */ +            break; +        default: /* single character (standard) extension */ +            tag_len = 1; +            if (next_digit != p+1) ver_len = 0; +            break; +    } + +    memset(ext_str, 0, 32); +    memset(ver_str, 0, 32); +    if (ver_len) { +        strncpy(ext_str, p, tag_len); +        strncpy(ver_str, next_digit, ver_len); +        sprintf(flag, "%s:%s", ext_str, ver_str); +        if (tag_len == 1) { +            RV_FIX_CASE(flag, 0); +        } else { +            RV_FIX_CASE(flag, 1); +        } +        return skip_len + tag_len + ver_len; +    } else { +        strncpy(ext_str, p, tag_len); +        sprintf(flag, "%s", ext_str); +        if (tag_len == 1) { RV_FIX_CASE(flag, 0); } +        return skip_len + tag_len; +    } +} + +#define FSTR_SIZE 1024 +#define RV_CHECK_FOR(e) ( strncasecmp(ps, e, 2) == 0 ) +#define ADD_EXT_FLAG(ext) el = strlen(ext); strncpy(pd, ext, el); strncpy(pd + el, " ", 1); pd += el + 1; +char *riscv_isa_to_flags(const char *isa) { +    char *flags = NULL, *ps = (char*)isa, *pd = NULL; +    char flag_buf[64] = ""; +    int isa_len = 0, tl = 0, el = 0; /* el used in macro */ + +    if (isa) { +        isa_len = strlen(isa); +        flags = malloc(FSTR_SIZE); +        if (flags) { +            memset(flags, 0, FSTR_SIZE); +            ps = (char*)isa; +            pd = flags; +            if ( RV_CHECK_FOR("RV") ) +            { ps += 2; } +            if ( RV_CHECK_FOR("32") ) +            { ADD_EXT_FLAG("RV32"); ps += 2; } +            else if ( RV_CHECK_FOR("64") ) +            { ADD_EXT_FLAG("RV64"); ps += 2; } +            else if ( RV_CHECK_FOR("128") ) +            { ADD_EXT_FLAG("RV128"); ps += 3; } + +            while( (tl = riscv_isa_next(ps, flag_buf)) ) { +                if (flag_buf[0] == 'G') { /* G = IMAFD */ +                    flag_buf[0] = 'I'; ADD_EXT_FLAG(flag_buf); +                    flag_buf[0] = 'M'; ADD_EXT_FLAG(flag_buf); +                    flag_buf[0] = 'A'; ADD_EXT_FLAG(flag_buf); +                    flag_buf[0] = 'F'; ADD_EXT_FLAG(flag_buf); +                    flag_buf[0] = 'D'; ADD_EXT_FLAG(flag_buf); +                } else { +                    ADD_EXT_FLAG(flag_buf); +                } +                ps += tl; +                if (ps - isa >= isa_len) break; /* just in case */ +            } +        } +    } +    return flags; +} diff --git a/modules/devices/riscv/riscv_data.h b/modules/devices/riscv/riscv_data.h new file mode 100644 index 00000000..1d3a0a48 --- /dev/null +++ b/modules/devices/riscv/riscv_data.h @@ -0,0 +1,33 @@ +/* + * rpiz - https://github.com/bp0/rpiz + * Copyright (C) 2017  Burt P. <pburt0@gmail.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. + * + */ + +#ifndef _RISCVDATA_H_ +#define _RISCVDATA_H_ + +/* convert RISC-V ISA string to flags list */ +char *riscv_isa_to_flags(const char *isa); + +/* all known extensions as flags list */ +const char *riscv_ext_list(void); + +/* get meaning of flag */ +const char *riscv_ext_meaning(const char *ext); + +#endif diff --git a/modules/devices/s390/processor.c b/modules/devices/s390/processor.c index 99f1c8bd..cf45c33c 100644 --- a/modules/devices/s390/processor.c +++ b/modules/devices/s390/processor.c @@ -18,61 +18,163 @@  #include "hardinfo.h"  #include "devices.h" +#include "string.h" +#include "cpu_util.h"  GSList *  processor_scan(void)  { -    Processor *processor; +    GSList *procs = NULL; +    Processor *processor = NULL;      FILE *cpuinfo;      gchar buffer[128]; +    gchar *vendor_id = NULL; +    gint   num_procs = 0; +    gfloat bogomips = 0.0f; +    GSList *pi = NULL; -    cpuinfo = fopen("/proc/cpuinfo", "r"); +    cpuinfo = fopen(PROC_CPUINFO, "r");      if (!cpuinfo) -	return NULL; +    return NULL; -    processor = g_new0(Processor, 1); +#define CHECK_FOR(k) (g_str_has_prefix(tmp[0], k))      while (fgets(buffer, 128, cpuinfo)) { -	gchar **tmp = g_strsplit(buffer, ":", 2); +        gchar **tmp = g_strsplit(buffer, ":", 2); +        if (tmp[0] && tmp[1]) { +            tmp[0] = g_strstrip(tmp[0]); +            tmp[1] = g_strstrip(tmp[1]); +        } else { +            g_strfreev(tmp); +            continue; +        } + +        get_str("vendor_id", vendor_id); +        get_int("# processors", num_procs); +        get_int("bogomips per cpu", bogomips); + +        if ( CHECK_FOR("processor") ) { +            /* finish previous */ +            if (processor) { +                procs = g_slist_append(procs, processor); +            } + +            /* start next */ +            processor = g_new0(Processor, 1); +            if (strlen(tmp[0]) >= 10) +                processor->id = atol(tmp[0] + 10); /* processor n: ... */ +            else +                processor->id = 0; /* idk */ +            processor->proc_str = g_strdup(tmp[1]); -	if (tmp[0] && tmp[1]) { -	    tmp[0] = g_strstrip(tmp[0]); -	    tmp[1] = g_strstrip(tmp[1]); +            if (vendor_id) +                processor->model_name = g_strdup(vendor_id); +            if (bogomips) +                processor->bogomips = bogomips; -	    get_str("vendor_id", processor->vendor_id); -	    get_float("# processors", processor->cache_size); -	    get_int("bogomips per cpu", processor->bogomips); +            g_strfreev(tmp); +            continue; +        } -	} -	g_strfreev(tmp); +        g_strfreev(tmp);      } -    processor->cpu_mhz = 0.0f; -     -    processor->model_name = g_strconcat("S390 ", processor->vendor_id, NULL); -    g_free(processor->vendor_id); +    if (processor) +        procs = g_slist_append(procs, processor); +    g_free(vendor_id);      fclose(cpuinfo); -    return g_slist_append(NULL, processor); +    /* data not from /proc/cpuinfo */ +    for (pi = procs; pi; pi = pi->next) { +        processor = (Processor *) pi->data; + +        /* strings can't be null or segfault later */ +        STRIFNULL(processor->model_name, _("S390 Processor") ); +        UNKIFNULL(processor->proc_str); + +        /* topo & freq */ +        processor->cpufreq = cpufreq_new(processor->id); +        processor->cputopo = cputopo_new(processor->id); + +        if (processor->cpufreq->cpukhz_max) +            processor->cpu_mhz = processor->cpufreq->cpukhz_max / 1000; +        else +            processor->cpu_mhz = 0.0f; + +    } + +    return procs; +} + +gchar *processor_name(GSList * processors) { +    return processor_name_default(processors); +} + +gchar *processor_describe(GSList * processors) { +    return processor_describe_default(processors);  }  gchar * -processor_get_info(GSList *processors) +processor_get_detailed_info(Processor *processor) +{ +    gchar *tmp_cpufreq, *tmp_topology, *ret; +    tmp_topology = cputopo_section_str(processor->cputopo); +    tmp_cpufreq = cpufreq_section_str(processor->cpufreq); + +    ret = g_strdup_printf("[%s]\n" +                        "%s=%s\n"      /* model */ +                        "%s=%s\n"      /* proc string */ +                        "%s=%.2f\n"    /* bogomips */ +                        "%s=%s\n"      /* byte order */ +                        "%s"  /* topology */ +                        "%s", /* frequency scaling */ +                        _("Processor"), +                        _("Model"), processor->model_name, +                        _("ID String"), processor->proc_str, +                        _("BogoMips"), processor->bogomips, +                        _("Byte Order"), byte_order_str(), +                        tmp_topology, +                        tmp_cpufreq +                        ); +    g_free(tmp_cpufreq); +    g_free(tmp_topology); +    return ret; +} + +gchar *processor_get_info(GSList * processors)  { -        Processor *processor = (Processor *)processors->data; -         -	return g_strdup_printf("[Processor]\n" -                               "Model=%s\n" -	                       "Processors=%d\n" -	                       "BogoMips per CPU=%.2f" -	                       "Byte Order=%s\n", -			       processor->model_name, -			       processor->cache_size, -			       processor->bogomips, -#if G_BYTE_ORDER == G_LITTLE_ENDIAN -                               "Little Endian" -#else -                               "Big Endian" -#endif -                              ); +    Processor *processor; + +    if (g_slist_length(processors) > 1) { +    gchar *ret, *tmp, *hashkey; +    GSList *l; + +    tmp = g_strdup(""); + +    for (l = processors; l; l = l->next) { +        processor = (Processor *) l->data; + +        tmp = g_strdup_printf("%s$CPU%d$%s=%.2f %s\n", +                  tmp, processor->id, +                  processor->model_name, +                  processor->cpu_mhz, _("MHz")); + +        hashkey = g_strdup_printf("CPU%d", processor->id); +        moreinfo_add_with_prefix("DEV", hashkey, +                processor_get_detailed_info(processor)); +           g_free(hashkey); +    } + +    ret = g_strdup_printf("[$ShellParam$]\n" +                  "ViewType=1\n" +                  "[Processors]\n" +                  "%s", tmp); +    g_free(tmp); + +    return ret; +    } + +    processor = (Processor *) processors->data; +    return processor_get_detailed_info(processor);  } + diff --git a/modules/devices/sensors.c b/modules/devices/sensors.c index 84e89361..c9d78ff7 100644 --- a/modules/devices/sensors.c +++ b/modules/devices/sensors.c @@ -27,8 +27,7 @@ gchar *sensors = NULL;  GHashTable *sensor_compute = NULL;  GHashTable *sensor_labels = NULL; -static void read_sensor_labels(gchar * driver) -{ +static void read_sensor_labels(gchar *driver) {      FILE *conf;      gchar buf[256], *line, *p;      gboolean lock = FALSE; @@ -38,7 +37,8 @@ static void read_sensor_labels(gchar * driver)      conf = fopen("/etc/sensors3.conf", "r");      /* If it fails, try to open sensors.conf */ -    if (!conf) conf = fopen("/etc/sensors.conf", "r"); +    if (!conf) +        conf = fopen("/etc/sensors.conf", "r");      if (!conf) {          /* Cannot open config file. */ @@ -46,117 +46,129 @@ static void read_sensor_labels(gchar * driver)      }      while (fgets(buf, 256, conf)) { -	line = buf; - -	remove_linefeed(line); -	strend(line, '#'); - -	if (*line == '\0') { -	    continue; -	} else if (lock && strstr(line, "label")) {	/* label lines */ -	    gchar **names = g_strsplit(strstr(line, "label") + 5, " ", 0); -	    gchar *name = NULL, *value = NULL; - -	    for (i = 0; names[i]; i++) { -		if (names[i][0] == '\0') -		    continue; - -		if (!name) -		    name = g_strdup(names[i]); -		else if (!value) -		    value = g_strdup(names[i]); -		else -		    value = g_strconcat(value, " ", names[i], NULL); -	    } - -	    remove_quotes(value); -	    g_hash_table_insert(sensor_labels, name, value); - -	    g_strfreev(names); -	} else if (lock && strstr(line, "ignore")) {	/* ignore lines */ -	    p = strstr(line, "ignore") + 6; -	    if (!strchr(p, ' ')) -		continue; - -	    while (*p == ' ') -		p++; -	    g_hash_table_insert(sensor_labels, g_strdup(p), "ignore"); -	} else if (lock && strstr(line, "compute")) {	/* compute lines */ -	    gchar **formulas = -		g_strsplit(strstr(line, "compute") + 7, " ", 0); -	    gchar *name = NULL, *formula = NULL; - -	    for (i = 0; formulas[i]; i++) { -		if (formulas[i][0] == '\0') -		    continue; -		if (formulas[i][0] == ',') -		    break; - -		if (!name) -		    name = g_strdup(formulas[i]); -		else if (!formula) -		    formula = g_strdup(formulas[i]); -		else -		    formula = g_strconcat(formula, formulas[i], NULL); -	    } - -	    g_strfreev(formulas); -	    g_hash_table_insert(sensor_compute, name, -				math_string_to_postfix(formula)); -	} else if (g_str_has_prefix(line, "chip")) {	/* chip lines (delimiter) */ -	    if (lock == FALSE) { -		gchar **chips = g_strsplit(line, " ", 0); - -		for (i = 1; chips[i]; i++) { -		    strend(chips[i], '*'); - -                     if (g_str_has_prefix(chips[i] + 1, driver)) { -			lock = TRUE; -			break; -		    } -		} - -		g_strfreev(chips); -	    } else { -		break; -	    } -	} +        line = buf; + +        remove_linefeed(line); +        strend(line, '#'); + +        if (*line == '\0') { +            continue; +        } else if (lock && strstr(line, "label")) { /* label lines */ +            gchar **names = g_strsplit(strstr(line, "label") + 5, " ", 0); +            gchar *name = NULL, *value = NULL; + +            for (i = 0; names[i]; i++) { +                if (names[i][0] == '\0') +                    continue; + +                if (!name) +                    name = g_strdup(names[i]); +                else if (!value) +                    value = g_strdup(names[i]); +                else +                    value = g_strconcat(value, " ", names[i], NULL); +            } + +            remove_quotes(value); +            g_hash_table_insert(sensor_labels, name, value); + +            g_strfreev(names); +        } else if (lock && strstr(line, "ignore")) { /* ignore lines */ +            p = strstr(line, "ignore") + 6; +            if (!strchr(p, ' ')) +                continue; + +            while (*p == ' ') +                p++; +            g_hash_table_insert(sensor_labels, g_strdup(p), "ignore"); +        } else if (lock && strstr(line, "compute")) { /* compute lines */ +            gchar **formulas = g_strsplit(strstr(line, "compute") + 7, " ", 0); +            gchar *name = NULL, *formula = NULL; + +            for (i = 0; formulas[i]; i++) { +                if (formulas[i][0] == '\0') +                    continue; +                if (formulas[i][0] == ',') +                    break; + +                if (!name) +                    name = g_strdup(formulas[i]); +                else if (!formula) +                    formula = g_strdup(formulas[i]); +                else +                    formula = g_strconcat(formula, formulas[i], NULL); +            } + +            g_strfreev(formulas); +            g_hash_table_insert(sensor_compute, name, +                                math_string_to_postfix(formula)); +        } else if (g_str_has_prefix(line, +                                    "chip")) { /* chip lines (delimiter) */ +            if (lock == FALSE) { +                gchar **chips = g_strsplit(line, " ", 0); + +                for (i = 1; chips[i]; i++) { +                    strend(chips[i], '*'); + +                    if (g_str_has_prefix(chips[i] + 1, driver)) { +                        lock = TRUE; +                        break; +                    } +                } + +                g_strfreev(chips); +            } else { +                break; +            } +        }      }      fclose(conf);  } -static gchar *get_sensor_label(gchar * sensor) -{ +static void add_sensor(const char *type, +                       const char *sensor, +                       const char *driver, +                       double value, +                       const char *unit) { +    char key[64]; + +    sensors = h_strdup_cprintf("%s/%s=%.2f%s|%s\n", sensors, +        driver, sensor, value, unit, type); + +    snprintf(key, sizeof(key), "%s/%s", driver, sensor); +    moreinfo_add_with_prefix("DEV", key, g_strdup_printf("%.2f%s", value, unit)); + +    lginterval = h_strdup_cprintf("UpdateInterval$%s=1000\n", lginterval, key); +} + +static gchar *get_sensor_label(gchar *sensor) {      gchar *ret;      ret = g_hash_table_lookup(sensor_labels, sensor);      if (!ret) -	ret = g_strdup(sensor); +        ret = g_strdup(sensor);      else -	ret = g_strdup(ret); +        ret = g_strdup(ret);      return ret;  } -static float adjust_sensor(gchar * name, float value) -{ +static float adjust_sensor(gchar *name, float value) {      GSList *postfix;      postfix = g_hash_table_lookup(sensor_compute, name);      if (!postfix) -	return value; +        return value;      return math_postfix_eval(postfix, value);  } -static char *get_sensor_path(int number, const char *prefix) -{ +static char *get_sensor_path(int number, const char *prefix) {      return g_strdup_printf("/sys/class/hwmon/hwmon%d/%s", number, prefix);  } -static char *determine_driver_for_hwmon_path(char *path) -{ +static char *determine_driver_for_hwmon_path(char *path) {      char *tmp, *driver;      tmp = g_strdup_printf("%s/device/driver", path); @@ -190,165 +202,171 @@ struct HwmonSensor {      const char *friendly_name;      const char *path_format;      const char *key_format; -    const char *value_format; +    const char *unit;      const float adjust_ratio;      const int begin_at;  };  static const struct HwmonSensor hwmon_sensors[] = { -    { "Cooling Fans",   "%s/fan%d_input",  "fan%d",  "%s (%s)=%.0fRPM\n",       1.0,    1 }, -    { "Temperature",    "%s/temp%d_input", "temp%d", "%s (%s)=%.2f\302\260C\n", 1000.0, 1 }, -    { "Voltage Values", "%s/in%d_input",   "in%d",   "%s (%s)=%.3fV\n",         1000.0, 0 }, -    { NULL,             NULL,              NULL,     NULL,                      0.0,    0 }, +    { +        "Fan", +        "%s/fan%d_input", +        "fan%d", +        "RPM", +        1.0, +        1 +    }, +    { +        "Temperature", +        "%s/temp%d_input", +        "temp%d", +        "\302\260C", +        1000.0, +        1 +    }, +    { +        "Voltage", +        "%s/in%d_input", +        "in%d", +        "V", +        1000.0, +        0 +    }, +    { }  }; -static const char *hwmon_prefix[] = { "device", "", NULL }; +static const char *hwmon_prefix[] = {"device", "", NULL}; -static void read_sensors_hwmon(void) -{ +static void read_sensors_hwmon(void) {      int hwmon, count;      gchar *path_hwmon, *path_sensor, *tmp, *driver, *name, *mon;      const char **prefix; -     +      for (prefix = hwmon_prefix; *prefix; prefix++) { -		hwmon = 0; -		path_hwmon = get_sensor_path(hwmon, *prefix); -		while (path_hwmon && g_file_test(path_hwmon, G_FILE_TEST_EXISTS)) { -			const struct HwmonSensor *sensor; - -			driver = determine_driver_for_hwmon_path(path_hwmon); -			DEBUG("hwmon%d has driver=%s", hwmon, driver); - -			if (!sensor_labels) { -				read_sensor_labels(driver); -			} - -			for (sensor = hwmon_sensors; sensor->friendly_name; sensor++) { -				char *output = NULL; -				DEBUG("current sensor type=%s", sensor->friendly_name); - -					for (count = sensor->begin_at;; count++) { -						path_sensor = g_strdup_printf(sensor->path_format, path_hwmon, count); -						DEBUG("should be reading from %s", path_sensor); -						if (!g_file_get_contents(path_sensor, &tmp, NULL, NULL)) { -							g_free(path_sensor); -							if (count<256) -								continue; // brute-force find all -							else -								break;  -						} - -						mon = g_strdup_printf(sensor->key_format, count); -						name = get_sensor_label(mon); -						if (!g_str_equal(name, "ignore")) { -							output = h_strdup_cprintf(sensor->value_format, -													  output, name, driver, -													  adjust_sensor(mon, -																	atof(tmp) / sensor->adjust_ratio)); -						} - -						g_free(tmp); -						g_free(mon); -						g_free(name); -						g_free(path_sensor); -					} - -					if (output) { -						sensors = g_strconcat(sensors, "[", sensor->friendly_name, "]\n", output, "\n", NULL); -						g_free(output); -					} -			} - -			g_free(path_hwmon); -			g_free(driver); - -			path_hwmon = get_sensor_path(++hwmon, *prefix); -		} - -		g_free(path_hwmon); -	} +        hwmon = 0; +        path_hwmon = get_sensor_path(hwmon, *prefix); +        while (path_hwmon && g_file_test(path_hwmon, G_FILE_TEST_EXISTS)) { +            const struct HwmonSensor *sensor; + +            driver = determine_driver_for_hwmon_path(path_hwmon); +            DEBUG("hwmon%d has driver=%s", hwmon, driver); + +            if (!sensor_labels) { +                read_sensor_labels(driver); +            } + +            for (sensor = hwmon_sensors; sensor->friendly_name; sensor++) { +                DEBUG("current sensor type=%s", sensor->friendly_name); + +                for (count = sensor->begin_at;; count++) { +                    path_sensor = +                        g_strdup_printf(sensor->path_format, path_hwmon, count); +                    DEBUG("should be reading from %s", path_sensor); +                    if (!g_file_get_contents(path_sensor, &tmp, NULL, NULL)) { +                        g_free(path_sensor); +                        if (count < 256) +                            continue; // brute-force find all +                        else +                            break; +                    } + +                    mon = g_strdup_printf(sensor->key_format, count); +                    name = get_sensor_label(mon); +                    if (!g_str_equal(name, "ignore")) { +                        float adjusted = adjust_sensor(mon, +                            atof(tmp) / sensor->adjust_ratio); + +                        add_sensor(sensor->friendly_name, +                                   name, +                                   driver, +                                   adjusted, +                                   sensor->unit); +                    } + +                    g_free(tmp); +                    g_free(mon); +                    g_free(name); +                    g_free(path_sensor); +                } +            } + +            g_free(path_hwmon); +            g_free(driver); + +            path_hwmon = get_sensor_path(++hwmon, *prefix); +        } + +        g_free(path_hwmon); +    }  } -static void read_sensors_acpi(void) -{ +static void read_sensors_acpi(void) {      const gchar *path_tz = "/proc/acpi/thermal_zone";      if (g_file_test(path_tz, G_FILE_TEST_EXISTS)) { -	GDir *tz; - -	if ((tz = g_dir_open(path_tz, 0, NULL))) { -	    const gchar *entry; -	    gchar *temp = g_strdup(""); - -	    while ((entry = g_dir_read_name(tz))) { -		gchar *path = -		    g_strdup_printf("%s/%s/temperature", path_tz, entry); -		gchar *contents; +        GDir *tz; -		if (g_file_get_contents(path, &contents, NULL, NULL)) { -		    int temperature; +        if ((tz = g_dir_open(path_tz, 0, NULL))) { +            const gchar *entry; -		    sscanf(contents, "temperature: %d C", &temperature); +            while ((entry = g_dir_read_name(tz))) { +                gchar *path = +                    g_strdup_printf("%s/%s/temperature", path_tz, entry); +                gchar *contents; -		    temp = h_strdup_cprintf("\n%s=%d\302\260C\n", -					      temp, entry, temperature); +                if (g_file_get_contents(path, &contents, NULL, NULL)) { +                    int temperature; -		    g_free(contents); -		} -	    } +                    sscanf(contents, "temperature: %d C", &temperature); -	    if (*temp != '\0') -    	        sensors = -	    	    h_strdup_cprintf("\n[ACPI Thermal Zone]\n%s", -	    	                    sensors, temp); +                    add_sensor("Temperature", +                               entry, +                               "ACPI Thermal Zone", +                               temperature, +                               "\302\260C"); +                } +            } -	    g_dir_close(tz); -	} +            g_dir_close(tz); +        }      } -  } -static void read_sensors_sys_thermal(void) -{ +static void read_sensors_sys_thermal(void) {      const gchar *path_tz = "/sys/class/thermal";      if (g_file_test(path_tz, G_FILE_TEST_EXISTS)) { -	GDir *tz; - -	if ((tz = g_dir_open(path_tz, 0, NULL))) { -	    const gchar *entry; -	    gchar *temp = g_strdup(""); +        GDir *tz; -	    while ((entry = g_dir_read_name(tz))) { -		gchar *path = -		    g_strdup_printf("%s/%s/temp", path_tz, entry); -		gchar *contents; +        if ((tz = g_dir_open(path_tz, 0, NULL))) { +            const gchar *entry; +            gchar *temp = g_strdup(""); -		if (g_file_get_contents(path, &contents, NULL, NULL)) { -		    int temperature; +            while ((entry = g_dir_read_name(tz))) { +                gchar *path = g_strdup_printf("%s/%s/temp", path_tz, entry); +                gchar *contents; -		    sscanf(contents, "%d", &temperature); +                if (g_file_get_contents(path, &contents, NULL, NULL)) { +                    int temperature; -		    temp = h_strdup_cprintf("\n%s=%.2f\302\260C\n", -					      temp, entry, (1.0*temperature/1000)); +                    sscanf(contents, "%d", &temperature); -		    g_free(contents); -		} -	    } +                    add_sensor("Temperature", +                               entry, +                               "thermal", +                               temperature / 1000.0, +                               "\302\260C"); -	    if (*temp != '\0') -    	        sensors = -	    	    h_strdup_cprintf("\n[ACPI Thermal Zone (sysfs)]\n%s", -	    	                    sensors, temp); +                    g_free(contents); +                } +            } -	    g_dir_close(tz); -	} +            g_dir_close(tz); +        }      } -  } -static void read_sensors_omnibook(void) -{ +static void read_sensors_omnibook(void) {      const gchar *path_ob = "/proc/omnibook/temperature";      gchar *contents; @@ -357,88 +375,79 @@ static void read_sensors_omnibook(void)          sscanf(contents, "CPU temperature: %d C", &temperature); -        sensors = h_strdup_cprintf("\n[Omnibook]\n" -                                  "CPU temperature=%d\302\260C\n", -                                  sensors, temperature); +        add_sensor("Temperature", +                   "CPU", +                   "omnibook", +                   temperature, +                   "\302\260C\n");          g_free(contents);      }  } -static void read_sensors_hddtemp(void) -{ +static void read_sensors_hddtemp(void) {      Socket *s; -    static gchar *old = NULL;      gchar buffer[1024];      gint len = 0; -    if ((s = sock_connect("127.0.0.1", 7634))) { -	while (!len) -	    len = sock_read(s, buffer, sizeof(buffer)); -        sock_close(s); - -	if (len > 2 && buffer[0] == '|' && buffer[1] == '/') { -	    gchar **disks; -	    int i; - -	    g_free(old); - -	    old = g_strdup("[Hard Disk Temperature]\n"); - -	    disks = g_strsplit(buffer, "\n", 0); -	    for (i = 0; disks[i]; i++) { -		gchar **fields = g_strsplit(disks[i] + 1, "|", 5); - -		/* -		 * 0 -> /dev/hda -		 * 1 -> FUJITSU MHV2080AH -		 * 2 -> 41 -		 * 3 -> C -		 */ -		old = h_strdup_cprintf("\n%s (%s)=%s\302\260%s\n", -				      old, -				      fields[1], fields[0], -				      fields[2], fields[3]); - -		g_strfreev(fields); -	    } +    if (!(s = sock_connect("127.0.0.1", 7634))) +        return; -	    g_strfreev(disks); -	} -    } else { -	g_free(old); -	old = NULL; -    } +    while (!len) +        len = sock_read(s, buffer, sizeof(buffer)); +    sock_close(s); + +    if (len > 2 && buffer[0] == '|' && buffer[1] == '/') { +        gchar **disks; +        int i; + +        disks = g_strsplit(buffer, "\n", 0); +        for (i = 0; disks[i]; i++) { +            gchar **fields = g_strsplit(disks[i] + 1, "|", 5); + +            /* +             * 0 -> /dev/hda +             * 1 -> FUJITSU MHV2080AH +             * 2 -> 41 +             * 3 -> C +             */ +            const gchar *unit = strcmp(fields[3], "C") +                ? "\302\260C" : "\302\260F"; +            add_sensor("Hard Drive", +                       fields[1], +                       "hddtemp", +                       atoi(fields[2]), +                       unit); + +            g_strfreev(fields); +        } -    if (old) { -	sensors = g_strconcat(sensors, "\n", old, NULL); +        g_strfreev(disks);      }  } -void scan_sensors_do(void) -{ +void scan_sensors_do(void) {      g_free(sensors); -      sensors = g_strdup(""); +    g_free(lginterval); +    lginterval = g_strdup(""); +      read_sensors_hwmon();      read_sensors_acpi();      read_sensors_sys_thermal();      read_sensors_omnibook();      read_sensors_hddtemp(); -      /* FIXME: Add support for  ibm acpi and more sensors */  } -void sensors_init(void) -{ -    sensor_labels = g_hash_table_new_full(g_str_hash, g_str_equal, -					  g_free, g_free); +void sensors_init(void) { +    sensor_labels = +        g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);      sensor_compute = g_hash_table_new(g_str_hash, g_str_equal);  } -void sensors_shutdown(void) -{ +void sensors_shutdown(void) {      g_hash_table_destroy(sensor_labels);      g_hash_table_destroy(sensor_compute);  } diff --git a/modules/devices/sh/processor.c b/modules/devices/sh/processor.c index cbd9a60a..9da2f9b0 100644 --- a/modules/devices/sh/processor.c +++ b/modules/devices/sh/processor.c @@ -18,6 +18,7 @@  #include "hardinfo.h"  #include "devices.h" +#include "cpu_util.h"  GSList *  processor_scan(void) @@ -26,50 +27,67 @@ processor_scan(void)      FILE *cpuinfo;      gchar buffer[128]; -    cpuinfo = fopen("/proc/cpuinfo", "r"); +    cpuinfo = fopen(PROC_CPUINFO, "r");      if (!cpuinfo) -	return NULL; +        return NULL;      processor = g_new0(Processor, 1);      while (fgets(buffer, 128, cpuinfo)) { -	gchar **tmp = g_strsplit(buffer, ":", 2); +        gchar **tmp = g_strsplit(buffer, ":", 2); -	if (tmp[0] && tmp[1]) { -	    tmp[0] = g_strstrip(tmp[0]); -	    tmp[1] = g_strstrip(tmp[1]); +        if (tmp[0] && tmp[1]) { +            tmp[0] = g_strstrip(tmp[0]); +            tmp[1] = g_strstrip(tmp[1]); -	    get_str("machine", processor->model_name); -	    get_str("cpu type", processor->vendor_id); -	    get_float("bogomips", processor->bogomips); -	    processor->cpu_mhz = processor->bogomips; -	} -	g_strfreev(tmp); +            get_str("machine", processor->vendor_id); +            get_str("cpu type", processor->model_name); +            get_str("cpu family", processor->family); +            get_float("cpu clock", processor->cpu_mhz); +            get_float("bus clock", processor->bus_mhz); +            get_float("module clock", processor->mod_mhz); +            get_float("bogomips", processor->bogomips); +        } +        g_strfreev(tmp);      }      fclose(cpuinfo); +    STRIFNULL(processor->model_name, _("SuperH Processor")); +    UNKIFNULL(processor->vendor_id); +      return g_slist_append(NULL, processor);  } +gchar *processor_name(GSList * processors) { +    return processor_name_default(processors); +} + +gchar *processor_describe(GSList * processors) { +    return processor_describe_default(processors); +} +  gchar *  processor_get_info(GSList *processors)  { -        Processor *processor = (Processor *)processors->data; -         -	return g_strdup_printf("[Processor]\n" -	                       "System Type=%s\n" -	                       "CPU Model=%s\n" -                               "Frequency=%.2fMHz\n" -			       "BogoMIPS=%.2f\n" -			       "Byte Order=%s\n", -			       processor->model_name, -			       processor->vendor_id, -			       processor->cpu_mhz, -			       processor->bogomips, -#if G_BYTE_ORDER == G_LITTLE_ENDIAN -                               "Little Endian" -#else -                               "Big Endian" -#endif -			       ); +    Processor *processor = (Processor *)processors->data; + +    return g_strdup_printf("[%s]\n" +                        "%s=%s\n"      /* cpu type */ +                        "%s=%s\n"      /* machine */ +                        "%s=%s\n"      /* family */ +                        "%s=%.2f %s\n" /* frequency */ +                        "%s=%.2f %s\n" /* bus frequency */ +                        "%s=%.2f %s\n" /* module frequency */ +                        "%s=%.2f\n"    /* bogomips */ +                        "%s=%s\n",     /* byte order */ +                    _("Processor"), +                    _("Name"), processor->model_name, +                    _("Machine"), processor->vendor_id, +                    _("Family"), processor->family, +                    _("Frequency"), processor->cpu_mhz, _("MHz"), +                    _("Bus Frequency"), processor->bus_mhz, _("MHz"), +                    _("Module Frequency"), processor->mod_mhz, _("MHz"), +                    _("BogoMips"), processor->bogomips, +                    _("Byte Order"), byte_order_str() +                   );  } diff --git a/modules/devices/sparc/processor.c b/modules/devices/sparc/processor.c index 594117a7..32c7aa94 100644 --- a/modules/devices/sparc/processor.c +++ b/modules/devices/sparc/processor.c @@ -18,6 +18,7 @@  #include "hardinfo.h"  #include "devices.h" +#include "cpu_util.h"  GSList *  processor_scan(void) @@ -26,22 +27,23 @@ processor_scan(void)      FILE *cpuinfo;      gchar buffer[128]; -    cpuinfo = fopen("/proc/cpuinfo", "r"); +    cpuinfo = fopen(PROC_CPUINFO, "r");      if (!cpuinfo) -	return NULL; +        return NULL;      processor = g_new0(Processor, 1);      while (fgets(buffer, 128, cpuinfo)) { -	gchar **tmp = g_strsplit(buffer, ":", 2); +        gchar **tmp = g_strsplit(buffer, ":", 2); -	if (tmp[0] && tmp[1]) { -	    tmp[0] = g_strstrip(tmp[0]); -	    tmp[1] = g_strstrip(tmp[1]); +        if (tmp[0] && tmp[1]) { +            tmp[0] = g_strstrip(tmp[0]); +            tmp[1] = g_strstrip(tmp[1]); -	    get_str("cpu", processor->model_name); -	    get_str("fpu", processor->has_fpu); -	} -	g_strfreev(tmp); +            get_str("cpucaps", processor->cpucaps); +            get_str("cpu", processor->model_name); +            get_str("fpu", processor->has_fpu); +        } +        g_strfreev(tmp);      }      fclose(cpuinfo); @@ -51,14 +53,28 @@ processor_scan(void)      return g_slist_append(NULL, processor);  } +gchar *processor_name(GSList * processors) { +    return processor_name_default(processors); +} + +gchar *processor_describe(GSList * processors) { +    return processor_describe_default(processors); +} +  gchar *  processor_get_info(GSList *processors)  { -        Processor *processor = (Processor *)processors->data; -         -	return g_strdup_printf("[Processor]\n" -	                       "CPU=%s\n" -	                       "FPU=%s\n", -			       processor->model_name, -			       processor->has_fpu); +    Processor *processor = (Processor *)processors->data; + +    return g_strdup_printf("[%s]\n" +                           "%s=%s\n"   /* cpu */ +                           "%s=%s\n"   /* fpu */ +                           "%s=%s\n"   /* byte order */ +                           "%s=%s\n",  /* caps */ +                   _("Processor"), +                   _("CPU"), processor->model_name, +                   _("FPU"), processor->has_fpu, +                   _("Byte Order"), byte_order_str(), +                   _("Capabilities"), processor->cpucaps +                   );  } diff --git a/modules/devices/spd-decode.c b/modules/devices/spd-decode.c index ac1dd52b..2db4895b 100644 --- a/modules/devices/spd-decode.c +++ b/modules/devices/spd-decode.c @@ -11,12 +11,12 @@   * it under the terms of the GNU General Public License as published by   * the Free Software Foundation; either version 2 of the License, or   * (at your option) any later version. - *  + *   * This program is distributed in the hope that it will be useful,   * but WITHOUT ANY WARRANTY; without even the implied warranty of   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the   * GNU General Public License for more details. - *  + *   * You should have received a copy of the GNU General Public License   * along with this program; if not, write to the Free Software   * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. @@ -1497,13 +1497,16 @@ void scan_spd_do(void)      g_slist_free(dimm_list);      g_free(spd_info); -    spd_info = g_strdup_printf("[SPD]\n" -			       "%s\n" -			       "[$ShellParam$]\n" -			       "ViewType=1\n" -			       "ColumnTitle$TextValue=Bank\n" -			       "ColumnTitle$Extra1=Size\n" -			       "ColumnTitle$Extra2=Manufacturer\n" -			       "ColumnTitle$Value=Model\n" "ShowColumnHeaders=true\n", list); +    spd_info = g_strdup_printf("[%s]\n" +                   "%s\n" +                   "[$ShellParam$]\n" +                   "ViewType=1\n" +                   "ColumnTitle$TextValue=%s\n" /* Bank */ +                   "ColumnTitle$Extra1=%s\n" /* Size */ +                   "ColumnTitle$Extra2=%s\n" /* Manufacturer */ +                   "ColumnTitle$Value=%s\n" /* Model */ +                   "ShowColumnHeaders=true\n", +                   _("SPD"), list, +                   _("Bank"), _("Size"), _("Manufacturer"), _("Model") );      g_free(list);  } diff --git a/modules/devices/usb.c b/modules/devices/usb.c index 3a93a3b6..e5088bd2 100644 --- a/modules/devices/usb.c +++ b/modules/devices/usb.c @@ -41,51 +41,59 @@ void __scan_usb_sysfs_add_device(gchar * endpoint, int n)      version = h_sysfs_read_float(endpoint, "version");      if (!(mxpwr = h_sysfs_read_string(endpoint, "bMaxPower"))) { -    	mxpwr = g_strdup("0 mA"); +    	mxpwr = g_strdup_printf("%d %s", 0 , _("mA") );      }      if (!(manufacturer = h_sysfs_read_string(endpoint, "manufacturer"))) { -    	manufacturer = g_strdup("Unknown"); +    	manufacturer = g_strdup(_("(Unknown)"));      }      if (!(product = h_sysfs_read_string(endpoint, "product"))) { -	if (classid == 9) { -	    product = g_strdup_printf("USB %.2f Hub", version); -	} else { -	    product = g_strdup_printf("Unknown USB %.2f Device (class %d)", version, classid); -	} +        if (classid == 9) { +            product = g_strdup_printf(_(/*/%.2f is version*/ "USB %.2f Hub"), version); +        } else { +            product = g_strdup_printf(_("Unknown USB %.2f Device (class %d)"), version, classid); +        }      } -    const gchar *url = vendor_get_url(manufacturer); -    if (url) { -	tmp = g_strdup_printf("%s (%s)", vendor_get_name(manufacturer), url); -	 -	g_free(manufacturer); -	manufacturer = tmp; +    const gchar *v_url = vendor_get_url(manufacturer); +    const gchar *v_name = vendor_get_name(manufacturer); +    gchar *v_str; +    if (v_url != NULL) { +        v_str = g_strdup_printf("%s (%s)", v_name, v_url); +    } else { +        v_str = g_strdup_printf("%s", manufacturer);      }      tmp = g_strdup_printf("USB%d", n);      usb_list = h_strdup_cprintf("$%s$%s=\n", usb_list, tmp, product); -    strhash = g_strdup_printf("[Device Information]\n" -			      "Product=%s\n" -			      "Manufacturer=%s\n" -			      "Speed=%.2fMbit/s\n" -			      "Max Current=%s\n" -			      "[Misc]\n" -			      "USB Version=%.2f\n" -			      "Class=0x%x\n" -			      "Vendor=0x%x\n" -			      "Product ID=0x%x\n" -			      "Bus=%d\n", -			      product, -			      manufacturer, -			      speed, -			      mxpwr, -			      version, classid, vendor, prodid, bus); +    strhash = g_strdup_printf("[%s]\n" +             /* Product */      "%s=%s\n" +             /* Manufacturer */ "%s=%s\n" +             /* Speed */        "%s=%.2f %s\n" +             /* Max Current */  "%s=%s\n" +                  "[%s]\n" +             /* USB Version */  "%s=%.2f\n" +             /* Class */        "%s=0x%x\n" +             /* Vendor */       "%s=0x%x\n" +             /* Product ID */   "%s=0x%x\n" +             /* Bus */          "%s=%d\n", +                  _("Device Information"), +                  _("Product"), product, +                  _("Manufacturer"), v_str, +                  _("Speed"), speed, _("Mbit/s"), +                  _("Max Current"), mxpwr, +                  _("Misc"), +                  _("USB Version"), version, +                  _("Class"), classid, +                  _("Vendor ID"), vendor, +                  _("Product ID"), prodid, +                  _("Bus"), bus);      moreinfo_add_with_prefix("DEV", tmp, strhash);      g_free(tmp); +    g_free(v_str);      g_free(manufacturer);      g_free(product);      g_free(mxpwr); @@ -106,7 +114,7 @@ gboolean __scan_usb_sysfs(void)         moreinfo_del_with_prefix("DEV:USB");  	g_free(usb_list);      } -    usb_list = g_strdup("[USB Devices]\n"); +    usb_list = g_strdup_printf("[%s]\n", _("USB Devices"));      while ((filename = (gchar *) g_dir_read_name(sysfs))) {  	gchar *endpoint = @@ -145,7 +153,7 @@ gboolean __scan_usb_procfs(void)  	moreinfo_del_with_prefix("DEV:USB");  	g_free(usb_list);      } -    usb_list = g_strdup("[USB Devices]\n"); +    usb_list = g_strdup_printf("[%s]\n", _("USB Devices"));      while (fgets(buffer, 128, dev)) {  	tmp = buffer; @@ -179,50 +187,68 @@ gboolean __scan_usb_procfs(void)  	    if (product && *product == '\0') {  		g_free(product);  		if (classid == 9) { -		    product = g_strdup_printf("USB %.2f Hub", ver); +		    product = g_strdup_printf(_("USB %.2f Hub"), ver);  		} else { -		    product = g_strdup_printf("Unknown USB %.2f Device (class %d)", ver, classid); +		    product = g_strdup_printf(_("Unknown USB %.2f Device (class %d)"), ver, classid);  		}  	    } -	    if (classid == 9) {	/* hub */ -		usb_list = h_strdup_cprintf("[%s#%d]\n", usb_list, product, n); -	    } else {		/* everything else */ -		usb_list = h_strdup_cprintf("$%s$%s=\n", usb_list, tmp, product); - -		const gchar *url = vendor_get_url(manuf); -		if (url) { -		    gchar *tmp = g_strdup_printf("%s (%s)", vendor_get_name(manuf), -						 url); -		    g_free(manuf); -		    manuf = tmp; -		} - -		gchar *strhash = g_strdup_printf("[Device Information]\n" "Product=%s\n", -						 product); -		if (manuf && strlen(manuf)) -		    strhash = h_strdup_cprintf("Manufacturer=%s\n", strhash, manuf); - -		strhash = h_strdup_cprintf("[Port #%d]\n" -					   "Speed=%.2fMbit/s\n" -					   "Max Current=%s\n" -					   "[Misc]\n" -					   "USB Version=%.2f\n" -					   "Revision=%.2f\n" -					   "Class=0x%x\n" -					   "Vendor=0x%x\n" -					   "Product ID=0x%x\n" -					   "Bus=%d\n" "Level=%d\n", -					   strhash, port, speed, mxpwr, ver, rev, classid, vendor, prodid, bus, level); - -		moreinfo_add_with_prefix("DEV", tmp, strhash); -		g_free(tmp); -	    } +        if (classid == 9) {	/* hub */ +            usb_list = h_strdup_cprintf("[%s#%d]\n", usb_list, product, n); +        } else {		/* everything else */ +            usb_list = h_strdup_cprintf("$%s$%s=\n", usb_list, tmp, product); + +        EMPIFNULL(manuf); +        const gchar *v_url = vendor_get_url(manuf); +        const gchar *v_name = vendor_get_name(manuf); +        gchar *v_str = NULL; +        if (strlen(manuf)) { +            if (v_url != NULL) +                v_str = g_strdup_printf("%s (%s)", v_name, v_url); +            else +                v_str = g_strdup_printf("%s", manuf); +        } +        UNKIFNULL(v_str); +        UNKIFNULL(product); + +        gchar *strhash = g_strdup_printf("[%s]\n" "%s=%s\n" "%s=%s\n", +                        _("Device Information"), +                        _("Product"), product, +                        _("Manufacturer"), v_str); + +        strhash = h_strdup_cprintf("[%s #%d]\n" +                  /* Speed */       "%s=%.2f %s\n" +                  /* Max Current */ "%s=%s\n" +                       "[%s]\n" +                  /* USB Version */ "%s=%.2f\n" +                  /* Revision */    "%s=%.2f\n" +                  /* Class */       "%s=0x%x\n" +                  /* Vendor */      "%s=0x%x\n" +                  /* Product ID */  "%s=0x%x\n" +                  /* Bus */         "%s=%d\n" +                  /* Level */       "%s=%d\n", +                       strhash, +                       _("Port"), port, +                       _("Speed"), speed, _("Mbit/s"), +                       _("Max Current"), mxpwr, +                       _("Misc"), +                       _("USB Version"), ver, +                       _("Revision"), rev, +                       _("Class"), classid, +                       _("Vendor ID"), vendor, +                       _("Product ID"), prodid, +                       _("Bus"), bus, +                       _("Level"), level); + +        moreinfo_add_with_prefix("DEV", tmp, strhash); +        g_free(v_str); +        g_free(tmp); +        }  	    g_free(manuf);  	    g_free(product); -	    manuf = g_strdup(""); -	    product = g_strdup(""); +	    manuf = NULL; +	    product = NULL;  	    port = classid = 0;  	}      } @@ -274,35 +300,63 @@ void __scan_usb_lsusb_add_device(char *buffer, int bufsize, FILE * lsusb, int us      }      if (dev_class && strstr(dev_class, "0 (Defined at Interface level)")) { -	g_free(dev_class); -	if (int_class) { -	    dev_class = int_class; -	} else { -	    dev_class = g_strdup("Unknown"); -	} +        g_free(dev_class); +        if (int_class) { +            dev_class = int_class; +        } else { +            dev_class = g_strdup(_("(Unknown)")); +        }      } else -	dev_class = g_strdup("Unknown"); +    dev_class = g_strdup(_("(Unknown)"));      tmp = g_strdup_printf("USB%d", usb_device_number);      usb_list = h_strdup_cprintf("$%s$%s=\n", usb_list, tmp, name); -    strhash = g_strdup_printf("[Device Information]\n" -			      "Product=%s\n" -			      "Manufacturer=%s\n" -			      "Max Current=%s\n" -			      "[Misc]\n" -			      "USB Version=%s\n" -			      "Class=%s\n" -			      "Vendor=0x%x\n" -			      "Product ID=0x%x\n" -			      "Bus=%d\n", -			      product ? g_strstrip(product) : "Unknown", -			      vendor ? g_strstrip(vendor) : "Unknown", -			      max_power ? g_strstrip(max_power) : "Unknown", -			      version ? g_strstrip(version) : "Unknown", -			      dev_class ? g_strstrip(dev_class) : "Unknown", vendor_id, product_id, bus); +    const gchar *v_url = vendor_get_url(vendor); +    const gchar *v_name = vendor_get_name(vendor); +    gchar *v_str; +    if (v_url != NULL) { +        v_str = g_strdup_printf("%s (%s)", v_name, v_url); +    } else { +        v_str = g_strdup_printf("%s", g_strstrip(vendor) ); +    } + +    if (max_power != NULL) { +        int mA = atoi(g_strstrip(max_power)); +        gchar *trent_steel = g_strdup_printf("%d %s", mA, _("mA")); +        g_free(max_power); +        max_power = trent_steel; +    } + +    UNKIFNULL(product); +    UNKIFNULL(v_str); +    UNKIFNULL(max_power); +    UNKIFNULL(version); +    UNKIFNULL(dev_class); + +    strhash = g_strdup_printf("[%s]\n" +             /* Product */      "%s=%s\n" +             /* Manufacturer */ "%s=%s\n" +             /* Max Current */  "%s=%s\n" +                            "[%s]\n" +             /* USB Version */ "%s=%s\n" +             /* Class */       "%s=%s\n" +             /* Vendor ID */   "%s=0x%x\n" +             /* Product ID */  "%s=0x%x\n" +             /* Bus */         "%s=%d\n", +                _("Device Information"), +                _("Product"), g_strstrip(product), +                _("Vendor"), v_str, +                _("Max Current"), g_strstrip(max_power), +                _("Misc"), +                _("USB Version"), g_strstrip(version), +                _("Class"), g_strstrip(dev_class), +                _("Vendor ID"), vendor_id, +                _("Product ID"), product_id, +                _("Bus"), bus);      moreinfo_add_with_prefix("DEV", tmp, strhash); +    g_free(v_str);      g_free(vendor);      g_free(product);      g_free(max_power); @@ -356,25 +410,25 @@ gboolean __scan_usb_lsusb(void)      if (usb_list) {         moreinfo_del_with_prefix("DEV:USB"); -	g_free(usb_list); +        g_free(usb_list);      } -    usb_list = g_strdup("[USB Devices]\n"); +    usb_list = g_strdup_printf("[%s]\n", _("USB Devices"));      while (fgets(buffer, sizeof(buffer), temp_lsusb)) {          if (g_str_has_prefix(buffer, "Bus ")) {             __scan_usb_lsusb_add_device(buffer, sizeof(buffer), temp_lsusb, ++usb_device_number);          }      } -     +      fclose(temp_lsusb); -     +      return usb_device_number > 0;  }  void __scan_usb(void)  {      if (!__scan_usb_procfs()) { -	if (!__scan_usb_sysfs()) { +        if (!__scan_usb_sysfs()) {               __scan_usb_lsusb();          }      } diff --git a/modules/devices/x86/processor.c b/modules/devices/x86/processor.c index 25dc6c4a..ad3c7ca4 100644 --- a/modules/devices/x86/processor.c +++ b/modules/devices/x86/processor.c @@ -18,6 +18,10 @@  #include "hardinfo.h"  #include "devices.h" +#include "cpu_util.h" + +#include "x86_data.h" +#include "x86_data.c"  /*   * This function is partly based on x86cpucaps @@ -148,10 +152,10 @@ static gchar *__cache_get_info_as_string(Processor *processor)      for (cache_list = processor->cache; cache_list; cache_list = cache_list->next) {          cache = (ProcessorCache *)cache_list->data; -        result = h_strdup_cprintf("Level %d (%s)=%d-way set-associative, %d sets, %dKB size\n", +        result = h_strdup_cprintf(_("Level %d (%s)=%d-way set-associative, %d sets, %dKB size\n"),                                    result,                                    cache->level, -                                  cache->type, +                                  C_("cache-type", cache->type),                                    cache->ways_of_associativity,                                    cache->number_of_sets,                                    cache->size); @@ -160,6 +164,14 @@ static gchar *__cache_get_info_as_string(Processor *processor)      return result;  } +/* This is not used directly, but creates translatable strings for + * the type string returned from /sys/.../cache */ +static const char* cache_types[] = { +    NC_("cache-type", /*/cache type, as appears in: Level 1 (Data)*/ "Data"), +    NC_("cache-type", /*/cache type, as appears in: Level 1 (Instruction)*/ "Instruction"), +    NC_("cache-type", /*/cache type, as appears in: Level 2 (Unified)*/ "Unified") +}; +  static void __cache_obtain_info(Processor *processor)  {      ProcessorCache *cache; @@ -214,33 +226,6 @@ fail:      g_free(endpoint);  } -int processor_has_flag(gchar * strflags, gchar * strflag) -{ -    gchar **flags; -    gint ret = 0; -    if (strflags == NULL || strflag == NULL) -        return 0; -    flags = g_strsplit(strflags, " ", 0); -    ret = g_strv_contains((const gchar * const *)flags, strflag); -    g_strfreev(flags); -    return ret; -} - -static gint get_cpu_int(const gchar* file, gint cpuid) { -    gchar *tmp0 = NULL; -    gchar *tmp1 = NULL; -    gint ret = 0; - -    tmp0 = g_strdup_printf("/sys/devices/system/cpu/cpu%d/%s", cpuid, file); -    g_file_get_contents(tmp0, &tmp1, NULL, NULL); -    if (tmp1) -        ret = atol(tmp1); - -    g_free(tmp0); -    g_free(tmp1); -    return ret; -} -  GSList *processor_scan(void)  {      GSList *procs = NULL, *l = NULL; @@ -248,7 +233,7 @@ GSList *processor_scan(void)      FILE *cpuinfo;      gchar buffer[512]; -    cpuinfo = fopen("/proc/cpuinfo", "r"); +    cpuinfo = fopen(PROC_CPUINFO, "r");      if (!cpuinfo)          return NULL; @@ -280,6 +265,7 @@ GSList *processor_scan(void)              get_str("flags", processor->flags);              get_str("bugs", processor->bugs);              get_str("power management", processor->pm); +            get_str("microcode", processor->microcode);              get_int("cache size", processor->cache_size);              get_float("cpu MHz", processor->cpu_mhz);              get_float("bogomips", processor->bogomips); @@ -290,6 +276,7 @@ GSList *processor_scan(void)              get_str("hlt_bug", processor->bug_hlt);              get_str("f00f_bug", processor->bug_f00f);              get_str("coma_bug", processor->bug_coma); +            /* sep_bug? */              get_int("model", processor->model);              get_int("cpu family", processor->family); @@ -298,6 +285,8 @@ GSList *processor_scan(void)          g_strfreev(tmp);      } +    fclose(cpuinfo); +      /* finish last */      if (processor)          procs = g_slist_append(procs, processor); @@ -305,9 +294,17 @@ GSList *processor_scan(void)      for (l = procs; l; l = l->next) {          processor = (Processor *) l->data; +        STRIFNULL(processor->microcode, _("(Not Available)") ); +          get_processor_strfamily(processor);          __cache_obtain_info(processor); +#define NULLIFNOTYES(f) if (processor->f) if (strcmp(processor->f, "yes") != 0) { g_free(processor->f); processor->f = NULL; } +        NULLIFNOTYES(bug_fdiv); +        NULLIFNOTYES(bug_hlt); +        NULLIFNOTYES(bug_f00f); +        NULLIFNOTYES(bug_coma); +          if (processor->bugs == NULL || g_strcmp0(processor->bugs, "") == 0) {              g_free(processor->bugs);              /* make bugs list on old kernels that don't offer one */ @@ -337,291 +334,38 @@ GSList *processor_scan(void)              g_strchug(processor->pm);          } -        /* freq */ -        processor->cpukhz_cur = get_cpu_int("cpufreq/scaling_cur_freq", processor->id); -        processor->cpukhz_min = get_cpu_int("cpufreq/scaling_min_freq", processor->id); -        processor->cpukhz_max = get_cpu_int("cpufreq/scaling_max_freq", processor->id); -        if (processor->cpukhz_max) -            processor->cpu_mhz = processor->cpukhz_max / 1000; -    } - -    fclose(cpuinfo); - -    return procs; -} - -/* - * Sources: - * - Linux' cpufeature.h - * - http://gentoo-wiki.com/Cpuinfo - * - Intel IA-32 Architecture Software Development Manual - * - https://unix.stackexchange.com/questions/43539/what-do-the-flags-in-proc-cpuinfo-mean - */ -static struct { -    char *name, *meaning; -} flag_meaning[] = { -	{ "3dnow",	"3DNow! Technology"				}, -	{ "3dnowext",	"Extended 3DNow! Technology"			}, -	{ "fpu",	"Floating Point Unit"				}, -	{ "vme",	"Virtual 86 Mode Extension"			}, -	{ "de",		"Debug Extensions - I/O breakpoints"		}, -	{ "pse",	"Page Size Extensions (4MB pages)"		}, -	{ "tsc",	"Time Stamp Counter and RDTSC instruction"	}, -	{ "msr",	"Model Specific Registers"			}, -	{ "pae",	"Physical Address Extensions"			}, -	{ "mce",	"Machine Check Architecture"			}, -	{ "cx8",	"CMPXCHG8 instruction"				}, -	{ "apic",	"Advanced Programmable Interrupt Controller"	}, -	{ "sep",	"Fast System Call (SYSENTER/SYSEXIT)"		}, -	{ "mtrr",	"Memory Type Range Registers"			}, -	{ "pge",	"Page Global Enable"				}, -	{ "mca",	"Machine Check Architecture"			}, -	{ "cmov",	"Conditional Move instruction"			}, -	{ "pat",	"Page Attribute Table"				}, -	{ "pse36",	"36bit Page Size Extensions"			}, -	{ "psn",	"96 bit Processor Serial Number"		}, -	{ "mmx",	"MMX technology"				}, -	{ "mmxext",	"Extended MMX Technology"			}, -	{ "cflush",	"Cache Flush"					}, -	{ "dtes",	"Debug Trace Store"				}, -	{ "fxsr",	"FXSAVE and FXRSTOR instructions"		}, -	{ "kni",	"Streaming SIMD instructions"			}, -	{ "xmm",	"Streaming SIMD instructions"			}, -	{ "ht",		"HyperThreading"				}, -	{ "mp",		"Multiprocessing Capable"			}, -	{ "sse",	"SSE instructions"				}, -	{ "sse2",	"SSE2 (WNI) instructions"			}, -	{ "acc",	"Automatic Clock Control"			}, -	{ "ia64",	"IA64 Instructions"				}, -	{ "syscall",	"SYSCALL and SYSEXIT instructions"		}, -	{ "nx",		"No-execute Page Protection"			}, -	{ "xd",		"Execute Disable"				}, -	{ "clflush",	"Cache Line Flush instruction"			}, -	{ "acpi",	"Thermal Monitor and Software Controlled Clock"	}, -	{ "dts",	"Debug Store"					}, -	{ "ss",		"Self Snoop"					}, -	{ "tm",		"Thermal Monitor"				}, -	{ "pbe",	"Pending Break Enable"				}, -	{ "pb",		"Pending Break Enable"				}, -	{ "pn",		"Processor serial number"			}, -	{ "ds",		"Debug Store"					}, -	{ "xmm2",	"Streaming SIMD Extensions-2"			}, -	{ "xmm3",	"Streaming SIMD Extensions-3"			}, -	{ "selfsnoop",	"CPU self snoop"				}, -	{ "rdtscp",	"RDTSCP"					}, -	{ "recovery",	"CPU in recovery mode"				}, -	{ "longrun",	"Longrun power control"				}, -	{ "lrti",	"LongRun table interface"			}, -	{ "cxmmx",	"Cyrix MMX extensions"				}, -	{ "k6_mtrr",	"AMD K6 nonstandard MTRRs"			}, -	{ "cyrix_arr",	"Cyrix ARRs (= MTRRs)"				}, -	{ "centaur_mcr","Centaur MCRs (= MTRRs)"			}, -	{ "constant_tsc","TSC ticks at a constant rate"			}, -	{ "up",		"smp kernel running on up"			}, -	{ "fxsave_leak","FXSAVE leaks FOP/FIP/FOP"			}, -	{ "arch_perfmon","Intel Architectural PerfMon"			}, -	{ "pebs",	"Precise-Event Based Sampling"			}, -	{ "bts",	"Branch Trace Store"				}, -	{ "sync_rdtsc",	"RDTSC synchronizes the CPU"			}, -	{ "rep_good",	"rep microcode works well on this CPU"		}, -	{ "mwait",	"Monitor/Mwait support"				}, -	{ "ds_cpl",	"CPL Qualified Debug Store"			}, -	{ "est",	"Enhanced SpeedStep"				}, -	{ "tm2",	"Thermal Monitor 2"				}, -	{ "cid",	"Context ID"					}, -	{ "xtpr",	"Send Task Priority Messages"			}, -	{ "xstore",	"on-CPU RNG present (xstore insn)"		}, -	{ "xstore_en",	"on-CPU RNG enabled"				}, -	{ "xcrypt",	"on-CPU crypto (xcrypt insn)"			}, -	{ "xcrypt_en",	"on-CPU crypto enabled"				}, -	{ "ace2",	"Advanced Cryptography Engine v2"		}, -	{ "ace2_en",	"ACE v2 enabled"				}, -	{ "phe",	"PadLock Hash Engine"				}, -	{ "phe_en",	"PHE enabled"					}, -	{ "pmm",	"PadLock Montgomery Multiplier"			}, -	{ "pmm_en",	"PMM enabled"					}, -	{ "lahf_lm",	"LAHF/SAHF in long mode"			}, -	{ "cmp_legacy",	"HyperThreading not valid"			}, -	{ "lm",		"LAHF/SAHF in long mode"			}, -	{ "ds_cpl",	"CPL Qualified Debug Store"			}, -	{ "vmx",	"Virtualization support (Intel)"		}, -	{ "svm",	"Virtualization support (AMD)"			}, -	{ "est",	"Enhanced SpeedStep"				}, -	{ "tm2",	"Thermal Monitor 2"				}, -	{ "ssse3",	"Supplemental Streaming SIMD Extension 3"	}, -	{ "cx16",	"CMPXCHG16B instruction"			}, -	{ "xptr",	"Send Task Priority Messages"			}, -	{ "pebs",	"Precise Event Based Sampling"			}, -	{ "bts",	"Branch Trace Store"				}, -	{ "ida",	"Intel Dynamic Acceleration"			}, -	{ "arch_perfmon","Intel Architectural PerfMon"			}, -	{ "pni",	"Streaming SIMD Extension 3 (Prescott New Instruction)"	}, -	{ "rep_good",	"rep microcode works well on this CPU"		}, -	{ "ts",		"Thermal Sensor"				}, -	{ "sse3",	"Streaming SIMD Extension 3"			}, -	{ "sse4",	"Streaming SIMD Extension 4"			}, -	{ "tni",	"Tejas New Instruction"				}, -	{ "nni",	"Nehalem New Instruction"			}, -	{ "tpr",	"Task Priority Register"			}, -	{ "vid",	"Voltage Identifier"				}, -	{ "fid", 	"Frequency Identifier"				}, -	{ "dtes64", 	"64-bit Debug Store"				}, -	{ "monitor", 	"Monitor/Mwait support"				}, -	{ "sse4_1",     "Streaming SIMD Extension 4.1"                  }, -	{ "sse4_2",     "Streaming SIMD Extension 4.2"                  }, -	{ "nopl",       "NOPL instructions"                             }, -	{ "cxmmx",      "Cyrix MMX extensions"                          }, -	{ "xtopology",  "CPU topology enum extensions"                  }, -	{ "nonstop_tsc", "TSC does not stop in C states"                }, -	{ "eagerfpu",   "Non lazy FPU restor"                           }, -	{ "pclmulqdq",  "Perform a Carry-Less Multiplication of Quadword instruction" }, -	{ "smx",        "Safer mode: TXT (TPM support)"                 }, -	{ "pdcm",       "Performance capabilities"                      }, -	{ "pcid",       "Process Context Identifiers"                   }, -	{ "x2apic",     "x2APIC"                                        }, -	{ "popcnt",     "Set bit count instructions"                    }, -	{ "aes",        "Advanced Encryption Standard"                  }, -	{ "aes-ni",     "Advanced Encryption Standard (New Instructions)" }, -	{ "xsave",      "Save Processor Extended States"                }, -	{ "avx",        "Advanced Vector Instructions"                  }, -	{ NULL,		NULL						}, -}; - -static struct { -    char *name, *meaning; -} bug_meaning[] = { -	{ "f00f",        "Intel F00F bug"    }, -	{ "fdiv",        "FPU FDIV"          }, -	{ "coma",        "Cyrix 6x86 coma"   }, -	{ "tlb_mmatch",  "AMD Erratum 383"   }, -	{ "apic_c1e",    "AMD Erratum 400"   }, -	{ "11ap",        "Bad local APIC aka 11AP"  }, -	{ "fxsave_leak", "FXSAVE leaks FOP/FIP/FOP" }, -	{ "clflush_monitor",  "AAI65, CLFLUSH required before MONITOR" }, -	{ "sysret_ss_attrs",  "SYSRET doesn't fix up SS attrs" }, -	{ "espfix",      "IRET to 16-bit SS corrupts ESP/RSP high bits" }, -	{ "null_seg",    "Nulling a selector preserves the base" },         /* see: detect_null_seg_behavior() */ -	{ "swapgs_fence","SWAPGS without input dep on GS" }, -	{ "monitor",     "IPI required to wake up remote CPU" }, -	{ "amd_e400",    "AMD Erratum 400" }, -	{ NULL,		NULL						}, -}; - -/* from arch/x86/kernel/cpu/powerflags.h */ -static struct { -    char *name, *meaning; -} pm_meaning[] = { -	{ "ts",            "temperature sensor"     }, -	{ "fid",           "frequency id control"   }, -	{ "vid",           "voltage id control"     }, -	{ "ttp",           "thermal trip"           }, -	{ "tm",            "hardware thermal control"   }, -	{ "stc",           "software thermal control"   }, -	{ "100mhzsteps",   "100 MHz multiplier control" }, -	{ "hwpstate",      "hardware P-state control"   }, -/*	{ "",              "tsc invariant mapped to constant_tsc" }, */ -	{ "cpb",           "core performance boost"     }, -	{ "eff_freq_ro",   "Readonly aperf/mperf"       }, -	{ "proc_feedback", "processor feedback interface" }, -	{ "acc_power",     "accumulated power mechanism"  }, -	{ NULL,		NULL						}, -}; - -GHashTable *cpu_flags = NULL; - -static void -populate_cpu_flags_list_internal() -{ -    int i; - -    DEBUG("using internal CPU flags database"); +        /* topo & freq */ +        processor->cpufreq = cpufreq_new(processor->id); +        processor->cputopo = cputopo_new(processor->id); -    for (i = 0; flag_meaning[i].name != NULL; i++) { -        g_hash_table_insert(cpu_flags, flag_meaning[i].name, -                            flag_meaning[i].meaning); +        if (processor->cpufreq->cpukhz_max) +            processor->cpu_mhz = processor->cpufreq->cpukhz_max / 1000;      } -    for (i = 0; bug_meaning[i].name != NULL; i++) { -        g_hash_table_insert(cpu_flags, bug_meaning[i].name, -                            bug_meaning[i].meaning); -    } -    for (i = 0; pm_meaning[i].name != NULL; i++) { -        g_hash_table_insert(cpu_flags, pm_meaning[i].name, -                            pm_meaning[i].meaning); -    } -} - -void cpu_flags_init(void) -{ -    gint i; -    gchar *path; - -    cpu_flags = g_hash_table_new(g_str_hash, g_str_equal); - -    path = g_build_filename(g_get_home_dir(), ".hardinfo", "cpuflags.conf", NULL); -    if (!g_file_test(path, G_FILE_TEST_EXISTS)) { -        populate_cpu_flags_list_internal(); -    } else { -        GKeyFile *flags_file; -        DEBUG("using %s as CPU flags database", path); - -        flags_file = g_key_file_new(); -        if (g_key_file_load_from_file(flags_file, path, 0, NULL)) { -            gchar **flag_keys; - -            flag_keys = g_key_file_get_keys(flags_file, "flags", -                                            NULL, NULL); -            if (!flag_keys) { -                DEBUG("error while using %s as CPU flags database, falling back to internal", -                      path); -                populate_cpu_flags_list_internal(); -            } else { -                for (i = 0; flag_keys[i]; i++) { -                    gchar *meaning; - -                    meaning = g_key_file_get_string(flags_file, "flags", -                                                    flag_keys[i], NULL); - -                    g_hash_table_insert(cpu_flags, g_strdup(flag_keys[i]), meaning); - -                    /* can't free meaning */ -                } - -                g_strfreev(flag_keys); -            } -        } - -        g_key_file_free(flags_file); -    } - -    g_free(path); +    return procs;  } -gchar *processor_get_capabilities_from_flags(gchar * strflags) +gchar *processor_get_capabilities_from_flags(gchar *strflags, gchar *lookup_prefix)  { -    /* FIXME: -     * - Separate between processor capabilities, additional instructions and whatnot. -     */      gchar **flags, **old; +    gchar tmp_flag[64] = ""; +    const gchar *meaning;      gchar *tmp = NULL;      gint j = 0; -    if (!cpu_flags) { -        cpu_flags_init(); -    } -      flags = g_strsplit(strflags, " ", 0);      old = flags;      while (flags[j]) { -	gchar *meaning = g_hash_table_lookup(cpu_flags, flags[j]); +        sprintf(tmp_flag, "%s%s", lookup_prefix, flags[j]); +        meaning = x86_flag_meaning(tmp_flag); -	if (meaning) { -  	  tmp = h_strdup_cprintf("%s=%s\n", tmp, flags[j], meaning); +        if (meaning) { +            tmp = h_strdup_cprintf("%s=%s\n", tmp, flags[j], meaning);          } else { -  	  tmp = h_strdup_cprintf("%s=\n", tmp, flags[j]); +            tmp = h_strdup_cprintf("%s=\n", tmp, flags[j]);          } -	j++; +        j++;      }      if (tmp == NULL || g_strcmp0(tmp, "") == 0)          tmp = g_strdup_printf("%s=%s\n", "empty", _("Empty List")); @@ -632,96 +376,120 @@ gchar *processor_get_capabilities_from_flags(gchar * strflags)  gchar *processor_get_detailed_info(Processor * processor)  { -    gchar *tmp_flags, *tmp_bugs, *tmp_pm, *ret, *cache_info; +    gchar *tmp_flags, *tmp_bugs, *tmp_pm, *tmp_cpufreq, *tmp_topology, *ret, *cache_info; -    tmp_flags = processor_get_capabilities_from_flags(processor->flags); -    tmp_bugs = processor_get_capabilities_from_flags(processor->bugs); -    tmp_pm = processor_get_capabilities_from_flags(processor->pm); +    tmp_flags = processor_get_capabilities_from_flags(processor->flags, ""); +    tmp_bugs = processor_get_capabilities_from_flags(processor->bugs, "bug:"); +    tmp_pm = processor_get_capabilities_from_flags(processor->pm, "pm:");      cache_info = __cache_get_info_as_string(processor); -    ret = g_strdup_printf(_("[Processor]\n" -			  "Name=%s\n" -			  "Family, model, stepping=%d, %d, %d (%s)\n" -			  "Vendor=%s\n" -			  "[Configuration]\n" -			  "Cache Size=%dkb\n" -			  "Frequency=%.2fMHz\n" -			  "BogoMIPS=%.2f\n" -			  "Byte Order=%s\n" -			  "[Frequency Scaling]\n" -			  "Minimum=%d kHz\n" -			  "Maximum=%d kHz\n" -			  "Current=%d kHz\n" -			  "[Features]\n" -			  "Has FPU=%s\n" -			  "[Cache]\n" -			  "%s\n" -			  "[Power Management]\n" -			  "%s" -			  "[Bugs]\n" -			  "%s" -			  "[Capabilities]\n" -			  "%s"), -			  processor->model_name, -			  processor->family, -			  processor->model, -			  processor->stepping, -			  processor->strmodel, -			  vendor_get_name(processor->vendor_id), -			  processor->cache_size, -			  processor->cpu_mhz, processor->bogomips, -#if G_BYTE_ORDER == G_LITTLE_ENDIAN -			  "Little Endian", -#else -			  "Big Endian", -#endif -			  processor->cpukhz_min, -			  processor->cpukhz_max, -			  processor->cpukhz_cur, -			  processor->has_fpu  ? processor->has_fpu  : "no", -			  cache_info, -			  tmp_pm, tmp_bugs, tmp_flags); +    tmp_topology = cputopo_section_str(processor->cputopo); +    tmp_cpufreq = cpufreq_section_str(processor->cpufreq); + +    ret = g_strdup_printf("[%s]\n" +                       "%s=%s\n" +                       "%s=%d, %d, %d (%s)\n" /* family, model, stepping (decoded name) */ +                       "%s=%s\n"      /* vendor */ +                       "%s=%s\n"      /* microcode */ +                       "[%s]\n"       /* configuration */ +                       "%s=%d %s\n"   /* cache size (from cpuinfo) */ +                       "%s=%.2f %s\n" /* frequency */ +                       "%s=%.2f\n"    /* bogomips */ +                       "%s=%s\n"      /* byte order */ +                       "%s"     /* topology */ +                       "%s"     /* frequency scaling */ +                       "[%s]\n" /* cache */ +                       "%s\n" +                       "[%s]\n" /* pm */ +                       "%s" +                       "[%s]\n" /* bugs */ +                       "%s" +                       "[%s]\n" /* flags */ +                       "%s", +                   _("Processor"), +                   _("Model Name"), processor->model_name, +                   _("Family, model, stepping"), +                   processor->family, +                   processor->model, +                   processor->stepping, +                   processor->strmodel, +                   _("Vendor"), vendor_get_name(processor->vendor_id), +                   _("Microcode Version"), processor->microcode, +                   _("Configuration"), +                   _("Cache Size"), processor->cache_size, _("kb"), +                   _("Frequency"), processor->cpu_mhz, _("MHz"), +                   _("BogoMips"), processor->bogomips, +                   _("Byte Order"), byte_order_str(), +                   tmp_topology, +                   tmp_cpufreq, +                   _("Cache"), cache_info, +                   _("Power Management"), tmp_pm, +                   _("Bug Workarounds"), tmp_bugs, +                   _("Capabilities"), tmp_flags );      g_free(tmp_flags);      g_free(tmp_bugs);      g_free(tmp_pm);      g_free(cache_info); +    g_free(tmp_cpufreq); +    g_free(tmp_topology); +    return ret; +} + +gchar *processor_name(GSList * processors) { +    return processor_name_default(processors); +} +gchar *processor_describe(GSList * processors) { +    return processor_describe_default(processors); +} + +gchar *processor_meta(GSList * processors) { +    gchar *meta_cpu_name = processor_name(processors); +    gchar *meta_cpu_desc = processor_describe(processors); +    gchar *ret = NULL; +    UNKIFNULL(meta_cpu_desc); +    ret = g_strdup_printf("[%s]\n" +                        "%s=%s\n" +                        "%s=%s\n", +                        _("Package Information"), +                        _("Name"), meta_cpu_name, +                        _("Description"), meta_cpu_desc); +    g_free(meta_cpu_desc);      return ret;  }  gchar *processor_get_info(GSList * processors)  {      Processor *processor; +    gchar *ret, *tmp, *hashkey; +    gchar *meta; /* becomes owned by more_info? no need to free? */ +    GSList *l; -    if (g_slist_length(processors) > 1) { -	gchar *ret, *tmp, *hashkey; -	GSList *l; - -	tmp = g_strdup(""); +    tmp = g_strdup_printf("$CPU_META$%s=\n", _("Package Information") ); -	for (l = processors; l; l = l->next) { -	    processor = (Processor *) l->data; +    meta = processor_meta(processors); +    moreinfo_add_with_prefix("DEV", "CPU_META", meta); -	    tmp = g_strdup_printf(_("%s$CPU%d$%s=%.2fMHz\n"), -				  tmp, processor->id, -				  processor->model_name, -				  processor->cpu_mhz); - -	    hashkey = g_strdup_printf("CPU%d", processor->id); -	    moreinfo_add_with_prefix("DEV", hashkey, -				processor_get_detailed_info(processor)); -           g_free(hashkey); -	} +    for (l = processors; l; l = l->next) { +        processor = (Processor *) l->data; -	ret = g_strdup_printf("[$ShellParam$]\n" -			      "ViewType=1\n" -			      "[Processors]\n" -			      "%s", tmp); -	g_free(tmp); +        tmp = g_strdup_printf("%s$CPU%d$%s=%.2f %s\n", +                  tmp, processor->id, +                  processor->model_name, +                  processor->cpu_mhz, _("MHz")); -	return ret; +        hashkey = g_strdup_printf("CPU%d", processor->id); +        moreinfo_add_with_prefix("DEV", hashkey, +                processor_get_detailed_info(processor)); +        g_free(hashkey);      } -    processor = (Processor *) processors->data; -    return processor_get_detailed_info(processor); +    ret = g_strdup_printf("[$ShellParam$]\n" +                  "ViewType=1\n" +                  "[Processors]\n" +                  "%s", tmp); +    g_free(tmp); + +    return ret;  } + diff --git a/modules/devices/x86/x86_data.c b/modules/devices/x86/x86_data.c new file mode 100644 index 00000000..ebd434bb --- /dev/null +++ b/modules/devices/x86/x86_data.c @@ -0,0 +1,344 @@ +/* + * rpiz - https://github.com/bp0/rpiz + * Copyright (C) 2017  Burt P. <pburt0@gmail.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. + * + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include "x86_data.h" + +#ifndef C_ +#define C_(Ctx, String) String +#endif +#ifndef NC_ +#define NC_(Ctx, String) String +#endif + +/* sources: + *   https://unix.stackexchange.com/a/43540 + *   https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable.git/tree/arch/x86/include/asm/cpufeatures.h?id=refs/tags/v4.9 + *   hardinfo: modules/devices/x86/processor.c + */ +static struct { +    char *name, *meaning; +} tab_flag_meaning[] = { +/* Intel-defined CPU features, CPUID level 0x00000001 (edx) + * See also Wikipedia and table 2-27 in Intel Advanced Vector Extensions Programming Reference */ +    { "fpu",     NC_("x86-flag", /*/flag:fpu*/  "Onboard FPU (floating point support)") }, +    { "vme",     NC_("x86-flag", /*/flag:vme*/  "Virtual 8086 mode enhancements") }, +    { "de",      NC_("x86-flag", /*/flag:de*/  "Debugging Extensions (CR4.DE)") }, +    { "pse",     NC_("x86-flag", /*/flag:pse*/  "Page Size Extensions (4MB memory pages)") }, +    { "tsc",     NC_("x86-flag", /*/flag:tsc*/  "Time Stamp Counter (RDTSC)") }, +    { "msr",     NC_("x86-flag", /*/flag:msr*/  "Model-Specific Registers (RDMSR, WRMSR)") }, +    { "pae",     NC_("x86-flag", /*/flag:pae*/  "Physical Address Extensions (support for more than 4GB of RAM)") }, +    { "mce",     NC_("x86-flag", /*/flag:mce*/  "Machine Check Exception") }, +    { "cx8",     NC_("x86-flag", /*/flag:cx8*/  "CMPXCHG8 instruction (64-bit compare-and-swap)") }, +    { "apic",    NC_("x86-flag", /*/flag:apic*/  "Onboard APIC") }, +    { "sep",     NC_("x86-flag", /*/flag:sep*/  "SYSENTER/SYSEXIT") }, +    { "mtrr",    NC_("x86-flag", /*/flag:mtrr*/  "Memory Type Range Registers") }, +    { "pge",     NC_("x86-flag", /*/flag:pge*/  "Page Global Enable (global bit in PDEs and PTEs)") }, +    { "mca",     NC_("x86-flag", /*/flag:mca*/  "Machine Check Architecture") }, +    { "cmov",    NC_("x86-flag", /*/flag:cmov*/  "CMOV instructions (conditional move) (also FCMOV)") }, +    { "pat",     NC_("x86-flag", /*/flag:pat*/  "Page Attribute Table") }, +    { "pse36",   NC_("x86-flag", /*/flag:pse36*/  "36-bit PSEs (huge pages)") }, +    { "pn",      NC_("x86-flag", /*/flag:pn*/  "Processor serial number") }, +    { "clflush", NC_("x86-flag", /*/flag:clflush*/  "Cache Line Flush instruction") }, +    { "dts",     NC_("x86-flag", /*/flag:dts*/  "Debug Store (buffer for debugging and profiling instructions), or alternately: digital thermal sensor") }, +    { "acpi",    NC_("x86-flag", /*/flag:acpi*/  "ACPI via MSR (temperature monitoring and clock speed modulation)") }, +    { "mmx",     NC_("x86-flag", /*/flag:mmx*/  "Multimedia Extensions") }, +    { "fxsr",    NC_("x86-flag", /*/flag:fxsr*/  "FXSAVE/FXRSTOR, CR4.OSFXSR") }, +    { "sse",     NC_("x86-flag", /*/flag:sse*/  "Intel SSE vector instructions") }, +    { "sse2",    NC_("x86-flag", /*/flag:sse2*/  "SSE2") }, +    { "ss",      NC_("x86-flag", /*/flag:ss*/  "CPU self snoop") }, +    { "ht",      NC_("x86-flag", /*/flag:ht*/  "Hyper-Threading") }, +    { "tm",      NC_("x86-flag", /*/flag:tm*/  "Automatic clock control (Thermal Monitor)") }, +    { "ia64",    NC_("x86-flag", /*/flag:ia64*/  "Intel Itanium Architecture 64-bit (not to be confused with Intel's 64-bit x86 architecture with flag x86-64 or \"AMD64\" bit indicated by flag lm)") }, +    { "pbe",     NC_("x86-flag", /*/flag:pbe*/  "Pending Break Enable (PBE# pin) wakeup support") }, +/* AMD-defined CPU features, CPUID level 0x80000001 + * See also Wikipedia and table 2-23 in Intel Advanced Vector Extensions Programming Reference */ +    { "syscall",  NC_("x86-flag", /*/flag:syscall*/  "SYSCALL (Fast System Call) and SYSRET (Return From Fast System Call)") }, +    { "mp",       NC_("x86-flag", /*/flag:mp*/  "Multiprocessing Capable.") }, +    { "nx",       NC_("x86-flag", /*/flag:nx*/  "Execute Disable") }, +    { "mmxext",   NC_("x86-flag", /*/flag:mmxext*/  "AMD MMX extensions") }, +    { "fxsr_opt", NC_("x86-flag", /*/flag:fxsr_opt*/  "FXSAVE/FXRSTOR optimizations") }, +    { "pdpe1gb",  NC_("x86-flag", /*/flag:pdpe1gb*/  "One GB pages (allows hugepagesz=1G)") }, +    { "rdtscp",   NC_("x86-flag", /*/flag:rdtscp*/  "Read Time-Stamp Counter and Processor ID") }, +    { "lm",       NC_("x86-flag", /*/flag:lm*/  "Long Mode (x86-64: amd64, also known as Intel 64, i.e. 64-bit capable)") }, +    { "3dnow",    NC_("x86-flag", /*/flag:3dnow*/  "3DNow! (AMD vector instructions, competing with Intel's SSE1)") }, +    { "3dnowext", NC_("x86-flag", /*/flag:3dnowext*/  "AMD 3DNow! extensions") }, +/* Transmeta-defined CPU features, CPUID level 0x80860001 */ +    { "recovery", NC_("x86-flag", /*/flag:recovery*/  "CPU in recovery mode") }, +    { "longrun",  NC_("x86-flag", /*/flag:longrun*/  "Longrun power control") }, +    { "lrti",     NC_("x86-flag", /*/flag:lrti*/  "LongRun table interface") }, +/* Other features, Linux-defined mapping */ +    { "cxmmx",        NC_("x86-flag", /*/flag:cxmmx*/  "Cyrix MMX extensions") }, +    { "k6_mtrr",      NC_("x86-flag", /*/flag:k6_mtrr*/  "AMD K6 nonstandard MTRRs") }, +    { "cyrix_arr",    NC_("x86-flag", /*/flag:cyrix_arr*/  "Cyrix ARRs (= MTRRs)") }, +    { "centaur_mcr",  NC_("x86-flag", /*/flag:centaur_mcr*/  "Centaur MCRs (= MTRRs)") }, +    { "constant_tsc", NC_("x86-flag", /*/flag:constant_tsc*/  "TSC ticks at a constant rate") }, +    { "up",           NC_("x86-flag", /*/flag:up*/  "SMP kernel running on UP") }, +    { "art",          NC_("x86-flag", /*/flag:art*/  "Always-Running Timer") }, +    { "arch_perfmon", NC_("x86-flag", /*/flag:arch_perfmon*/  "Intel Architectural PerfMon") }, +    { "pebs",         NC_("x86-flag", /*/flag:pebs*/  "Precise-Event Based Sampling") }, +    { "bts",          NC_("x86-flag", /*/flag:bts*/  "Branch Trace Store") }, +    { "rep_good",     NC_("x86-flag", /*/flag:rep_good*/  "rep microcode works well") }, +    { "acc_power",    NC_("x86-flag", /*/flag:acc_power*/  "AMD accumulated power mechanism") }, +    { "nopl",         NC_("x86-flag", /*/flag:nopl*/  "The NOPL (0F 1F) instructions") }, +    { "xtopology",    NC_("x86-flag", /*/flag:xtopology*/  "cpu topology enum extensions") }, +    { "tsc_reliable", NC_("x86-flag", /*/flag:tsc_reliable*/  "TSC is known to be reliable") }, +    { "nonstop_tsc",  NC_("x86-flag", /*/flag:nonstop_tsc*/  "TSC does not stop in C states") }, +    { "extd_apicid",  NC_("x86-flag", /*/flag:extd_apicid*/  "has extended APICID (8 bits)") }, +    { "amd_dcm",      NC_("x86-flag", /*/flag:amd_dcm*/  "multi-node processor") }, +    { "aperfmperf",   NC_("x86-flag", /*/flag:aperfmperf*/  "APERFMPERF") }, +    { "eagerfpu",     NC_("x86-flag", /*/flag:eagerfpu*/  "Non lazy FPU restore") }, +    { "nonstop_tsc_s3", NC_("x86-flag", /*/flag:nonstop_tsc_s3*/  "TSC doesn't stop in S3 state") }, +    { "mce_recovery",   NC_("x86-flag", /*/flag:mce_recovery*/  "CPU has recoverable machine checks") }, +/* Intel-defined CPU features, CPUID level 0x00000001 (ecx) + * See also Wikipedia and table 2-26 in Intel Advanced Vector Extensions Programming Reference */ +    { "pni",       NC_("x86-flag", /*/flag:pni*/  "SSE-3 (\"Prescott New Instructions\")") }, +    { "pclmulqdq", NC_("x86-flag", /*/flag:pclmulqdq*/  "Perform a Carry-Less Multiplication of Quadword instruction - accelerator for GCM)") }, +    { "dtes64",    NC_("x86-flag", /*/flag:dtes64*/  "64-bit Debug Store") }, +    { "monitor",   NC_("x86-flag", /*/flag:monitor*/  "Monitor/Mwait support (Intel SSE3 supplements)") }, +    { "ds_cpl",    NC_("x86-flag", /*/flag:ds_cpl*/  "CPL Qual. Debug Store") }, +    { "vmx",       NC_("x86-flag", /*/flag:vmx*/  "Hardware virtualization, Intel VMX") }, +    { "smx",       NC_("x86-flag", /*/flag:smx*/  "Safer mode TXT (TPM support)") }, +    { "est",       NC_("x86-flag", /*/flag:est*/  "Enhanced SpeedStep") }, +    { "tm2",       NC_("x86-flag", /*/flag:tm2*/  "Thermal Monitor 2") }, +    { "ssse3",     NC_("x86-flag", /*/flag:ssse3*/  "Supplemental SSE-3") }, +    { "cid",       NC_("x86-flag", /*/flag:cid*/  "Context ID") }, +    { "sdbg",      NC_("x86-flag", /*/flag:sdbg*/  "silicon debug") }, +    { "fma",       NC_("x86-flag", /*/flag:fma*/  "Fused multiply-add") }, +    { "cx16",      NC_("x86-flag", /*/flag:cx16*/  "CMPXCHG16B") }, +    { "xtpr",      NC_("x86-flag", /*/flag:xtpr*/  "Send Task Priority Messages") }, +    { "pdcm",      NC_("x86-flag", /*/flag:pdcm*/  "Performance Capabilities") }, +    { "pcid",      NC_("x86-flag", /*/flag:pcid*/  "Process Context Identifiers") }, +    { "dca",       NC_("x86-flag", /*/flag:dca*/  "Direct Cache Access") }, +    { "sse4_1",    NC_("x86-flag", /*/flag:sse4_1*/  "SSE-4.1") }, +    { "sse4_2",    NC_("x86-flag", /*/flag:sse4_2*/  "SSE-4.2") }, +    { "x2apic",    NC_("x86-flag", /*/flag:x2apic*/  "x2APIC") }, +    { "movbe",     NC_("x86-flag", /*/flag:movbe*/  "Move Data After Swapping Bytes instruction") }, +    { "popcnt",    NC_("x86-flag", /*/flag:popcnt*/  "Return the Count of Number of Bits Set to 1 instruction (Hamming weight, i.e. bit count)") }, +    { "tsc_deadline_timer", NC_("x86-flag", /*/flag:tsc_deadline_timer*/  "Tsc deadline timer") }, +    { "aes/aes-ni",  NC_("x86-flag", /*/flag:aes/aes-ni*/  "Advanced Encryption Standard (New Instructions)") }, +    { "xsave",       NC_("x86-flag", /*/flag:xsave*/  "Save Processor Extended States: also provides XGETBY,XRSTOR,XSETBY") }, +    { "avx",         NC_("x86-flag", /*/flag:avx*/  "Advanced Vector Extensions") }, +    { "f16c",        NC_("x86-flag", /*/flag:f16c*/  "16-bit fp conversions (CVT16)") }, +    { "rdrand",      NC_("x86-flag", /*/flag:rdrand*/  "Read Random Number from hardware random number generator instruction") }, +    { "hypervisor",  NC_("x86-flag", /*/flag:hypervisor*/  "Running on a hypervisor") }, +/* VIA/Cyrix/Centaur-defined CPU features, CPUID level 0xC0000001 */ +    { "rng",     NC_("x86-flag", /*/flag:rng*/  "Random Number Generator present (xstore)") }, +    { "rng_en",  NC_("x86-flag", /*/flag:rng_en*/  "Random Number Generator enabled") }, +    { "ace",     NC_("x86-flag", /*/flag:ace*/  "on-CPU crypto (xcrypt)") }, +    { "ace_en",  NC_("x86-flag", /*/flag:ace_en*/  "on-CPU crypto enabled") }, +    { "ace2",    NC_("x86-flag", /*/flag:ace2*/  "Advanced Cryptography Engine v2") }, +    { "ace2_en", NC_("x86-flag", /*/flag:ace2_en*/  "ACE v2 enabled") }, +    { "phe",     NC_("x86-flag", /*/flag:phe*/  "PadLock Hash Engine") }, +    { "phe_en",  NC_("x86-flag", /*/flag:phe_en*/  "PHE enabled") }, +    { "pmm",     NC_("x86-flag", /*/flag:pmm*/  "PadLock Montgomery Multiplier") }, +    { "pmm_en",  NC_("x86-flag", /*/flag:pmm_en*/  "PMM enabled") }, +/* More extended AMD flags: CPUID level 0x80000001, ecx */ +    { "lahf_lm",       NC_("x86-flag", /*/flag:lahf_lm*/  "Load AH from Flags (LAHF) and Store AH into Flags (SAHF) in long mode") }, +    { "cmp_legacy",    NC_("x86-flag", /*/flag:cmp_legacy*/  "If yes HyperThreading not valid") }, +    { "svm",           NC_("x86-flag", /*/flag:svm*/  "\"Secure virtual machine\": AMD-V") }, +    { "extapic",       NC_("x86-flag", /*/flag:extapic*/  "Extended APIC space") }, +    { "cr8_legacy",    NC_("x86-flag", /*/flag:cr8_legacy*/  "CR8 in 32-bit mode") }, +    { "abm",           NC_("x86-flag", /*/flag:abm*/  "Advanced Bit Manipulation") }, +    { "sse4a",         NC_("x86-flag", /*/flag:sse4a*/  "SSE-4A") }, +    { "misalignsse",   NC_("x86-flag", /*/flag:misalignsse*/  "indicates if a general-protection exception (#GP) is generated when some legacy SSE instructions operate on unaligned data. Also depends on CR0 and Alignment Checking bit") }, +    { "3dnowprefetch", NC_("x86-flag", /*/flag:3dnowprefetch*/  "3DNow prefetch instructions") }, +    { "osvw",          NC_("x86-flag", /*/flag:osvw*/  "indicates OS Visible Workaround, which allows the OS to work around processor errata.") }, +    { "ibs",           NC_("x86-flag", /*/flag:ibs*/  "Instruction Based Sampling") }, +    { "xop",           NC_("x86-flag", /*/flag:xop*/  "extended AVX instructions") }, +    { "skinit",        NC_("x86-flag", /*/flag:skinit*/  "SKINIT/STGI instructions") }, +    { "wdt",           NC_("x86-flag", /*/flag:wdt*/  "Watchdog timer") }, +    { "lwp",           NC_("x86-flag", /*/flag:lwp*/  "Light Weight Profiling") }, +    { "fma4",          NC_("x86-flag", /*/flag:fma4*/  "4 operands MAC instructions") }, +    { "tce",           NC_("x86-flag", /*/flag:tce*/  "translation cache extension") }, +    { "nodeid_msr",    NC_("x86-flag", /*/flag:nodeid_msr*/  "NodeId MSR") }, +    { "tbm",           NC_("x86-flag", /*/flag:tbm*/  "Trailing Bit Manipulation") }, +    { "topoext",       NC_("x86-flag", /*/flag:topoext*/  "Topology Extensions CPUID leafs") }, +    { "perfctr_core",  NC_("x86-flag", /*/flag:perfctr_core*/  "Core Performance Counter Extensions") }, +    { "perfctr_nb",    NC_("x86-flag", /*/flag:perfctr_nb*/  "NB Performance Counter Extensions") }, +    { "bpext",         NC_("x86-flag", /*/flag:bpext*/  "data breakpoint extension") }, +    { "ptsc",          NC_("x86-flag", /*/flag:ptsc*/  "performance time-stamp counter") }, +    { "perfctr_l2",    NC_("x86-flag", /*/flag:perfctr_l2*/  "L2 Performance Counter Extensions") }, +    { "mwaitx",        NC_("x86-flag", /*/flag:mwaitx*/  "MWAIT extension (MONITORX/MWAITX)") }, +/* Auxiliary flags: Linux defined - For features scattered in various CPUID levels */ +    { "cpb",           NC_("x86-flag", /*/flag:cpb*/  "AMD Core Performance Boost") }, +    { "epb",           NC_("x86-flag", /*/flag:epb*/  "IA32_ENERGY_PERF_BIAS support") }, +    { "hw_pstate",     NC_("x86-flag", /*/flag:hw_pstate*/  "AMD HW-PState") }, +    { "proc_feedback", NC_("x86-flag", /*/flag:proc_feedback*/  "AMD ProcFeedbackInterface") }, +    { "intel_pt",      NC_("x86-flag", /*/flag:intel_pt*/  "Intel Processor Tracing") }, +/* Virtualization flags: Linux defined */ +    { "tpr_shadow",   NC_("x86-flag", /*/flag:tpr_shadow*/  "Intel TPR Shadow") }, +    { "vnmi",         NC_("x86-flag", /*/flag:vnmi*/  "Intel Virtual NMI") }, +    { "flexpriority", NC_("x86-flag", /*/flag:flexpriority*/  "Intel FlexPriority") }, +    { "ept",          NC_("x86-flag", /*/flag:ept*/  "Intel Extended Page Table") }, +    { "vpid",         NC_("x86-flag", /*/flag:vpid*/  "Intel Virtual Processor ID") }, +    { "vmmcall",      NC_("x86-flag", /*/flag:vmmcall*/  "prefer VMMCALL to VMCALL") }, +/* Intel-defined CPU features, CPUID level 0x00000007:0 (ebx) */ +    { "fsgsbase",   NC_("x86-flag", /*/flag:fsgsbase*/  "{RD/WR}{FS/GS}BASE instructions") }, +    { "tsc_adjust", NC_("x86-flag", /*/flag:tsc_adjust*/  "TSC adjustment MSR") }, +    { "bmi1",       NC_("x86-flag", /*/flag:bmi1*/  "1st group bit manipulation extensions") }, +    { "hle",        NC_("x86-flag", /*/flag:hle*/  "Hardware Lock Elision") }, +    { "avx2",       NC_("x86-flag", /*/flag:avx2*/  "AVX2 instructions") }, +    { "smep",       NC_("x86-flag", /*/flag:smep*/  "Supervisor Mode Execution Protection") }, +    { "bmi2",       NC_("x86-flag", /*/flag:bmi2*/  "2nd group bit manipulation extensions") }, +    { "erms",       NC_("x86-flag", /*/flag:erms*/  "Enhanced REP MOVSB/STOSB") }, +    { "invpcid",    NC_("x86-flag", /*/flag:invpcid*/  "Invalidate Processor Context ID") }, +    { "rtm",        NC_("x86-flag", /*/flag:rtm*/  "Restricted Transactional Memory") }, +    { "cqm",        NC_("x86-flag", /*/flag:cqm*/  "Cache QoS Monitoring") }, +    { "mpx",        NC_("x86-flag", /*/flag:mpx*/  "Memory Protection Extension") }, +    { "avx512f",    NC_("x86-flag", /*/flag:avx512f*/  "AVX-512 foundation") }, +    { "avx512dq",   NC_("x86-flag", /*/flag:avx512dq*/  "AVX-512 Double/Quad instructions") }, +    { "rdseed",     NC_("x86-flag", /*/flag:rdseed*/  "The RDSEED instruction") }, +    { "adx",        NC_("x86-flag", /*/flag:adx*/  "The ADCX and ADOX instructions") }, +    { "smap",       NC_("x86-flag", /*/flag:smap*/  "Supervisor Mode Access Prevention") }, +    { "clflushopt", NC_("x86-flag", /*/flag:clflushopt*/  "CLFLUSHOPT instruction") }, +    { "clwb",       NC_("x86-flag", /*/flag:clwb*/  "CLWB instruction") }, +    { "avx512pf",   NC_("x86-flag", /*/flag:avx512pf*/  "AVX-512 Prefetch") }, +    { "avx512er",   NC_("x86-flag", /*/flag:avx512er*/  "AVX-512 Exponential and Reciprocal") }, +    { "avx512cd",   NC_("x86-flag", /*/flag:avx512cd*/  "AVX-512 Conflict Detection") }, +    { "sha_ni",     NC_("x86-flag", /*/flag:sha_ni*/  "SHA1/SHA256 Instruction Extensions") }, +    { "avx512bw",   NC_("x86-flag", /*/flag:avx512bw*/  "AVX-512 Byte/Word instructions") }, +    { "avx512vl",   NC_("x86-flag", /*/flag:avx512vl*/  "AVX-512 128/256 Vector Length extensions") }, +/* Extended state features, CPUID level 0x0000000d:1 (eax) */ +    { "xsaveopt",   NC_("x86-flag", /*/flag:xsaveopt*/  "Optimized XSAVE") }, +    { "xsavec",     NC_("x86-flag", /*/flag:xsavec*/  "XSAVEC") }, +    { "xgetbv1",    NC_("x86-flag", /*/flag:xgetbv1*/  "XGETBV with ECX = 1") }, +    { "xsaves",     NC_("x86-flag", /*/flag:xsaves*/  "XSAVES/XRSTORS") }, +/* Intel-defined CPU QoS sub-leaf, CPUID level 0x0000000F:0 (edx) */ +    { "cqm_llc",    NC_("x86-flag", /*/flag:cqm_llc*/  "LLC QoS") }, +/* Intel-defined CPU QoS sub-leaf, CPUID level 0x0000000F:1 (edx) */ +    { "cqm_occup_llc",  NC_("x86-flag", /*/flag:cqm_occup_llc*/  "LLC occupancy monitoring") }, +    { "cqm_mbm_total",  NC_("x86-flag", /*/flag:cqm_mbm_total*/  "LLC total MBM monitoring") }, +    { "cqm_mbm_local",  NC_("x86-flag", /*/flag:cqm_mbm_local*/  "LLC local MBM monitoring") }, +/* AMD-defined CPU features, CPUID level 0x80000008 (ebx) */ +    { "clzero",         NC_("x86-flag", /*/flag:clzero*/  "CLZERO instruction") }, +    { "irperf",         NC_("x86-flag", /*/flag:irperf*/  "instructions retired performance counter") }, +/* Thermal and Power Management leaf, CPUID level 0x00000006 (eax) */ +    { "dtherm",         NC_("x86-flag", /*/flag:dtherm*/  "digital thermal sensor") }, /* formerly dts */ +    { "ida",            NC_("x86-flag", /*/flag:ida*/  "Intel Dynamic Acceleration") }, +    { "arat",           NC_("x86-flag", /*/flag:arat*/  "Always Running APIC Timer") }, +    { "pln",            NC_("x86-flag", /*/flag:pln*/  "Intel Power Limit Notification") }, +    { "pts",            NC_("x86-flag", /*/flag:pts*/  "Intel Package Thermal Status") }, +    { "hwp",            NC_("x86-flag", /*/flag:hwp*/  "Intel Hardware P-states") }, +    { "hwp_notify",     NC_("x86-flag", /*/flag:hwp_notify*/  "HWP notification") }, +    { "hwp_act_window", NC_("x86-flag", /*/flag:hwp_act_window*/  "HWP Activity Window") }, +    { "hwp_epp",        NC_("x86-flag", /*/flag:hwp_epp*/  "HWP Energy Performance Preference") }, +    { "hwp_pkg_req",    NC_("x86-flag", /*/flag:hwp_pkg_req*/  "HWP package-level request") }, +/* AMD SVM Feature Identification, CPUID level 0x8000000a (edx) */ +    { "npt",            NC_("x86-flag", /*/flag:npt*/  "AMD Nested Page Table support") }, +    { "lbrv",           NC_("x86-flag", /*/flag:lbrv*/  "AMD LBR Virtualization support") }, +    { "svm_lock",       NC_("x86-flag", /*/flag:svm_lock*/  "AMD SVM locking MSR") }, +    { "nrip_save",      NC_("x86-flag", /*/flag:nrip_save*/  "AMD SVM next_rip save") }, +    { "tsc_scale",      NC_("x86-flag", /*/flag:tsc_scale*/  "AMD TSC scaling support") }, +    { "vmcb_clean",     NC_("x86-flag", /*/flag:vmcb_clean*/  "AMD VMCB clean bits support") }, +    { "flushbyasid",    NC_("x86-flag", /*/flag:flushbyasid*/  "AMD flush-by-ASID support") }, +    { "decodeassists",  NC_("x86-flag", /*/flag:decodeassists*/  "AMD Decode Assists support") }, +    { "pausefilter",    NC_("x86-flag", /*/flag:pausefilter*/  "AMD filtered pause intercept") }, +    { "pfthreshold",    NC_("x86-flag", /*/flag:pfthreshold*/  "AMD pause filter threshold") }, +    { "avic",           NC_("x86-flag", /*/flag:avic*/  "Virtual Interrupt Controller") }, +/* Intel-defined CPU features, CPUID level 0x00000007:0 (ecx) */ +    { "pku",            NC_("x86-flag", /*/flag:pku*/  "Protection Keys for Userspace") }, +    { "ospke",          NC_("x86-flag", /*/flag:ospke*/  "OS Protection Keys Enable") }, +/* AMD-defined CPU features, CPUID level 0x80000007 (ebx) */ +    { "overflow_recov", NC_("x86-flag", /*/flag:overflow_recov*/  "MCA overflow recovery support") }, +    { "succor",         NC_("x86-flag", /*/flag:succor*/  "uncorrectable error containment and recovery") }, +    { "smca",           NC_("x86-flag", /*/flag:smca*/  "Scalable MCA") }, + +/* bug workarounds */ +    { "bug:f00f",       NC_("x86-flag", /*/bug:f00f*/  "Intel F00F bug")    }, +    { "bug:fdiv",       NC_("x86-flag", /*/bug:fdiv*/  "FPU FDIV")          }, +    { "bug:coma",       NC_("x86-flag", /*/bug:coma*/  "Cyrix 6x86 coma")   }, +    { "bug:tlb_mmatch", NC_("x86-flag", /*/bug:tlb_mmatch*/  "AMD Erratum 383")   }, +    { "bug:apic_c1e",   NC_("x86-flag", /*/bug:apic_c1e*/  "AMD Erratum 400")   }, +    { "bug:11ap",       NC_("x86-flag", /*/bug:11ap*/  "Bad local APIC aka 11AP")  }, +    { "bug:fxsave_leak",      NC_("x86-flag", /*/bug:fxsave_leak*/  "FXSAVE leaks FOP/FIP/FOP") }, +    { "bug:clflush_monitor",  NC_("x86-flag", /*/bug:clflush_monitor*/  "AAI65, CLFLUSH required before MONITOR") }, +    { "bug:sysret_ss_attrs",  NC_("x86-flag", /*/bug:sysret_ss_attrs*/  "SYSRET doesn't fix up SS attrs") }, +    { "bug:espfix",       NC_("x86-flag", /*/bug:espfix*/  "IRET to 16-bit SS corrupts ESP/RSP high bits") }, +    { "bug:null_seg",     NC_("x86-flag", /*/bug:null_seg*/  "Nulling a selector preserves the base") },         /* see: detect_null_seg_behavior() */ +    { "bug:swapgs_fence", NC_("x86-flag", /*/bug:swapgs_fence*/  "SWAPGS without input dep on GS") }, +    { "bug:monitor",      NC_("x86-flag", /*/bug:monitor*/  "IPI required to wake up remote CPU") }, +    { "bug:amd_e400",     NC_("x86-flag", /*/bug:amd_e400*/  "AMD Erratum 400") }, +/* power management + * ... from arch/x86/kernel/cpu/powerflags.h */ +    { "pm:ts",            NC_("x86-flag", /*/flag:pm:ts*/  "temperature sensor")     }, +    { "pm:fid",           NC_("x86-flag", /*/flag:pm:fid*/  "frequency id control")   }, +    { "pm:vid",           NC_("x86-flag", /*/flag:pm:vid*/  "voltage id control")     }, +    { "pm:ttp",           NC_("x86-flag", /*/flag:pm:ttp*/  "thermal trip")           }, +    { "pm:tm",            NC_("x86-flag", /*/flag:pm:tm*/  "hardware thermal control")   }, +    { "pm:stc",           NC_("x86-flag", /*/flag:pm:stc*/  "software thermal control")   }, +    { "pm:100mhzsteps",   NC_("x86-flag", /*/flag:pm:100mhzsteps*/  "100 MHz multiplier control") }, +    { "pm:hwpstate",      NC_("x86-flag", /*/flag:pm:hwpstate*/  "hardware P-state control")   }, +    { "pm:cpb",           NC_("x86-flag", /*/flag:pm:cpb*/  "core performance boost")     }, +    { "pm:eff_freq_ro",   NC_("x86-flag", /*/flag:pm:eff_freq_ro*/  "Readonly aperf/mperf")       }, +    { "pm:proc_feedback", NC_("x86-flag", /*/flag:pm:proc_feedback*/  "processor feedback interface") }, +    { "pm:acc_power",     NC_("x86-flag", /*/flag:pm:acc_power*/  "accumulated power mechanism")  }, +    { NULL, NULL}, +}; + +static char all_flags[4096] = ""; + +#define APPEND_FLAG(f) strcat(all_flags, f); strcat(all_flags, " "); +const char *x86_flag_list() { +    int i = 0, built = 0; +    built = strlen(all_flags); +    if (!built) { +        while(tab_flag_meaning[i].name != NULL) { +            APPEND_FLAG(tab_flag_meaning[i].name); +            i++; +        } +    } +    return all_flags; +} + +const char *x86_flag_meaning(const char *flag) { +    int i = 0; +    if (flag) +    while(tab_flag_meaning[i].name != NULL) { +        if (strcmp(tab_flag_meaning[i].name, flag) == 0) { +            if (tab_flag_meaning[i].meaning != NULL) +                return C_("x86-flag", tab_flag_meaning[i].meaning); +            else return NULL; +        } +        i++; +    } +    return NULL; +} + +static void x86_flag_find_dups(void) { +    int t, i; + +    t = 0; +    while(tab_flag_meaning[t].name != NULL) { +        i = t+1; +        while(tab_flag_meaning[i].name != NULL) { +            if (strcmp(tab_flag_meaning[t].name, tab_flag_meaning[i].name) == 0) { +                printf("x86-flag duplicate definition: %s\n ... %d: %s\n ... %d: %s\n", +                    tab_flag_meaning[i].name, +                    t, tab_flag_meaning[t].meaning, +                    i, tab_flag_meaning[i].meaning); +            } +            i++; +        } +        t++; +    } +} diff --git a/modules/devices/x86/x86_data.h b/modules/devices/x86/x86_data.h new file mode 100644 index 00000000..66a4c80f --- /dev/null +++ b/modules/devices/x86/x86_data.h @@ -0,0 +1,28 @@ +/* + * rpiz - https://github.com/bp0/rpiz + * Copyright (C) 2017  Burt P. <pburt0@gmail.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA. + * + */ + +#ifndef _X86DATA_H_ +#define _X86DATA_H_ + +/* cpu flags from /proc/cpuinfo */ +const char *x86_flag_list(void);                 /* list of all known flags */ +const char *x86_flag_meaning(const char *flag);  /* lookup flag meaning */ + +#endif diff --git a/modules/devices/x86_64 b/modules/devices/x86_64 deleted file mode 120000 index de1ff735..00000000 --- a/modules/devices/x86_64 +++ /dev/null @@ -1 +0,0 @@ -./x86
\ No newline at end of file | 
