aboutsummaryrefslogtreecommitdiff
path: root/modules/devices
diff options
context:
space:
mode:
authorLucas de Castro Borges <lucas@gnuabordo.com.br>2024-04-22 00:35:53 -0300
committerLucas de Castro Borges <lucas@gnuabordo.com.br>2024-04-22 00:35:53 -0300
commit5f01c706267c595de92406a32e7f31ef5056c2d0 (patch)
treed1e74ef54efc41ada622900fe3e2a50dee44a237 /modules/devices
parent09fcc751ef158898c315ebc9299a0fa3a722d914 (diff)
New upstream version 2.0.3preupstream/2.0.3pre
Diffstat (limited to 'modules/devices')
-rw-r--r--modules/devices/alpha/processor.c4
-rw-r--r--modules/devices/arm/arm_data.c112
-rw-r--r--modules/devices/arm/arm_data.h5
-rw-r--r--modules/devices/arm/processor.c52
-rw-r--r--modules/devices/battery.c23
-rw-r--r--modules/devices/devicetree.c43
-rw-r--r--modules/devices/devicetree/pmac_data.c4
-rw-r--r--modules/devices/devicetree/rpi_data.c89
-rw-r--r--modules/devices/devmemory.c120
-rw-r--r--modules/devices/dmi.c156
-rw-r--r--modules/devices/dmi_memory.c1050
-rw-r--r--modules/devices/e2k/processor.c420
-rw-r--r--modules/devices/firmware.c261
-rw-r--r--modules/devices/gpu.c291
-rw-r--r--modules/devices/ia64/processor.c4
-rw-r--r--modules/devices/inputdevices.c199
-rw-r--r--modules/devices/loongarch64/processor.c90
-rw-r--r--modules/devices/m68k/processor.c4
-rw-r--r--modules/devices/mips/processor.c4
-rw-r--r--modules/devices/monitors.c515
-rw-r--r--modules/devices/parisc/processor.c4
-rw-r--r--modules/devices/pci.c384
-rw-r--r--modules/devices/ppc/processor.c4
-rw-r--r--modules/devices/printers.c70
-rw-r--r--modules/devices/resources.c30
-rw-r--r--modules/devices/riscv/processor.c4
-rw-r--r--modules/devices/riscv/riscv_data.c2
-rw-r--r--modules/devices/s390/processor.c4
-rw-r--r--modules/devices/sensors.c503
-rw-r--r--modules/devices/sh/processor.c4
-rw-r--r--modules/devices/sparc/processor.c4
-rw-r--r--modules/devices/spd-decode.c2064
-rw-r--r--modules/devices/spd-vendors.c292
-rw-r--r--modules/devices/storage.c509
-rw-r--r--modules/devices/usb.c542
-rw-r--r--modules/devices/x86/processor.c108
-rw-r--r--modules/devices/x86/x86_data.c88
37 files changed, 5664 insertions, 2398 deletions
diff --git a/modules/devices/alpha/processor.c b/modules/devices/alpha/processor.c
index c7862232..0e625316 100644
--- a/modules/devices/alpha/processor.c
+++ b/modules/devices/alpha/processor.c
@@ -1,10 +1,10 @@
/*
* HardInfo - Displays System Information
- * Copyright (C) 2003-2006 Leandro A. F. Pereira <leandro@hardinfo.org>
+ * Copyright (C) 2003-2006 L. A. F. Pereira <l@tia.mat.br>
*
* 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.
+ * the Free Software Foundation, version 2 or later.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/modules/devices/arm/arm_data.c b/modules/devices/arm/arm_data.c
index 60e8ea34..aece272f 100644
--- a/modules/devices/arm/arm_data.c
+++ b/modules/devices/arm/arm_data.c
@@ -82,47 +82,6 @@ static struct {
};
static struct {
- int code; char *name;
-} tab_arm_implementer[] = {
- { 0x41, "ARM" },
- { 0x44, "Intel (formerly DEC) StrongARM" },
- { 0x4e, "nVidia" },
- { 0x54, "Texas Instruments" },
- { 0x56, "Marvell" },
- { 0x69, "Intel XScale" },
- { 0, NULL},
-};
-
-static struct {
- /* source: t = tested, d = official docs, f = web */
- int code; char *part_desc;
-} tab_arm_arm_part[] = { /* only valid for implementer 0x41 ARM */
- /*d */ { 0x920, "ARM920" },
- /*d */ { 0x926, "ARM926" },
- /*d */ { 0x946, "ARM946" },
- /*d */ { 0x966, "ARM966" },
- /*d */ { 0xb02, "ARM11 MPCore" },
- /*d */ { 0xb36, "ARM1136" },
- /*d */ { 0xb56, "ARM1156" },
- /*dt*/ { 0xb76, "ARM1176" },
- /*dt*/ { 0xc05, "Cortex-A5" },
- /*d */ { 0xc07, "Cortex-A7 MPCore" },
- /*dt*/ { 0xc08, "Cortex-A8" },
- /*dt*/ { 0xc09, "Cortex-A9" },
- /*d */ { 0xc0e, "Cortex-A17 MPCore" },
- /*d */ { 0xc0f, "Cortex-A15" },
- /*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},
-};
-
-static struct {
char *code; char *name; char *more;
} tab_arm_arch[] = {
{ "7", "AArch32", "AArch32 (ARMv7)" },
@@ -161,37 +120,47 @@ const char *arm_flag_meaning(const char *flag) {
return NULL;
}
-static int code_match(int c0, const char* code1) {
- int c1;
- if (code1 == NULL) return 0;
- c1 = strtol(code1, NULL, 0);
- return (c0 == c1) ? 1 : 0;
-}
-
-const char *arm_implementer(const char *code) {
- int i = 0;
- if (code)
- while(tab_arm_implementer[i].code) {
- if (code_match(tab_arm_implementer[i].code, code))
- return tab_arm_implementer[i].name;
- i++;
+#include "util_ids.h"
+
+gchar *arm_ids_file = NULL;
+
+void find_arm_ids_file() {
+ if (arm_ids_file) return;
+ char *file_search_order[] = {
+ g_build_filename(g_get_user_config_dir(), "hardinfo2", "arm.ids", NULL),
+ g_build_filename(params.path_data, "arm.ids", NULL),
+ NULL
+ };
+ int n;
+ for(n = 0; file_search_order[n]; n++) {
+ if (!arm_ids_file && !access(file_search_order[n], R_OK))
+ arm_ids_file = (gchar*) auto_free_on_exit( file_search_order[n] );
+ else
+ g_free(file_search_order[n]);
}
- return NULL;
}
-const char *arm_part(const char *imp_code, const char *part_code) {
- int i = 0;
- if (imp_code && part_code) {
- if (code_match(0x41, imp_code)) {
- /* 0x41=ARM parts */
- while(tab_arm_arm_part[i].code) {
- if (code_match(tab_arm_arm_part[i].code, part_code))
- return tab_arm_arm_part[i].part_desc;
- i++;
- }
- }
- }
- return NULL;
+void arm_part(const char *imp_code, const char *part_code, char **imp, char **part) {
+ gchar *qpath = NULL;
+ ids_query_result result = {};
+ unsigned int i,p;
+
+ if (!arm_ids_file)
+ find_arm_ids_file();
+
+ i = strtol(imp_code, NULL, 0);
+ p = strtol(part_code, NULL, 0);
+ qpath = g_strdup_printf("%02x/%03x", i, p);
+ scan_ids_file(arm_ids_file, qpath, &result, -1);
+ g_free(qpath);
+ if (imp)
+ *imp = result.results[0]
+ ? g_strdup(result.results[0])
+ : NULL;
+ if (part)
+ *part = result.results[1]
+ ? g_strdup(result.results[1])
+ : NULL;
}
const char *arm_arch(const char *cpuinfo_arch_str) {
@@ -229,8 +198,7 @@ char *arm_decoded_name(const char *imp, const char *part, const char *var, const
* variant and revision can be rendered r{variant}p{revision} */
r = strtol(var, NULL, 0);
p = strtol(rev, NULL, 0);
- imp_name = (char*) arm_implementer(imp);
- part_desc = (char*) arm_part(imp, part);
+ arm_part(imp, part, &imp_name, &part_desc);
arch_name = (char*) arm_arch(arch);
if (imp_name || part_desc) {
if (arch_name != arch)
@@ -251,6 +219,8 @@ char *arm_decoded_name(const char *imp, const char *part, const char *var, const
(part_desc) ? part_desc : part,
r, p, arch);
}
+ g_free(imp_name);
+ g_free(part_desc);
} else {
/* prolly not ARM arch at all */
if (model_name)
diff --git a/modules/devices/arm/arm_data.h b/modules/devices/arm/arm_data.h
index 63b3c906..0e93d323 100644
--- a/modules/devices/arm/arm_data.h
+++ b/modules/devices/arm/arm_data.h
@@ -22,13 +22,12 @@
#define _ARMDATA_H_
/* table lookups */
-const char *arm_implementer(const char *code);
-const char *arm_part(const char *imp_code, const char *part_code);
+void arm_part(const char *imp_code, const char *part_code, char **imp, char **part);
const char *arm_arch(const char *cpuinfo_arch_str);
const char *arm_arch_more(const char *cpuinfo_arch_str);
/* cpu_implementer, cpu_part, cpu_variant, cpu_revision, cpu_architecture from /proc/cpuinfo
- * model_name is returned as a fallback if not enough data is known */
+ * strdup(model_name) is returned as a fallback if not enough data is known */
char *arm_decoded_name(
const char *imp, const char *part, const char *var, const char *rev,
const char *arch, const char *model_name);
diff --git a/modules/devices/arm/processor.c b/modules/devices/arm/processor.c
index 3bee39f8..9446108d 100644
--- a/modules/devices/arm/processor.c
+++ b/modules/devices/arm/processor.c
@@ -1,10 +1,10 @@
/*
* HardInfo - Displays System Information
- * Copyright (C) 2003-2006 Leandro A. F. Pereira <leandro@hardinfo.org>
+ * Copyright (C) 2003-2006 L. A. F. Pereira <l@tia.mat.br>
*
* 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.
+ * the Free Software Foundation, version 2 or later.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -45,6 +45,7 @@ processor_scan(void)
gchar buffer[128];
gchar *rep_pname = NULL;
GSList *pi = NULL;
+ dtr *dt = dtr_new(NULL);
cpuinfo = fopen(PROC_CPUINFO, "r");
if (!cpuinfo)
@@ -162,6 +163,18 @@ processor_scan(void)
else
processor->cpu_mhz = 0.0f;
+ /* Try OPP, although if it exists, it should have been available
+ * via cpufreq. */
+ if (dt && processor->cpu_mhz == 0.0f) {
+ gchar *dt_cpu_path = g_strdup_printf("/cpus/cpu@%d", processor->id);
+ dt_opp_range *opp = dtr_get_opp_range(dt, dt_cpu_path);
+ if (opp) {
+ processor->cpu_mhz = (double)opp->khz_max / 1000;
+ g_free(opp);
+ }
+ g_free(dt_cpu_path);
+ }
+
/* mode */
processor->mode = ARM_A32;
if ( processor_has_flag(processor->flags, "pmull")
@@ -173,6 +186,7 @@ processor_scan(void)
#endif
}
}
+ dtr_free(dt);
return procs;
}
@@ -233,7 +247,7 @@ gchar *clocks_summary(GSList * processors)
/* create list of all clock references */
for (l = processors; l; l = l->next) {
p = (Processor*)l->data;
- if (p->cpufreq) {
+ if (p->cpufreq && p->cpufreq->cpukhz_max > 0) {
all_clocks = g_slist_prepend(all_clocks, p->cpufreq);
}
}
@@ -297,10 +311,10 @@ gchar *clocks_summary(GSList * processors)
gchar *
processor_get_detailed_info(Processor *processor)
{
- gchar *tmp_flags, *tmp_imp, *tmp_part, *tmp_arch, *tmp_cpufreq, *tmp_topology, *ret;
+ gchar *tmp_flags, *tmp_imp = NULL, *tmp_part = NULL,
+ *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);
+ arm_part(processor->cpu_implementer, processor->cpu_part, &tmp_imp, &tmp_part);
tmp_arch = (char*)arm_arch_more(processor->cpu_architecture);
tmp_topology = cputopo_section_str(processor->cputopo);
@@ -361,9 +375,15 @@ gchar *processor_name(GSList *processors) {
char *vendor;
char *soc;
} dt_compat_searches[] = {
- { "brcm,bcm2837", "Broadcom", "BCM2837" },
- { "brcm,bcm2836", "Broadcom", "BCM2836" },
- { "brcm,bcm2835", "Broadcom", "BCM2835" },
+ { "brcm,bcm2838", "Broadcom", "BCM2838" }, // RPi 4
+ { "brcm,bcm2837", "Broadcom", "BCM2837" }, // RPi 3
+ { "brcm,bcm2836", "Broadcom", "BCM2836" }, // RPi 2
+ { "brcm,bcm2835", "Broadcom", "BCM2835" }, // RPi 1
+ { "rockchip,rk3288", "Rockchip", "RK3288" }, // Asus Tinkerboard
+ { "rockchip,rk3328", "Rockchip", "RK3328" }, // Firefly Renegade
+ { "rockchip,rk3399", "Rockchip", "RK3399" }, // Firefly Renegade Elite
+ { "rockchip,rk32", "Rockchip", "RK32xx-family" },
+ { "rockchip,rk33", "Rockchip", "RK33xx-family" },
{ "ti,omap5432", "Texas Instruments", "OMAP5432" },
{ "ti,omap5430", "Texas Instruments", "OMAP5430" },
{ "ti,omap4470", "Texas Instruments", "OMAP4470" },
@@ -395,13 +415,15 @@ gchar *processor_name(GSList *processors) {
{ "mediatek,mt6732", "MediaTek", "MT6732" },
{ "qcom,msm8939", "Qualcomm", "Snapdragon 615"},
{ "qcom,msm", "Qualcomm", "Snapdragon-family"},
- { "nvidia,tegra" "nVidia", "Tegra-family" },
- { "bcm,", "Broadcom", UNKSOC },
- { "nvidia," "nVidia", UNKSOC },
- { "rockchip," "Rockchip", UNKSOC },
+ { "nvidia,tegra", "nVidia", "Tegra-family" },
+ { "brcm,", "Broadcom", UNKSOC },
+ { "nvidia,", "nVidia", UNKSOC },
+ { "rockchip,", "Rockchip", UNKSOC },
{ "ti,", "Texas Instruments", UNKSOC },
{ "qcom,", "Qualcom", UNKSOC },
- { "mediatek," "MediaTek", UNKSOC },
+ { "mediatek,", "MediaTek", UNKSOC },
+ { "amlogic,", "Amlogic", UNKSOC },
+ { "allwinner,", "Allwinner", UNKSOC },
{ NULL, NULL }
};
gchar *ret = NULL;
@@ -464,7 +486,7 @@ gchar *processor_get_info(GSList * processors)
gchar *meta; /* becomes owned by more_info? no need to free? */
GSList *l;
- tmp = g_strdup_printf("$CPU_META$%s=\n", _("SOC/Package Information") );
+ tmp = g_strdup_printf("$!CPU_META$%s=\n", _("SOC/Package Information") );
meta = processor_meta(processors);
moreinfo_add_with_prefix("DEV", "CPU_META", meta);
diff --git a/modules/devices/battery.c b/modules/devices/battery.c
index cbcebb12..e356c14a 100644
--- a/modules/devices/battery.c
+++ b/modules/devices/battery.c
@@ -1,10 +1,10 @@
/*
* HardInfo - Displays System Information
- * Copyright (C) 2003-2006 Leandro A. F. Pereira <leandro@hardinfo.org>
+ * Copyright (C) 2003-2006 L. A. F. Pereira <l@tia.mat.br>
*
* 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.
+ * the Free Software Foundation, version 2 or later.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -57,7 +57,7 @@ __scan_battery_apcupsd(void)
GHashTable *ups_data;
FILE *apcaccess;
char buffer[512], *apcaccess_path;
- int i;
+ guint i;
apcaccess_path = find_program("apcaccess");
if (apcaccess_path && (apcaccess = popen(apcaccess_path, "r"))) {
@@ -82,9 +82,9 @@ __scan_battery_apcupsd(void)
battery_list = h_strdup_cprintf("[%s]\n", battery_list, ups_fields[i].key);
} else {
/* there's a name: adds a line */
+ const gchar *name = g_hash_table_lookup(ups_data, ups_fields[i].key);
battery_list = h_strdup_cprintf("%s=%s\n", battery_list,
- ups_fields[i].name,
- g_hash_table_lookup(ups_data, ups_fields[i].key));
+ ups_fields[i].name, name);
}
}
@@ -165,12 +165,9 @@ __scan_battery_acpi(void)
fclose(f);
- const gchar *url = vendor_get_url(manufacturer);
- if (url) {
- char *tmp = g_strdup_printf("%s (%s)", vendor_get_name(manufacturer), url);
- g_free(manufacturer);
- manufacturer = tmp;
- }
+ gchar *tmp = vendor_get_link(manufacturer);
+ g_free(manufacturer);
+ manufacturer = tmp;
if (g_str_equal(present, "yes")) {
if (remaining && capacity)
@@ -229,11 +226,11 @@ read_contents(const gchar *base, const gchar *key)
return NULL;
if (!g_file_get_contents(path, &value, NULL, NULL)) {
- free(path);
+ g_free(path);
return NULL;
}
- free(path);
+ g_free(path);
return g_strchomp(value);
}
diff --git a/modules/devices/devicetree.c b/modules/devices/devicetree.c
index 4f3c85a2..7c798670 100644
--- a/modules/devices/devicetree.c
+++ b/modules/devices/devicetree.c
@@ -1,10 +1,10 @@
/*
* HardInfo - Displays System Information
- * Copyright (C) 2003-2007 Leandro A. F. Pereira <leandro@hardinfo.org>
+ * Copyright (C) 2003-2007 L. A. F. Pereira <l@tia.mat.br>
*
* 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.
+ * the Free Software Foundation, version 2 or later.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -28,6 +28,10 @@
#include "devices.h"
#include "cpu_util.h"
#include "dt_util.h"
+#include "appf.h"
+
+gchar *dtree_info = NULL;
+const char *dtree_mem_str = NULL; /* used by memory devices when nothing else is available */
/* These should really go into CMakeLists.txt */
#if defined(__arm__)
@@ -36,8 +40,6 @@
#include "devicetree/pmac_data.c"
#endif
-gchar *dtree_info = NULL;
-
static gchar *get_node(dtr *dt, char *np) {
gchar *nodes = NULL, *props = NULL, *ret = NULL;
gchar *tmp = NULL, *pstr = NULL, *lstr = NULL;
@@ -216,13 +218,14 @@ static gchar *get_summary(dtr *dt) {
return ret;
}
-static void mi_add(const char *key, const char *value) {
+static void mi_add(const char *key, const char *value, int report_details) {
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);
+ dtree_info = h_strdup_cprintf("$%s%s$%s=\n", dtree_info,
+ (report_details) ? "!" : "", rkey, ckey);
moreinfo_add_with_prefix("DEV", rkey, g_strdup(value));
g_free(ckey);
@@ -237,15 +240,14 @@ static void add_keys(dtr *dt, char *np) {
GDir *dir;
dtr_obj *obj;
- /* add self */
- obj = dtr_obj_read(dt, np);
- dt_path = dtr_obj_path(obj);
- n_info = get_node(dt, 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) {
+ if(!dir){ /* add self */
+ obj = dtr_obj_read(dt, np);
+ dt_path = dtr_obj_path(obj);
+ n_info = get_node(dt, dt_path);
+ mi_add(dt_path, n_info, 0);
+ }else { //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) ) {
@@ -253,24 +255,25 @@ static void add_keys(dtr *dt, char *np) {
ntmp = g_strdup_printf("/%s", fn);
else
ntmp = g_strdup_printf("%s/%s", np, fn);
- add_keys(dt, ntmp);
+ if(strlen(ntmp)>0) add_keys(dt, ntmp);
g_free(ntmp);
}
g_free(ftmp);
}
+ g_dir_close(dir);
}
- g_dir_close(dir);
+ g_free(dir_path);
}
static char *msg_section(dtr *dt, int dump) {
gchar *aslbl = NULL;
gchar *messages = dtr_messages(dt);
- gchar *ret = g_strdup_printf("[%s]\n", _("Messages"));
+ gchar *ret = g_strdup_printf("[%s]", _("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);
+ ret = appfnl(ret, "%s=", aslbl);
g_free(aslbl);
i++;
}
@@ -289,13 +292,13 @@ void __scan_dtree()
gchar *messages = NULL;
dtree_info = g_strdup("[Device Tree]\n");
- mi_add("Summary", summary);
- mi_add("Maps", maps);
+ mi_add("Summary", summary, 1);
+ mi_add("Maps", maps, 0);
if(dtr_was_found(dt))
add_keys(dt, "/");
messages = msg_section(dt, 0);
- mi_add("Messages", messages);
+ mi_add("Messages", messages, 0);
g_free(summary);
g_free(maps);
diff --git a/modules/devices/devicetree/pmac_data.c b/modules/devices/devicetree/pmac_data.c
index b236aef1..8c5471f0 100644
--- a/modules/devices/devicetree/pmac_data.c
+++ b/modules/devices/devicetree/pmac_data.c
@@ -1,10 +1,10 @@
/*
* HardInfo - Displays System Information
- * Copyright (C) 2003-2007 Leandro A. F. Pereira <leandro@hardinfo.org>
+ * Copyright (C) 2003-2007 L. A. F. Pereira <l@tia.mat.br>
*
* 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.
+ * the Free Software Foundation, version 2 or later.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/modules/devices/devicetree/rpi_data.c b/modules/devices/devicetree/rpi_data.c
index d0132e3a..63daa7f3 100644
--- a/modules/devices/devicetree/rpi_data.c
+++ b/modules/devices/devicetree/rpi_data.c
@@ -1,12 +1,12 @@
/*
* HardInfo - Displays System Information
- * Copyright (C) 2003-2007 Leandro A. F. Pereira <leandro@hardinfo.org>
+ * Copyright (C) 2003-2007 L. A. F. Pereira <l@tia.mat.br>
* 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.
+ * the Free Software Foundation, version 2 or later.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -21,48 +21,57 @@
static char unk[] = "(Unknown)";
/* information table from: http://elinux.org/RPi_HardwareHistory */
-static struct {
+typedef struct {
char *value, *intro, *model, *pcb, *mem, *mfg, *soc;
-} rpi_boardinfo[] = {
+} RaspberryPiBoard;
+
+static const RaspberryPiBoard 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 },
+ { "Beta", "Q1 2012", "B (Beta)", unk, "256 MB", "(Beta board)", NULL },
+ { "0002", "Q1 2012", "B", "1.0", "256 MB", unk, "BCM2835" },
+ { "0003", "Q3 2012", "B (ECN0001)", "1.0", "256 MB", "(Fuses mod and D14 removed)", NULL },
+ { "0004", "Q3 2012", "B", "2.0", "256 MB", "Sony", NULL },
+ { "0005", "Q4 2012", "B", "2.0", "256 MB", "Qisda", NULL },
+ { "0006", "Q4 2012", "B", "2.0", "256 MB", "Egoman", NULL },
+ { "0007", "Q1 2013", "A", "2.0", "256 MB", "Egoman", NULL },
+ { "0008", "Q1 2013", "A", "2.0", "256 MB", "Sony", NULL },
+ { "0009", "Q1 2013", "A", "2.0", "256 MB", "Qisda", NULL },
+ { "000d", "Q4 2012", "B", "2.0", "512 MB", "Egoman", NULL },
+ { "000e", "Q4 2012", "B", "2.0", "512 MB", "Sony", NULL },
+ { "000f", "Q4 2012", "B", "2.0", "512 MB", "Qisda", NULL },
+ { "0010", "Q3 2014", "B+", "1.0", "512 MB", "Sony", NULL },
+ { "0011", "Q2 2014", "Compute Module 1", "1.0", "512 MB", "Sony", NULL },
+ { "0012", "Q4 2014", "A+", "1.1", "256 MB", "Sony", NULL },
+ { "0013", "Q1 2015", "B+", "1.2", "512 MB", unk, NULL },
+ { "0014", "Q2 2014", "Compute Module 1", "1.0", "512 MB", "Embest", NULL },
+ { "0015", unk, "A+", "1.1", "256 MB/512 MB", "Embest", NULL },
+ { "a01040", unk, "2 Model B", "1.0", "1024 MB DDR2", "Sony", "BCM2836" },
+ { "a01041", "Q1 2015", "2 Model B", "1.1", "1024 MB DDR2", "Sony", "BCM2836" },
+ { "a21041", "Q1 2015", "2 Model B", "1.1", "1024 MB DDR2", "Embest", "BCM2836" },
+ { "a22042", "Q3 2016", "2 Model B", "1.2", "1024 MB DDR2", "Embest", "BCM2837" }, /* (with BCM2837) */
+ { "900021", "Q3 2016", "A+", "1.1", "512 MB", "Sony", NULL },
+ { "900032", "Q2 2016?", "B+", "1.2", "512 MB", "Sony", NULL },
+ { "900092", "Q4 2015", "Zero", "1.2", "512 MB", "Sony", NULL },
+ { "900093", "Q2 2016", "Zero", "1.3", "512 MB", "Sony", NULL },
+ { "920093", "Q4 2016?", "Zero", "1.3", "512 MB", "Embest", NULL },
+ { "9000c1", "Q1 2017", "Zero W", "1.1", "512 MB", "Sony", NULL },
+ { "a02082", "Q1 2016", "3 Model B", "1.2", "1024 MB DDR2", "Sony", "BCM2837" },
+ { "a020a0", "Q1 2017", "Compute Module 3 or CM3 Lite", "1.0", "1024 MB DDR2", "Sony", NULL },
+ { "a22082", "Q1 2016", "3 Model B", "1.2", "1024 MB DDR2", "Embest", "BCM2837" },
+ { "a32082", "Q4 2016", "3 Model B", "1.2", "1024 MB DDR2", "Sony Japan", NULL },
+ { "a020d3", "Q1 2018", "3 Model B+", "1.3", "1024 MB DDR2", "Sony", "BCM2837" },
+ { "9020e0", "Q4 2018", "3 Model A+", "1.0", "512 MB DDR2", "Sony", "BCM2837" },
+
+ { "a03111", "Q2 2019", "4 Model B", "1.0", "1024 MB DDR4", "Sony", "BCM2838" },
+ { "b03111", "Q2 2019", "4 Model B", "1.0", "2048 MB DDR4", "Sony", "BCM2838" },
+ { "c03111", "Q2 2019", "4 Model B", "1.1", "4096 MB DDR4", "Sony", "BCM2838" },
+ { "c03114", "Q2 2020", "4 Model B", "1.4", "8192 MB DDR4", "Sony", "BCM2838" },
+
{ 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... */
@@ -154,7 +163,7 @@ static gchar *rpi_board_details(void) {
_("PCB Revision"), rpi_boardinfo[i].pcb,
_("Introduction"), rpi_boardinfo[i].intro,
_("Manufacturer"), rpi_boardinfo[i].mfg,
- _("RCode"), rpi_boardinfo[i].value,
+ _("RCode"), (rpi_boardinfo[i].value != unk) ? rpi_boardinfo[i].value : revision,
_("SOC (spec)"), rpi_boardinfo[i].soc,
_("Memory (spec)"), rpi_boardinfo[i].mem,
_("Serial Number"), serial,
@@ -162,5 +171,9 @@ static gchar *rpi_board_details(void) {
g_free(soc);
g_free(revision);
+
+ if (rpi_boardinfo[i].mem)
+ dtree_mem_str = rpi_boardinfo[i].mem;
+
return ret;
}
diff --git a/modules/devices/devmemory.c b/modules/devices/devmemory.c
deleted file mode 100644
index 29094dd8..00000000
--- a/modules/devices/devmemory.c
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * 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 <string.h>
-#include "devices.h"
-
-GHashTable *memlabels = NULL;
-
-void scan_memory_do(void)
-{
- gchar **keys, *tmp, *tmp_label, *trans_val;
- 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 */
- gchar *os_kernel = module_call_method("computer::getOSKernel");
- if (os_kernel) {
- offset = strstr(os_kernel, "Linux 2.4") ? 3 : 0;
- g_free(os_kernel);
- } else {
- 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]);
-
- /* 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... */
-
- if (strstr(newkeys[1], "kB")) {
- trans_val = g_strdup_printf("%d %s", atoi(newkeys[1]), _("KiB") );
- } else {
- trans_val = strdup(newkeys[1]);
- }
-
- moreinfo_add_with_prefix("DEV", newkeys[0], g_strdup(trans_val));
-
- tmp = g_strconcat(meminfo, newkeys[0], "=", trans_val, "|", tmp_label, "\n", NULL);
- g_free(meminfo);
- meminfo = tmp;
-
- g_free(trans_val);
-
- tmp = g_strconcat(lginterval,
- "UpdateInterval$", newkeys[0], "=1000\n", NULL);
- g_free(lginterval);
- lginterval = tmp;
-
- g_strfreev(newkeys);
- }
- g_strfreev(keys);
-}
-
-void init_memory_labels(void)
-{
- static const struct {
- 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") },
- { 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 b25cfe21..34374fbe 100644
--- a/modules/devices/dmi.c
+++ b/modules/devices/dmi.c
@@ -1,10 +1,10 @@
/*
* HardInfo - Displays System Information
- * Copyright (C) 2003-2007 Leandro A. F. Pereira <leandro@hardinfo.org>
+ * Copyright (C) 2003-2007 L. A. F. Pereira <l@tia.mat.br>
*
* 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.
+ * the Free Software Foundation, version 2 or later.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -30,26 +30,29 @@ struct _DMIInfo {
const gchar *name;
const gchar *id_str;
int group;
+ gboolean maybe_vendor;
};
DMIInfo dmi_info_table[] = {
{ N_("Product"), NULL, 1 },
{ N_("Name"), "system-product-name", 0 },
{ N_("Family"), "system-product-family", 0 },
- { N_("Vendor"), "system-manufacturer", 0 },
+ { N_("Vendor"), "system-manufacturer", 0, TRUE },
{ N_("Version"), "system-version", 0 },
+ { N_("Serial Number"), "system-serial-number", 0 },
+ { N_("SKU"), "system-sku", 0 },
{ N_("BIOS"), NULL, 1 },
{ N_("Date"), "bios-release-date", 0 },
- { N_("Vendor"), "bios-vendor", 0 },
+ { N_("Vendor"), "bios-vendor", 0, TRUE },
{ N_("Version"), "bios-version", 0 },
{ N_("Board"), NULL, 1 },
{ N_("Name"), "baseboard-product-name", 0 },
- { N_("Vendor"), "baseboard-manufacturer", 0 },
+ { N_("Vendor"), "baseboard-manufacturer", 0, TRUE },
{ N_("Version"), "baseboard-version", 0 },
{ N_("Serial Number"), "baseboard-serial-number", 0 },
{ N_("Asset Tag"), "baseboard-asset-tag", 0 },
{ N_("Chassis"), NULL, 1 },
- { N_("Vendor"), "chassis-manufacturer", 0 },
+ { N_("Vendor"), "chassis-manufacturer", 0, TRUE },
{ N_("Type"), "chassis-type", 0 },
{ N_("Version"), "chassis-version", 0 },
{ N_("Serial Number"), "chassis-serial-number", 0 },
@@ -64,77 +67,102 @@ static void add_to_moreinfo(const char *group, const char *key, char *value)
moreinfo_add_with_prefix("DEV", new_key, g_strdup(g_strstrip(value)));
}
-gboolean dmi_get_info()
+gboolean dmi_get_info(void)
{
- const gchar *group = NULL;
- DMIInfo *info;
- gboolean dmi_succeeded = FALSE;
- gint i;
- gchar *value;
-
- if (dmi_info) {
- g_free(dmi_info);
- dmi_info = NULL;
- }
+ const gchar *group = NULL;
+ DMIInfo *info;
+ gboolean dmi_succeeded = FALSE;
+ guint i;
+ gchar *value;
+ const gchar *vendor;
+
+ 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->group) {
- group = info->name;
- dmi_info = h_strdup_cprintf("[%s]\n", dmi_info, _(info->name) );
- } else if (group && info->id_str) {
- if (strcmp(info->id_str, "chassis-type") == 0)
- value = dmi_chassis_type_str(-1, 1);
- else
- value = dmi_get_str(info->id_str);
-
- if (value != NULL) {
- add_to_moreinfo(group, info->name, value);
-
- const gchar *url = vendor_get_url(value);
- if (url) {
- const gchar *vendor = vendor_get_name(value);
- dmi_info = h_strdup_cprintf("%s=%s (%s, %s)\n",
- dmi_info,
- _(info->name),
- value,
- vendor, url);
- } else {
- dmi_info = h_strdup_cprintf("%s=%s\n",
- dmi_info,
- _(info->name),
- value);
+ for (i = 0; i < G_N_ELEMENTS(dmi_info_table); i++) {
+ info = &dmi_info_table[i];
+
+ if (info->group) {
+ group = info->name;
+ dmi_info = h_strdup_cprintf("[%s]\n", dmi_info, _(info->name));
+ } else if (group && info->id_str) {
+ int state = 3;
+
+ if (strcmp(info->id_str, "chassis-type") == 0) {
+ value = dmi_chassis_type_str(-1, 1);
+ if (value == NULL)
+ state = (getuid() == 0) ? 0 : 1;
+ }
+ else {
+ switch (dmi_str_status(info->id_str)) {
+ case 0:
+ value = NULL;
+ state = (getuid() == 0) ? 0 : 1;
+ break;
+ case -1:
+ state = 2;
+ value = dmi_get_str_abs(info->id_str);
+ break;
+ case 1:
+ value = dmi_get_str_abs(info->id_str);
+ break;
+ }
+ }
+
+ switch (state) {
+ case 0: /* no value, root */
+ dmi_info = h_strdup_cprintf("%s=%s\n", dmi_info, _(info->name),
+ _("(Not available)"));
+ break;
+ case 1: /* no value, no root */
+ dmi_info = h_strdup_cprintf("%s=%s\n", dmi_info, _(info->name),
+ _("(Not available; Perhaps try "
+ "running HardInfo as root.)"));
+ break;
+ case 2: /* ignored value */
+ if (params.markup_ok)
+ dmi_info = h_strdup_cprintf("%s=<s>%s</s>\n", dmi_info,
+ _(info->name), value);
+ else
+ dmi_info = h_strdup_cprintf("%s=[X]\"%s\"\n", dmi_info,
+ _(info->name), value);
+ break;
+ case 3: /* good value */
+ {
+ dmi_info =
+ h_strdup_cprintf("%s%s=%s\n", dmi_info,
+ info->maybe_vendor ? "$^$" : "",
+ _(info->name), value);
+ add_to_moreinfo(group, info->name, value);
+ dmi_succeeded = TRUE;
+ break;
+ }
+ }
}
- dmi_succeeded = TRUE;
- } else {
- dmi_info = h_strdup_cprintf("%s=%s\n",
- dmi_info,
- _(info->name),
- (getuid() == 0)
- ? _("(Not available)")
- : _("(Not available; Perhaps try running HardInfo as root.)") );
- }
}
- }
- if (!dmi_succeeded) {
- g_free(dmi_info);
- dmi_info = NULL;
- }
+ if (!dmi_succeeded) {
+ g_free(dmi_info);
+ dmi_info = NULL;
+ }
- return dmi_succeeded;
+ return dmi_succeeded;
}
-void __scan_dmi()
+void __scan_dmi(void)
{
gboolean dmi_ok;
dmi_ok = dmi_get_info();
if (!dmi_ok) {
- dmi_info = g_strdup("[No DMI information]\n"
- "There was an error retrieving the information.=\n"
- "Please try running HardInfo as root.=\n");
+ dmi_info = g_strdup_printf("[%s]\n%s=\n",
+ _("DMI Unavailable"),
+ (getuid() == 0)
+ ? _("DMI is not avaliable. Perhaps this platform does not provide DMI.")
+ : _("DMI is not available; Perhaps try running HardInfo as root.") );
+
}
}
diff --git a/modules/devices/dmi_memory.c b/modules/devices/dmi_memory.c
new file mode 100644
index 00000000..eba26c8b
--- /dev/null
+++ b/modules/devices/dmi_memory.c
@@ -0,0 +1,1050 @@
+/*
+ * HardInfo - Displays System Information
+ * Copyright (C) 2003-2019 L. A. F. Pereira <l@tia.mat.br>
+ * Copyright (C) 2019 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 or later.
+ *
+ * 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
+ */
+
+#define _GNU_SOURCE
+
+#include "hardinfo.h"
+#include "devices.h"
+#include "vendor.h"
+#include <inttypes.h>
+
+extern const char *dtree_mem_str; /* in devicetree.c */
+
+/* in monitors.c */
+gchar **get_output_lines(const char *cmd_line);
+
+#include "util_sysobj.h" /* for appfsp() */
+#define dmi_spd_msg(...) /* fprintf (stderr, __VA_ARGS__) */
+
+typedef uint64_t dmi_mem_size;
+
+#include "spd-decode.c"
+
+gboolean no_handles = FALSE;
+gboolean sketchy_info = FALSE;
+
+int dmi_ram_types = 0; /* bits using enum RamType */
+
+/* strings from dmidecode */
+static const char empty_mem_str[] = "No Module Installed";
+static const char unknown_mfgr_str[] = "<BAD INDEX>";
+static const char mobo_location[] = "System Board Or Motherboard";
+static const char mobo_shorter[] = "Mainboard";
+static const dmi_type dta = 16; /* array */
+static const dmi_type dtm = 17; /* socket */
+static const char mem_icon[] = "memory.png";
+static const char array_icon[] = "devices.png";
+static const char empty_icon[] = "module.png";
+
+#define UNKNOWN_MEM_TYPE_STRING _("RAM")
+#define UNKIFNULL2(f) ((f) ? f : _("(Unknown)"))
+#define UNKIFEMPTY2(f) ((*f) ? f : _("(Unknown)"))
+#define STR_IGNORE(str, ignore) if (SEQ(str, ignore)) { *str = 0; null_if_empty(&str); }
+
+dmi_mem_size dmi_read_memory_str_to_MiB(const char *memstr) {
+ dmi_mem_size ret = 0, v = 0;
+ char l[7] = "";
+ /* dmidecode units: "bytes", "kB", "MB", "GB", "TB", "PB", "EB", "ZB" */
+ int mc = sscanf(memstr, "%"PRId64" %6s", &v, l);
+ if (mc == 2) {
+ if (SEQ(l, "ZB")) ret = v * 1024 * 1024 * 1024 * 1024 * 1024;
+ else if (SEQ(l, "EB")) ret = v * 1024 * 1024 * 1024 * 1024;
+ else if (SEQ(l, "PB")) ret = v * 1024 * 1024 * 1024;
+ else if (SEQ(l, "TB")) ret = v * 1024 * 1024;
+ else if (SEQ(l, "GB")) ret = v * 1024;
+ else if (SEQ(l, "MB")) ret = v;
+ else if (SEQ(l, "kB")) {
+ /* should never appear */
+ if (v % 1024) { dmi_spd_msg("OMG kB!"); }
+ ret = v / 1024;
+ }
+ else if (SEQ(l, "bytes")) {
+ /* should never appear */
+ if (v % 1024) { dmi_spd_msg("OMG bytes!"); }
+ ret = v / (1024 * 1024);
+ }
+ }
+ return ret;
+}
+
+typedef struct {
+ dmi_handle array_handle;
+ gboolean is_main_memory;
+ gchar *locator;
+ gchar *use;
+ gchar *ecc;
+ int devs;
+ int devs_populated;
+ dmi_mem_size size_MiB_max;
+ dmi_mem_size size_MiB_present;
+ dmi_mem_size size_MiB_rom;
+ int ram_types; /* bits using enum RamType */
+} dmi_mem_array;
+
+dmi_mem_array *dmi_mem_array_new(dmi_handle h) {
+ dmi_mem_array *s = g_new0(dmi_mem_array, 1);
+ s->array_handle = h;
+ s->use = dmidecode_match("Use", &dta, &h);
+ if (SEQ(s->use, "System Memory"))
+ s->is_main_memory = TRUE;
+ s->ecc = dmidecode_match("Error Correction Type", &dta, &h);
+ s->locator = dmidecode_match("Location", &dta, &h);
+ if (SEQ(s->locator, mobo_location)) {
+ g_free(s->locator);
+ s->locator = g_strdup(mobo_shorter);
+ s->is_main_memory = TRUE;
+ }
+
+ gchar *array_max_size = dmidecode_match("Maximum Capacity", &dta, &h);
+ if (array_max_size) {
+ s->size_MiB_max = dmi_read_memory_str_to_MiB(array_max_size);
+ g_free(array_max_size);
+ }
+ gchar *array_devs = dmidecode_match("Number Of Devices", &dta, &h);
+ if (array_devs) {
+ s->devs = strtol(array_devs, NULL, 10);
+ g_free(array_devs);
+ }
+ return s;
+}
+
+void dmi_mem_array_free(dmi_mem_array* s) {
+ if (s) {
+ g_free(s->locator);
+ g_free(s->use);
+ g_free(s->ecc);
+ g_free(s);
+ }
+}
+
+typedef struct dmi_mem_socket {
+ dmi_handle handle;
+ dmi_handle array_handle;
+ gboolean populated;
+ gchar *locator;
+ gchar *full_locator;
+ gchar *short_locator;
+ gchar *size_str;
+ dmi_mem_size size_MiB;
+
+ gboolean is_not_ram; /* maybe is_rom, maybe elsewise, but don't include in RAM total */
+ gboolean is_rom;
+
+ gchar *type;
+ gchar *type_detail;
+ int ram_type; /* using enum RamType */
+ gchar *array_locator;
+ gchar *bank_locator;
+ gchar *rank;
+ gchar *form_factor;
+ gchar *speed_str;
+ gchar *configured_clock_str;
+ gchar *voltage_min_str;
+ gchar *voltage_max_str;
+ gchar *voltage_conf_str;
+ gchar *partno;
+ gchar *data_width;
+ gchar *total_width;
+ gchar *mfgr;
+ gboolean has_jedec_mfg_id;
+ int mfgr_bank, mfgr_index;
+
+ const Vendor *vendor;
+ spd_data *spd;
+} dmi_mem_socket;
+
+typedef struct {
+ gboolean empty;
+ GSList *arrays;
+ GSList *sockets;
+ GSList *spd;
+ dmi_mem_size spd_size_MiB;
+ int spd_ram_types; /* bits using enum RamType */
+
+ dmi_mem_size system_memory_MiB;
+ int system_memory_ram_types; /* bits using enum RamType */
+
+ /* ->short_locator is unique among *sockets */
+ gboolean unique_short_locators;
+} dmi_mem;
+
+gboolean null_if_empty(gchar **str) {
+ if (str && *str) {
+ gchar *p = *str;
+ while(p && *p) {
+ if (isalnum(*p))
+ return FALSE;
+ p++;
+ }
+ *str = NULL;
+ }
+ return TRUE;
+}
+
+dmi_mem_socket *dmi_mem_socket_new(dmi_handle h) {
+ dmi_mem_socket *s = g_new0(dmi_mem_socket, 1);
+ s->handle = h;
+ s->locator = dmidecode_match("Locator", &dtm, &h);
+ s->size_str = dmidecode_match("Size", &dtm, &h);
+ if (s->size_str)
+ s->size_MiB = dmi_read_memory_str_to_MiB(s->size_str);
+
+ s->bank_locator = dmidecode_match("Bank Locator", &dtm, &h);
+ STR_IGNORE(s->bank_locator, "Unknown");
+ STR_IGNORE(s->bank_locator, "Not Specified");
+ null_if_empty(&s->bank_locator);
+
+ gchar *ah = dmidecode_match("Array Handle", &dtm, &h);
+ STR_IGNORE(ah, "Unknown");
+ if (ah) {
+ s->array_handle = strtol(ah, NULL, 16);
+ g_free(ah);
+ s->array_locator = dmidecode_match("Location", &dta, &s->array_handle);
+ if (SEQ(s->array_locator, mobo_location)) {
+ g_free(s->array_locator);
+ s->array_locator = g_strdup(mobo_shorter);
+ }
+ }
+
+ gchar *ah_str = g_strdup_printf("0x%"PRIx32, s->array_handle);
+ gchar *h_str = g_strdup_printf("0x%"PRIx32, s->handle);
+ s->short_locator = g_strdup_printf("%s \u27A4 %s",
+ s->array_locator ? s->array_locator : ah_str,
+ s->locator ? s->locator : h_str);
+
+ if (s->bank_locator)
+ s->full_locator = g_strdup_printf("%s \u27A4 %s \u27A4 %s",
+ s->array_locator ? s->array_locator : ah_str,
+ s->bank_locator,
+ s->locator ? s->locator : h_str);
+ else
+ s->full_locator = g_strdup(s->short_locator);
+
+ g_free(ah_str);
+ g_free(h_str);
+
+ if (!g_str_has_prefix(s->size_str, empty_mem_str)) {
+ s->populated = 1;
+
+ s->form_factor = dmidecode_match("Form Factor", &dtm, &h);
+ s->type = dmidecode_match("Type", &dtm, &h);
+ STR_IGNORE(s->type, "Unknown");
+ if (SEQ(s->type, "Flash") || SEQ(s->type, "ROM")) {
+ s->is_rom = TRUE;
+ s->is_not_ram = TRUE;
+ } else {
+ if (SEQ(s->type, "DDR")) s->ram_type = DDR_SDRAM;
+ if (SEQ(s->type, "DDR2")) s->ram_type = DDR2_SDRAM;
+ if (SEQ(s->type, "DDR3")) s->ram_type = DDR3_SDRAM;
+ if (SEQ(s->type, "DDR4")) s->ram_type = DDR4_SDRAM;
+ if (SEQ(s->type, "DRDRAM")) s->ram_type = DIRECT_RAMBUS;
+ if (SEQ(s->type, "RDRAM")) s->ram_type = RAMBUS;
+ if (s->ram_type)
+ dmi_ram_types |= (1 << (s->ram_type-1));
+ }
+ s->type_detail = dmidecode_match("Type Detail", &dtm, &h);
+ STR_IGNORE(s->type_detail, "None");
+
+ s->speed_str = dmidecode_match("Speed", &dtm, &h);
+ s->configured_clock_str = dmidecode_match("Configured Clock Speed", &dtm, &h);
+ if (!s->configured_clock_str)
+ s->configured_clock_str = dmidecode_match("Configured Memory Speed", &dtm, &h);
+
+ s->voltage_min_str = dmidecode_match("Minimum Voltage", &dtm, &h);
+ s->voltage_max_str = dmidecode_match("Maximum Voltage", &dtm, &h);
+ s->voltage_conf_str = dmidecode_match("Configured Voltage", &dtm, &h);
+ STR_IGNORE(s->voltage_min_str, "Unknown");
+ STR_IGNORE(s->voltage_max_str, "Unknown");
+ STR_IGNORE(s->voltage_conf_str, "Unknown");
+
+ s->partno = dmidecode_match("Part Number", &dtm, &h);
+ STR_IGNORE(s->partno, "PartNum0");
+ STR_IGNORE(s->partno, "PartNum1");
+ STR_IGNORE(s->partno, "PartNum2");
+ STR_IGNORE(s->partno, "PartNum3");
+ null_if_empty(&s->partno);
+
+ s->data_width = dmidecode_match("Data Width", &dtm, &h);
+ s->total_width = dmidecode_match("Total Width", &dtm, &h);
+
+ s->rank = dmidecode_match("Rank", &dtm, &h);
+
+ s->mfgr = dmidecode_match("Manufacturer", &dtm, &h);
+ STR_IGNORE(s->mfgr, unknown_mfgr_str);
+ STR_IGNORE(s->mfgr, "Manufacturer0");
+ STR_IGNORE(s->mfgr, "Manufacturer1");
+ STR_IGNORE(s->mfgr, "Manufacturer2");
+ STR_IGNORE(s->mfgr, "Manufacturer3");
+ STR_IGNORE(s->mfgr, "Unknown");
+ null_if_empty(&s->mfgr);
+
+ gchar *mfgr_id_str = dmidecode_match("Module Manufacturer ID", &dtm, &h);
+ STR_IGNORE(mfgr_id_str, "Unknown");
+ if (mfgr_id_str) {
+ static const char dmi_mfg_id_fmt[] = "Bank %d, Hex 0x%02X"; /* from dmidecode.c */
+ int mc = sscanf(strstr(mfgr_id_str, "Bank"), dmi_mfg_id_fmt, &s->mfgr_bank, &s->mfgr_index);
+ if (mc > 0 && !s->mfgr) {
+ s->has_jedec_mfg_id = TRUE;
+ s->mfgr = g_strdup(JEDEC_MFG_STR(s->mfgr_bank, s->mfgr_index));
+ }
+ }
+
+ if (s->mfgr && !s->has_jedec_mfg_id && strlen(s->mfgr) == 4) {
+ /* Some BIOS put the code bytes into the mfgr string
+ * if they don't know the manufacturer.
+ * It's not always reliable, but what is lost
+ * by trying it? */
+ if (isxdigit(s->mfgr[0])
+ && isxdigit(s->mfgr[1])
+ && isxdigit(s->mfgr[2])
+ && isxdigit(s->mfgr[3]) ) {
+ int codes = strtol(s->mfgr, NULL, 16);
+ char *mstr = NULL;
+ decode_ddr34_manufacturer(codes >> 8, codes & 0xff,
+ &mstr, &s->mfgr_bank, &s->mfgr_index);
+ s->has_jedec_mfg_id = TRUE;
+ g_free(s->mfgr);
+ s->mfgr = NULL;
+ if (mstr)
+ s->mfgr = g_strdup(mstr);
+ }
+ }
+
+ s->vendor = vendor_match(s->mfgr, NULL);
+ }
+ return s;
+}
+
+void dmi_mem_socket_free(dmi_mem_socket* s) {
+ if (s) {
+ g_free(s->locator);
+ g_free(s->full_locator);
+ g_free(s->short_locator);
+ g_free(s->size_str);
+ g_free(s->type);
+ g_free(s->type_detail);
+ g_free(s->bank_locator);
+ g_free(s->rank);
+ g_free(s->array_locator);
+ g_free(s->form_factor);
+ g_free(s->speed_str);
+ g_free(s->configured_clock_str);
+ g_free(s->voltage_min_str);
+ g_free(s->voltage_max_str);
+ g_free(s->voltage_conf_str);
+ g_free(s->partno);
+ g_free(s->data_width);
+ g_free(s->total_width);
+ g_free(s->mfgr);
+
+ g_free(s);
+ }
+}
+
+dmi_mem_array *dmi_mem_find_array(dmi_mem *s, unsigned int handle) {
+ GSList *l = NULL;
+ for(l = s->arrays; l; l = l->next) {
+ dmi_mem_array *a = (dmi_mem_array*)l->data;
+ if (a->array_handle == handle)
+ return a;
+ }
+ return NULL;
+}
+
+static int dmi_spd_match_score(dmi_mem_socket *s, spd_data *e) {
+ int score = 0;
+ if (SEQ(s->partno, e->partno))
+ score += 20;
+ if (s->size_MiB == e->size_MiB)
+ score += 10;
+ if (s->vendor == e->vendor)
+ score += 5;
+ return score;
+}
+
+/* fill in missing from SPD */
+static void dmi_fill_from_spd(dmi_mem_socket *s) {
+ if (!s->spd)
+ return;
+
+ if (!s->mfgr && s->spd->vendor_str) {
+ s->mfgr = g_strdup(s->spd->vendor_str);
+ s->vendor = s->spd->vendor;
+ }
+ if (!s->has_jedec_mfg_id) {
+ s->mfgr_bank = s->spd->vendor_bank;
+ s->mfgr_index = s->spd->vendor_index;
+ s->has_jedec_mfg_id = TRUE;
+ }
+
+ //Always true - FIXME
+ //if (!s->partno && s->spd->partno)
+ s->partno = g_strdup(s->spd->partno);
+
+ if (!s->form_factor && s->spd->form_factor)
+ s->form_factor = g_strdup(s->spd->form_factor);
+
+ //Always true - FIXME
+ //if (!s->type_detail && s->spd->type_detail)
+ s->type_detail = g_strdup(s->spd->type_detail);
+}
+
+static dmi_mem_size size_of_online_memory_blocks() {
+ gchar *block_size_bytes_str = NULL;
+ dmi_mem_size block_size_bytes = 0;
+ dmi_mem_size ret = 0;
+
+ if (g_file_get_contents("/sys/devices/system/memory/block_size_bytes", &block_size_bytes_str, NULL, NULL) ) {
+ block_size_bytes = strtoll(block_size_bytes_str, NULL, 16);
+ }
+ if (!block_size_bytes)
+ return 0;
+
+ const gchar *f = NULL;
+ GDir *d = g_dir_open("/sys/devices/system/memory", 0, NULL);
+ if (!d) return 0;
+
+ while((f = g_dir_read_name(d))) {
+ gchar *p = g_strdup_printf("/sys/devices/system/memory/%s/online", f);
+ gchar *ol = NULL;
+ if (g_file_get_contents(p, &ol, NULL, NULL) ) {
+ if (1 == strtol(ol, NULL, 0)) {
+ ret += block_size_bytes;
+ }
+ }
+ g_free(ol);
+ g_free(p);
+ }
+ g_dir_close(d);
+ return ret;
+}
+
+dmi_mem *dmi_mem_new() {
+ dmi_mem *m = g_new0(dmi_mem, 1);
+
+ dmi_handle_list *hla = dmidecode_handles(&dta);
+ if (hla) {
+ unsigned int i = 0;
+ for(i = 0; i < hla->count; i++) {
+ dmi_handle h = hla->handles[i];
+ m->arrays = g_slist_append(m->arrays, dmi_mem_array_new(h));
+ }
+ dmi_handle_list_free(hla);
+ }
+
+ dmi_handle_list *hlm = dmidecode_handles(&dtm);
+ if (hlm) {
+ unsigned int i = 0;
+ for(i = 0; i < hlm->count; i++) {
+ dmi_handle h = hlm->handles[i];
+ m->sockets = g_slist_append(m->sockets, dmi_mem_socket_new(h));
+ }
+ dmi_handle_list_free(hlm);
+ }
+
+ m->spd = spd_scan();
+
+ if (!m->sockets && !m->arrays && !m->spd) {
+ m->empty = 1;
+ goto dmi_mem_new_last_chance;
+ }
+
+ GSList *l = NULL, *l2 = NULL;
+
+ /* totals for SPD */
+ for(l2 = m->spd; l2; l2 = l2->next) {
+ spd_data *e = (spd_data*)l2->data;
+ m->spd_size_MiB += e->size_MiB;
+ if (e->type)
+ m->spd_ram_types |= (1 << (e->type-1));
+ }
+
+ m->unique_short_locators = TRUE;
+ for(l = m->sockets; l; l = l->next) {
+ dmi_mem_socket *s = (dmi_mem_socket*)l->data;
+
+ /* check for duplicate short_locator */
+ if (m->unique_short_locators) {
+ for(l2 = l->next; l2; l2 = l2->next) {
+ dmi_mem_socket *d = (dmi_mem_socket*)l2->data;
+ if (SEQ(s->short_locator, d->short_locator)) {
+ m->unique_short_locators = FALSE;
+ break;
+ }
+ }
+ }
+
+ /* update array present devices/size */
+ dmi_mem_array *a = dmi_mem_find_array(m, s->array_handle);
+ if (a) {
+ if (s->is_not_ram) {
+ if (s->is_rom)
+ a->size_MiB_rom += s->size_MiB;
+ } else {
+ a->size_MiB_present += s->size_MiB;
+ if (s->populated)
+ a->devs_populated++;
+ if (s->ram_type)
+ a->ram_types |= (1 << (s->ram_type-1));
+ }
+ }
+ }
+
+ if (m->sockets && m->spd) {
+ /* attempt to match DMI and SPD data */
+ GSList *sock_queue = g_slist_copy(m->sockets);
+ int loops = g_slist_length(sock_queue) * 4;
+ while(sock_queue) {
+ if (loops-- <= 0) break; /* something is wrong, give up */
+ spd_data *best = NULL;
+ int best_score = 0;
+ dmi_mem_socket *s = (dmi_mem_socket*)sock_queue->data;
+ /* pop that one off */
+ sock_queue = g_slist_delete_link(sock_queue, sock_queue);
+ if (!s->populated)
+ continue;
+ for(l2 = m->spd; l2; l2 = l2->next) {
+ spd_data *e = (spd_data*)l2->data;
+ int score = dmi_spd_match_score(s, e);
+ if (score > best_score) {
+ if (score > e->match_score) {
+ best = e;
+ best_score = score;
+ }
+ }
+ }
+ if (best) {
+ if (best->dmi_socket) {
+ /* displace */
+ dmi_mem_socket *old_sock = best->dmi_socket;
+ old_sock->spd = NULL;
+ sock_queue = g_slist_append(sock_queue, old_sock);
+
+ best->dmi_socket = s;
+ best->match_score = best_score;
+ s->spd = best;
+ } else {
+ best->dmi_socket = s;
+ best->match_score = best_score;
+ s->spd = best;
+ }
+ }
+ }
+
+ /* fill any missing data in DMI that is
+ * provided by the matched SPD */
+ for(l = m->sockets; l; l = l->next) {
+ dmi_mem_socket *s = (dmi_mem_socket*)l->data;
+ dmi_fill_from_spd(s);
+ }
+
+ } /* end if (m->sockets && m->spd) */
+
+ /* Look for arrays with "System Memory" use,
+ * or Mainboard as locator */
+ for(l = m->arrays; l; l = l->next) {
+ dmi_mem_array *a = (dmi_mem_array*)l->data;
+ if (a->is_main_memory) {
+ m->system_memory_MiB += a->size_MiB_present;
+ m->system_memory_ram_types |= a->ram_types;
+ }
+ }
+
+ /* If no arrays, then try the SPD total */
+ if (!m->system_memory_MiB) {
+ m->system_memory_MiB = m->spd_size_MiB;
+ m->system_memory_ram_types |= m->spd_ram_types;
+ }
+
+dmi_mem_new_last_chance:
+ if (m->empty) {
+ /* reach */
+ if (dtree_mem_str) {
+ int rt = 0;
+ m->system_memory_MiB = dmi_read_memory_str_to_MiB(dtree_mem_str);
+ if (strstr(dtree_mem_str, "DDR4")) rt = DDR4_SDRAM;
+ else if (strstr(dtree_mem_str, "DDR3")) rt = DDR3_SDRAM;
+ else if (strstr(dtree_mem_str, "DDR2")) rt = DDR2_SDRAM;
+ else if (strstr(dtree_mem_str, "DDR")) rt = DDR_SDRAM;
+ else if (strstr(dtree_mem_str, "DRDRAM")) rt = DIRECT_RAMBUS;
+ else if (strstr(dtree_mem_str, "RDRAM")) rt = RAMBUS;
+ if (rt)
+ m->system_memory_ram_types |= (1 << (rt-1));
+ }
+ }
+
+ /* Try to sum the online blocks for a physical memory total */
+ if (!m->system_memory_MiB)
+ m->system_memory_MiB = size_of_online_memory_blocks() / 1024 / 1024;
+
+ return m;
+}
+
+void dmi_mem_free(dmi_mem* s) {
+ if (s) {
+ g_slist_free_full(s->arrays, (GDestroyNotify)dmi_mem_array_free);
+ g_slist_free_full(s->sockets, (GDestroyNotify)dmi_mem_socket_free);
+ g_slist_free_full(s->spd, (GDestroyNotify)spd_data_free);
+ g_free(s);
+ }
+}
+
+gchar *make_spd_section(spd_data *spd) {
+ gchar *ret = NULL;
+ if (spd) {
+ gchar *full_spd = NULL;
+ switch(spd->type) {
+ case SDR_SDRAM:
+ full_spd = decode_sdr_sdram_extra(spd->bytes);
+ break;
+ case DDR_SDRAM:
+ full_spd = decode_ddr_sdram_extra(spd->bytes);
+ break;
+ case DDR2_SDRAM:
+ full_spd = decode_ddr2_sdram_extra(spd->bytes);
+ break;
+ case DDR3_SDRAM:
+ full_spd = decode_ddr3_sdram_extra(spd->bytes);
+ break;
+ case DDR4_SDRAM:
+ full_spd = decode_ddr4_sdram_extra(spd->bytes, spd->spd_size);
+ break;
+ default:
+ DEBUG("blug for type: %d %s\n", spd->type, ram_types[spd->type]);
+ }
+ gchar *size_str = NULL;
+ if (!spd->size_MiB)
+ size_str = g_strdup(_("(Unknown)"));
+ else
+ size_str = g_strdup_printf("%"PRId64" %s", spd->size_MiB, _("MiB") );
+
+ gchar *mfg_date_str = NULL;
+ if (spd->year)
+ mfg_date_str = g_strdup_printf("%d / %d", spd->week, spd->year);
+
+ ret = g_strdup_printf("[%s]\n"
+ "%s=%s (%s)%s\n"
+ "%s=%d.%d\n"
+ "%s=%s\n"
+ "%s=%s\n"
+ "$^$%s=[%02x%02x] %s\n" /* module vendor */
+ "$^$%s=[%02x%02x] %s\n" /* dram vendor */
+ "%s=%s\n" /* part */
+ "%s=%s\n" /* size */
+ "%s=%s\n" /* mfg date */
+ "%s",
+ _("Serial Presence Detect (SPD)"),
+ _("Source"), spd->dev, spd->spd_driver,
+ (spd->type == DDR4_SDRAM && strcmp(spd->spd_driver, "ee1004") != 0) ? problem_marker() : "",
+ _("SPD Revision"), spd->spd_rev_major, spd->spd_rev_minor,
+ _("Form Factor"), UNKIFNULL2(spd->form_factor),
+ _("Type"), UNKIFEMPTY2(spd->type_detail),
+ _("Module Vendor"), spd->vendor_bank, spd->vendor_index,
+ UNKIFNULL2(spd->vendor_str),
+ _("DRAM Vendor"), spd->dram_vendor_bank, spd->dram_vendor_index,
+ UNKIFNULL2(spd->dram_vendor_str),
+ _("Part Number"), UNKIFEMPTY2(spd->partno),
+ _("Size"), size_str,
+ _("Manufacturing Date (Week / Year)"), UNKIFNULL2(mfg_date_str),
+ full_spd ? full_spd : ""
+ );
+ g_free(full_spd);
+ g_free(size_str);
+ g_free(mfg_date_str);
+ }
+ return ret;
+}
+
+static gchar *tag_make_safe_inplace(gchar *tag) {
+ if (!tag)
+ return tag;
+ if (!g_utf8_validate(tag, -1, NULL))
+ return tag; //TODO: reconsider
+ gchar *p = tag, *pd = tag;
+ while(*p) {
+ gchar *np = g_utf8_next_char(p);
+ gunichar c = g_utf8_get_char_validated(p, -1);
+ int l = g_unichar_to_utf8(c, NULL);
+ if (l == 1 && g_unichar_isalnum(c)) {
+ g_unichar_to_utf8(c, pd);
+ } else {
+ *pd = '_';
+ }
+ p = np;
+ pd++;
+ }
+ return tag;
+}
+
+gchar *memory_devices_get_info() {
+ gchar *icons = g_strdup("");
+ gchar *ret = g_strdup_printf("[%s]\n", _("Memory Device List"));
+ GSList *l = NULL;
+ sketchy_info = FALSE;
+ gchar tag_prefix[] = "DEV";
+
+ dmi_mem *mem = dmi_mem_new();
+
+ /* Arrays */
+ for(l = mem->arrays; l; l = l->next) {
+ dmi_mem_array *a = (dmi_mem_array*)l->data;
+ gchar *tag = g_strdup_printf("%s", a->locator);
+ gchar *size_str = NULL, *rom_size_str = NULL;
+
+ tag_make_safe_inplace(tag);
+
+ if (a->size_MiB_max > 1024 && (a->size_MiB_max % 1024 == 0)
+ && a->size_MiB_present > 1024 && (a->size_MiB_present % 1024 == 0) )
+ size_str = g_strdup_printf("%"PRId64" / %"PRId64" %s", a->size_MiB_present / 1024, a->size_MiB_max / 1024, _("GiB"));
+ else
+ size_str = g_strdup_printf("%"PRId64" / %"PRId64" %s", a->size_MiB_present, a->size_MiB_max, _("MiB"));
+
+ if (a->size_MiB_max < a->size_MiB_present) {
+ sketchy_info = TRUE;
+ size_str = h_strdup_cprintf(" %s", size_str, problem_marker());
+ }
+
+ if (a->size_MiB_rom > 1024 && (a->size_MiB_rom % 1024 == 0))
+ rom_size_str = g_strdup_printf("%"PRId64" %s", a->size_MiB_rom / 1024, _("GiB"));
+ else
+ rom_size_str = g_strdup_printf("%"PRId64" %s", a->size_MiB_rom, _("MiB"));
+
+ gchar *types_str = NULL;
+ int i;
+ for(i = 1; i < N_RAM_TYPES; i++) {
+ int bit = 1 << (i-1);
+ if (a->ram_types & bit)
+ types_str = appfsp(types_str, "%s", GET_RAM_TYPE_STR(i));
+ }
+
+ gchar *details = g_strdup_printf("[%s]\n"
+ "%s=0x%"PRIx32"\n"
+ "%s=%s\n"
+ "%s=%s\n"
+ "%s=%s\n"
+ "%s=%s\n"
+ "%s=%d / %d\n"
+ "%s=[0x%x] %s\n"
+ "%s=%s\n",
+ _("Memory Array"),
+ _("DMI Handle"), a->array_handle,
+ _("Locator"), a->locator ? a->locator : ".",
+ _("Use"), UNKIFNULL2(a->use),
+ _("Error Correction Type"), UNKIFNULL2(a->ecc),
+ _("Size (Present / Max)"), size_str,
+ _("Devices (Populated / Sockets)"), a->devs_populated, a->devs,
+ _("Types Present"), a->ram_types, UNKIFNULL2(types_str),
+ _("ROM Size"), rom_size_str
+ );
+ moreinfo_add_with_prefix(tag_prefix, tag, details); /* moreinfo now owns *details */
+ ret = h_strdup_cprintf("$!%s$%s=%s|%s\n",
+ ret,
+ tag, a->locator, UNKIFNULL2(types_str), size_str
+ );
+ icons = h_strdup_cprintf("Icon$%s$=%s\n", icons, tag, array_icon);
+ g_free(tag);
+ g_free(size_str);
+ g_free(rom_size_str);
+ g_free(types_str);
+ }
+
+ /* Sockets */
+ for(l = mem->sockets; l; l = l->next) {
+ dmi_mem_socket *s = (dmi_mem_socket*)l->data;
+ gchar *tag = g_strdup_printf("%s", s->full_locator);
+ tag_make_safe_inplace(tag);
+
+ if (s->populated) {
+ gchar *size_str = NULL;
+ if (!s->size_str)
+ size_str = g_strdup(_("(Unknown)"));
+ else if (!s->size_MiB)
+ size_str = g_strdup(s->size_str);
+ else
+ size_str = g_strdup_printf("%"PRId64" %s", s->size_MiB, _("MiB") );
+
+ gchar *spd = s->spd ? make_spd_section(s->spd) : NULL;
+
+ gchar *details = g_strdup_printf("[%s]\n"
+ "%s=0x%"PRIx32", 0x%"PRIx32"\n"
+ "%s=%s\n"
+ "%s=%s\n"
+ "%s=%s\n"
+ "%s=%s / %s\n"
+ "$^$%s=[%02x%02x] %s\n"
+ "%s=%s\n"
+ "%s=%s\n"
+ "%s=%s\n"
+ "%s=%s\n"
+ "%s=%s / %s\n"
+ "%s=%s\n"
+ "%s=%s\n"
+ "%s=%s\n"
+ "%s=%s\n"
+ "%s", /* spd */
+ _("Memory Socket"),
+ _("DMI Handles (Array, Socket)"), s->array_handle, s->handle,
+ _("Locator"), s->full_locator,
+ _("Bank Locator"), UNKIFNULL2(s->bank_locator),
+ _("Form Factor"), UNKIFNULL2(s->form_factor),
+ _("Type"), UNKIFNULL2(s->type), UNKIFNULL2(s->type_detail),
+ _("Vendor"),
+ s->mfgr_bank, s->mfgr_index, UNKIFNULL2(s->mfgr),
+ _("Part Number"), UNKIFNULL2(s->partno),
+ _("Size"), size_str,
+ _("Rated Speed"), UNKIFNULL2(s->speed_str),
+ _("Configured Speed"), UNKIFNULL2(s->configured_clock_str),
+ _("Data Width/Total Width"), UNKIFNULL2(s->data_width), UNKIFNULL2(s->total_width),
+ _("Rank"), UNKIFNULL2(s->rank),
+ _("Minimum Voltage"), UNKIFNULL2(s->voltage_min_str),
+ _("Maximum Voltage"), UNKIFNULL2(s->voltage_max_str),
+ _("Configured Voltage"), UNKIFNULL2(s->voltage_conf_str),
+ spd ? spd : ""
+ );
+ g_free(spd);
+ moreinfo_add_with_prefix(tag_prefix, tag, details); /* moreinfo now owns *details */
+ gchar *mfgr = s->mfgr ? vendor_match_tag(s->mfgr, params.fmt_opts) : NULL;
+ ret = h_strdup_cprintf("$!%s$%s=%s|%s|%s\n",
+ ret,
+ tag,
+ mem->unique_short_locators ? s->short_locator : s->full_locator,
+ UNKIFNULL2(s->partno), size_str, UNKIFNULL2(mfgr)
+ );
+ icons = h_strdup_cprintf("Icon$%s$=%s\n", icons, tag, mem_icon);
+ g_free(size_str);
+ g_free(mfgr);
+ } else {
+ gchar *details = g_strdup_printf("[%s]\n"
+ "%s=0x%"PRIx32", 0x%"PRIx32"\n"
+ "%s=%s\n"
+ "%s=%s\n"
+ "%s=%s\n",
+ _("Memory Socket"),
+ _("DMI Handles (Array, Socket)"), s->array_handle, s->handle,
+ _("Locator"), s->full_locator,
+ _("Bank Locator"), UNKIFNULL2(s->bank_locator),
+ _("Size"), _("(Empty)")
+ );
+ moreinfo_add_with_prefix(tag_prefix, tag, details); /* moreinfo now owns *details */
+ ret = h_strdup_cprintf("$%s$%s=|%s\n",
+ ret,
+ tag,
+ mem->unique_short_locators ? s->short_locator : s->full_locator,
+ _("(Empty)")
+ );
+ icons = h_strdup_cprintf("Icon$%s$=%s\n", icons, tag, empty_icon);
+ }
+ g_free(tag);
+ }
+
+ /* No DMI Array, show SPD totals */
+ if (!mem->arrays && mem->spd) {
+ gchar *key = g_strdup("SPD:*");
+ gchar *tag = g_strdup(key);
+ tag_make_safe_inplace(tag);
+ gchar *types_str = NULL;
+ gchar *size_str = NULL;
+
+ if (mem->spd_size_MiB > 1024 && (mem->spd_size_MiB % 1024 == 0) )
+ size_str = g_strdup_printf("%"PRId64" %s", mem->spd_size_MiB / 1024, _("GiB"));
+ else
+ size_str = g_strdup_printf("%"PRId64" %s", mem->spd_size_MiB, _("MiB"));
+
+ int i;
+ for(i = 1; i < N_RAM_TYPES; i++) {
+ int bit = 1 << (i-1);
+ if (mem->spd_ram_types & bit)
+ types_str = appfsp(types_str, "%s", GET_RAM_TYPE_STR(i));
+ }
+
+ gchar *details = g_strdup_printf("[%s]\n"
+ "%s=%s\n"
+ "%s=%d\n"
+ "%s=[0x%x] %s\n",
+ _("Serial Presence Detect (SPD) Summary"),
+ _("Size"), size_str,
+ _("Devices"), g_slist_length(mem->spd),
+ _("Types Present"), mem->spd_ram_types, UNKIFNULL2(types_str)
+ );
+ moreinfo_add_with_prefix(tag_prefix, tag, details); /* moreinfo now owns *details */
+ ret = h_strdup_cprintf("$!%s$%s=%s|%s\n",
+ ret,
+ tag, key, UNKIFNULL2(types_str), size_str
+ );
+ icons = h_strdup_cprintf("Icon$%s$=%s\n", icons, tag, array_icon);
+ g_free(key);
+ g_free(tag);
+ g_free(size_str);
+ g_free(types_str);
+ }
+
+ /* Unmatched SPD */
+ for(l = mem->spd; l; l = l->next) {
+ spd_data *s = (spd_data*)l->data;
+ if (s->dmi_socket) continue; /* claimed by DMI */
+ gchar *key = g_strdup_printf("SPD:%s", s->dev);
+ gchar *tag = g_strdup(key);
+ tag_make_safe_inplace(tag);
+
+ gchar *vendor_str = NULL;
+ if (s->vendor) {
+ vendor_str = vendor_get_link_from_vendor(s->vendor);
+ }
+ gchar *size_str = NULL;
+ if (!s->size_MiB)
+ size_str = g_strdup(_("(Unknown)"));
+ else
+ size_str = g_strdup_printf("%"PRId64" %s", s->size_MiB, _("MiB") );
+
+ gchar *details = make_spd_section(s);
+
+ moreinfo_add_with_prefix(tag_prefix, tag, details); /* moreinfo now owns *details */
+ const gchar *mfgr = s->vendor_str ? vendor_get_shortest_name(s->vendor_str) : NULL;
+ ret = h_strdup_cprintf("$!%s$%s%s=%s|%s|%s\n",
+ ret,
+ tag, key, problem_marker(), UNKIFEMPTY2(s->partno), size_str, UNKIFNULL2(mfgr)
+ );
+ icons = h_strdup_cprintf("Icon$%s$=%s\n", icons, tag, mem_icon);
+ g_free(vendor_str);
+ g_free(size_str);
+ g_free(key);
+ g_free(tag);
+ }
+
+ no_handles = FALSE;
+ if(mem->empty) {
+ no_handles = TRUE;
+ g_free(ret);
+ ret = g_strdup_printf("[%s]\n%s=%s\n" "[$ShellParam$]\nViewType=0\n",
+ _("Memory Device List"), _("Result"),
+ (getuid() == 0)
+ ? _("(Not available)")
+ : _("(Not available; Perhaps try running HardInfo as root.)") );
+ } else {
+ ret = h_strdup_cprintf(
+ "[$ShellParam$]\nViewType=1\n"
+ "ColumnTitle$TextValue=%s\n" /* Locator */
+ "ColumnTitle$Extra1=%s\n" /* Size */
+ "ColumnTitle$Extra2=%s\n" /* Vendor */
+ "ColumnTitle$Value=%s\n" /* Part */
+ "ShowColumnHeaders=true\n"
+ "%s",
+ ret,
+ _("Locator"),
+ _("Size"),
+ _("Vendor"),
+ _("Part"),
+ icons
+ );
+ }
+
+ g_free(icons);
+ dmi_mem_free(mem);
+ return ret;
+}
+
+gchar *memory_devices_get_system_memory_types_str() {
+ gchar *ret = NULL, *types_str = NULL;
+ int i, rtypes;
+
+ dmi_mem *lmem = dmi_mem_new();
+ rtypes = lmem->system_memory_ram_types;
+ dmi_mem_free(lmem);
+
+ for(i = 1; i < N_RAM_TYPES; i++) {
+ int bit = 1 << (i-1);
+ if (rtypes & bit)
+ types_str = appfsp(types_str, "%s", GET_RAM_TYPE_STR(i));
+ }
+
+ if (types_str)
+ ret = g_strdup(types_str);
+ else
+ ret = g_strdup(UNKNOWN_MEM_TYPE_STRING);
+ g_free(types_str);
+ return ret;
+}
+
+uint64_t memory_devices_get_system_memory_MiB() {
+ dmi_mem *mem = dmi_mem_new();
+ int ret = (int)mem->system_memory_MiB;
+ dmi_mem_free(mem);
+ return ret;
+}
+
+gchar *memory_devices_get_system_memory_str() {
+ gchar *ret = NULL;
+ dmi_mem_size m = memory_devices_get_system_memory_MiB();
+ if (m) {
+ if (m > 1024 && (m % 1024 == 0) )
+ ret = g_strdup_printf("%"PRId64" %s", m/1024, _("GiB"));
+ else
+ ret = g_strdup_printf("%"PRId64" %s", m, _("MiB"));
+ }
+ return ret;
+}
+
+static gchar note_state[note_max_len] = "";
+
+gboolean memory_devices_hinote(const char **msg) {
+ gchar *want_dmi = _(" <b><i>dmidecode</i></b> utility available");
+ gchar *want_root = _(" ... <i>and</i> HardInfo running with superuser privileges");
+ gchar *want_at24 = _(" <b><i>at24</i></b> (or eeprom) module loaded (for SDR, DDR, DDR2, DDR3)");
+ gchar *want_ee1004 = _(" ... <i>or</i> <b><i>ee1004</i></b> module loaded <b>and configured!</b> (for DDR4)");
+
+ gboolean has_root = (getuid() == 0);
+ gboolean has_dmi = !no_handles;
+ gboolean has_at24eep = g_file_test("/sys/bus/i2c/drivers/at24", G_FILE_TEST_IS_DIR) ||
+ g_file_test("/sys/bus/i2c/drivers/eeprom", G_FILE_TEST_IS_DIR);
+ gboolean has_ee1004 = g_file_test("/sys/bus/i2c/drivers/ee1004", G_FILE_TEST_IS_DIR);
+
+ *note_state = 0; /* clear */
+ note_printf(note_state, "%s\n", _("Memory information requires <b>one or both</b> of the following:"));
+ note_print(note_state, "<tt>1. </tt>");
+ note_cond_bullet(has_dmi, note_state, want_dmi);
+ note_print(note_state, "<tt> </tt>");
+ note_cond_bullet(has_root, note_state, want_root);
+ note_print(note_state, "<tt>2. </tt>");
+ note_cond_bullet(has_at24eep, note_state, want_at24);
+ note_print(note_state, "<tt> </tt>");
+ note_cond_bullet(has_ee1004, note_state, want_ee1004);
+ g_strstrip(note_state); /* remove last \n */
+
+ gboolean ddr3_ee1004 = ((dmi_ram_types & (1<<(DDR3_SDRAM-1))) && has_ee1004);
+
+ gboolean best_state = FALSE;
+ if (has_dmi && has_root &&
+ ((has_at24eep && !spd_ddr4_partial_data)
+ || (has_ee1004 && !ddr3_ee1004) ) )
+ best_state = TRUE;
+
+ if (!best_state) {
+ *msg = note_state;
+ return TRUE;
+ }
+
+ if (sketchy_info) {
+ *msg = g_strdup(
+ _("\"More often than not, information contained in the DMI tables is inaccurate,\n"
+ "incomplete or simply wrong.\" -<i><b>dmidecode</b></i> manual page"));
+ return TRUE;
+ }
+
+ return FALSE;
+}
diff --git a/modules/devices/e2k/processor.c b/modules/devices/e2k/processor.c
new file mode 100644
index 00000000..74476853
--- /dev/null
+++ b/modules/devices/e2k/processor.c
@@ -0,0 +1,420 @@
+/*
+ * HardInfo - Displays System Information
+ * Copyright (C) 2020 EntityFX <artem.solopiy@gmail.com> and MCST Elbrus Team
+ * modified by Boris Afonot <boris.afonot@gmail.com> (2022)
+ * 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 "hardinfo.h"
+#include "devices.h"
+#include "cpu_util.h"
+
+static gchar *__cache_get_info_as_string(Processor *processor)
+{
+ gchar *result = g_strdup("");
+ GSList *cache_list;
+ ProcessorCache *cache;
+
+ if (!processor->cache) {
+ return g_strdup(_("Cache information not available=\n"));
+ }
+
+ 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,
+ cache->level,
+ C_("cache-type", cache->type),
+ cache->ways_of_associativity,
+ cache->number_of_sets,
+ cache->size);
+ }
+
+ 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;
+ gchar *endpoint, *entry, *index;
+ gchar *uref = NULL;
+ gint i;
+ gint processor_number = processor->id;
+
+ endpoint = g_strdup_printf("/sys/devices/system/cpu/cpu%d/cache", processor_number);
+
+ for (i = 0; ; i++) {
+ cache = g_new0(ProcessorCache, 1);
+
+ index = g_strdup_printf("index%d/", i);
+
+ entry = g_strconcat(index, "type", NULL);
+ cache->type = h_sysfs_read_string(endpoint, entry);
+ g_free(entry);
+
+ if (!cache->type) {
+ g_free(cache);
+ g_free(index);
+ goto fail;
+ }
+
+ entry = g_strconcat(index, "level", NULL);
+ cache->level = h_sysfs_read_int(endpoint, entry);
+ g_free(entry);
+
+ entry = g_strconcat(index, "number_of_sets", NULL);
+ cache->number_of_sets = h_sysfs_read_int(endpoint, entry);
+ g_free(entry);
+
+ entry = g_strconcat(index, "physical_line_partition", NULL);
+ cache->physical_line_partition = h_sysfs_read_int(endpoint, entry);
+ g_free(entry);
+
+ entry = g_strconcat(index, "size", NULL);
+ cache->size = h_sysfs_read_int(endpoint, entry);
+ g_free(entry);
+
+ entry = g_strconcat(index, "ways_of_associativity", NULL);
+ cache->ways_of_associativity = h_sysfs_read_int(endpoint, entry);
+ g_free(entry);
+
+ /* unique cache references: id is nice, but share_cpu_list can be
+ * used if it is not available. */
+ entry = g_strconcat(index, "id", NULL);
+ uref = h_sysfs_read_string(endpoint, entry);
+ g_free(entry);
+ if (uref != NULL && *uref != 0 )
+ cache->uid = atoi(uref);
+ else
+ cache->uid = -1;
+ g_free(uref);
+ entry = g_strconcat(index, "shared_cpu_list", NULL);
+ cache->shared_cpu_list = h_sysfs_read_string(endpoint, entry);
+ g_free(entry);
+
+ /* reacharound */
+ entry = g_strconcat(index, "../../topology/physical_package_id", NULL);
+ cache->phy_sock = h_sysfs_read_int(endpoint, entry);
+ g_free(entry);
+
+ g_free(index);
+
+ processor->cache = g_slist_append(processor->cache, cache);
+ }
+
+fail:
+ g_free(endpoint);
+}
+
+#define cmp_cache_test(f) if (a->f < b->f) return -1; if (a->f > b->f) return 1;
+
+static gint cmp_cache(ProcessorCache *a, ProcessorCache *b) {
+ gint i = 0;
+ cmp_cache_test(phy_sock);
+ i = g_strcmp0(a->type, b->type); if (i!=0) return i;
+ cmp_cache_test(level);
+ cmp_cache_test(size);
+ cmp_cache_test(uid); /* uid is unique among caches with the same (type, level) */
+ if (a->uid == -1) {
+ /* if id wasn't available, use shared_cpu_list as a unique ref */
+ i = g_strcmp0(a->shared_cpu_list, b->shared_cpu_list); if (i!=0)
+ return i;
+ }
+ return 0;
+}
+
+static gint cmp_cache_ignore_id(ProcessorCache *a, ProcessorCache *b) {
+ gint i = 0;
+ cmp_cache_test(phy_sock);
+ i = g_strcmp0(a->type, b->type); if (i!=0) return i;
+ cmp_cache_test(level);
+ cmp_cache_test(size);
+ return 0;
+}
+
+gchar *caches_summary(GSList * processors)
+{
+ gchar *ret = g_strdup_printf("[%s]\n", _("Caches"));
+ GSList *all_cache = NULL, *uniq_cache = NULL;
+ GSList *tmp, *l;
+ Processor *p;
+ ProcessorCache *c, *cur = NULL;
+ gint cur_count = 0, i = 0;
+
+ /* create list of all cache references */
+ for (l = processors; l; l = l->next) {
+ p = (Processor*)l->data;
+ if (p->cache) {
+ tmp = g_slist_copy(p->cache);
+ if (all_cache) {
+ all_cache = g_slist_concat(all_cache, tmp);
+ } else {
+ all_cache = tmp;
+ }
+ }
+ }
+
+ if (g_slist_length(all_cache) == 0) {
+ ret = h_strdup_cprintf("%s=\n", ret, _("(Not Available)") );
+ g_slist_free(all_cache);
+ return ret;
+ }
+
+ /* ignore duplicate references */
+ all_cache = g_slist_sort(all_cache, (GCompareFunc)cmp_cache);
+ for (l = all_cache; l; l = l->next) {
+ c = (ProcessorCache*)l->data;
+ if (!cur) {
+ cur = c;
+ } else {
+ if (cmp_cache(cur, c) != 0) {
+ uniq_cache = g_slist_prepend(uniq_cache, cur);
+ cur = c;
+ }
+ }
+ }
+ uniq_cache = g_slist_prepend(uniq_cache, cur);
+ uniq_cache = g_slist_reverse(uniq_cache);
+ cur = 0, cur_count = 0;
+
+ /* count and list caches */
+ for (l = uniq_cache; l; l = l->next) {
+ c = (ProcessorCache*)l->data;
+ if (!cur) {
+ cur = c;
+ cur_count = 1;
+ } else {
+ if (cmp_cache_ignore_id(cur, c) != 0) {
+ ret = h_strdup_cprintf(_("Level %d (%s)#%d=%dx %dKB (%dKB), %d-way set-associative, %d sets\n"),
+ ret,
+ cur->level,
+ C_("cache-type", cur->type),
+ cur->phy_sock,
+ cur_count,
+ cur->size,
+ cur->size * cur_count,
+ cur->ways_of_associativity,
+ cur->number_of_sets);
+ cur = c;
+ cur_count = 1;
+ } else {
+ cur_count++;
+ }
+ }
+ }
+ ret = h_strdup_cprintf(_("Level %d (%s)#%d=%dx %dKB (%dKB), %d-way set-associative, %d sets\n"),
+ ret,
+ cur->level,
+ C_("cache-type", cur->type),
+ cur->phy_sock,
+ cur_count,
+ cur->size,
+ cur->size * cur_count,
+ cur->ways_of_associativity,
+ cur->number_of_sets);
+
+ g_slist_free(all_cache);
+ g_slist_free(uniq_cache);
+ return ret;
+}
+
+static gchar *processor_get_full_name(const gchar *model_name)
+{
+ if(g_strcmp0(model_name ,"E2S") == 0)
+ return "Elbrus-4C";
+ else if(g_strcmp0(model_name ,"E1C+") == 0)
+ return "Elbrus-1C+";
+ else if(g_strcmp0(model_name ,"E2C+DSP") == 0)
+ return "Elbrus-2C+";
+ else if(g_strcmp0(model_name ,"E8C") == 0)
+ return "Elbrus-8C";
+ else if(g_strcmp0(model_name ,"E8C2") == 0)
+ return "Elbrus-8CB";
+ else if(g_strcmp0(model_name ,"E12C") == 0)
+ return "Elbrus-12C";
+ else if(g_strcmp0(model_name ,"E16C") == 0)
+ return "Elbrus-16C";
+ else if(g_strcmp0(model_name ,"E2C3") == 0)
+ return "Elbrus-2C3";
+ else
+ return (gchar *)model_name;
+}
+
+GSList *processor_scan(void)
+{
+ GSList *procs = NULL, *l = NULL;
+ Processor *processor = NULL;
+ FILE *cpuinfo;
+ gchar buffer[1024];
+
+ cpuinfo = fopen(PROC_CPUINFO, "r");
+ if (!cpuinfo)
+ return NULL;
+
+ while (fgets(buffer, 1024, cpuinfo)) {
+ gchar **tmp = g_strsplit(buffer, ":", 2);
+ if (!tmp[1] || !tmp[0]) {
+ g_strfreev(tmp);
+ continue;
+ }
+
+ tmp[0] = g_strstrip(tmp[0]);
+ tmp[1] = g_strstrip(tmp[1]);
+
+ if (g_str_has_prefix(tmp[0], "processor")) {
+ /* finish previous */
+ if (processor)
+ procs = g_slist_append(procs, processor);
+
+ /* start next */
+ processor = g_new0(Processor, 1);
+ processor->id = atol(tmp[1]);
+ g_strfreev(tmp);
+ continue;
+ }
+
+ if (processor) {
+ if (g_str_has_prefix(tmp[0], "model name")) {
+ const gchar *model_name = processor_get_full_name(tmp[1]);
+ processor->model_name = g_strdup(model_name);
+ g_strfreev(tmp);
+ continue;
+ }
+
+ get_str("vendor_id", processor->vendor_id);
+ get_int("cpu family", processor->family);
+ get_int("model", processor->model);
+ get_int("revision", processor->revision);
+
+ get_float("cpu MHz", processor->cpu_mhz);
+ get_float("bogomips", processor->bogomips);
+ }
+
+ //populate processor structure
+ g_strfreev(tmp);
+ }
+
+ //appent to the list
+ if (processor)
+ procs = g_slist_append(procs, processor);
+
+ for (l = procs; l; l = l->next) {
+ processor = (Processor *) l->data;
+ __cache_obtain_info(processor);
+ }
+
+ fclose(cpuinfo);
+
+ 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_detailed_info(Processor *processor)
+{
+ gchar *ret;
+ gchar *cache_info;
+ cache_info = __cache_get_info_as_string(processor);
+
+ ret = g_strdup_printf("[%s]\n"
+ "$^$%s=%s\n" /* name */
+ "$^$%s=%s\n" /* vendor */
+ "%s=%d\n" /* family */
+ "%s=%d\n" /* model */
+ "%s=%d\n" /* revision */
+ "%s=%.2f %s\n" /* frequency */
+ "%s=%.2f\n" /* bogomips */
+ "%s=%s\n" /* byte order */
+ "[%s]\n" /* cache */
+ "%s\n",
+ _("Processor"),
+ _("Name"), processor->model_name,
+ _("Vendor"), processor->vendor_id,
+ _("Family"), processor->family,
+ _("Model"), processor->model,
+ _("Revision"), processor->revision,
+ _("Frequency"), processor->cpu_mhz, _("MHz"),
+ _("BogoMips"), processor->bogomips,
+ _("Byte Order"), byte_order_str(),
+ _("Cache"), cache_info
+ );
+ g_free(cache_info);
+ return ret;
+}
+
+//prepare processor info for all cpus
+gchar *processor_get_info(GSList * processors)
+{
+ Processor *processor;
+
+ gchar *ret, *tmp, *hashkey;
+ GSList *l;
+
+ tmp = g_strdup("");
+
+ for (l = processors; l; l = l->next) {
+ processor = (Processor *) l->data;
+ gchar *model_name = g_strdup_printf("MCST %s", processor->model_name);
+
+ /* change vendor id of 8CB processor for correct parse from vendor.ids */
+ if (!g_strcmp0(processor->vendor_id, "E8C")) {
+ gchar *orig_vendor_id = processor->vendor_id;
+ processor->vendor_id = g_strdup_printf("%s-SWTX", orig_vendor_id);
+ free(orig_vendor_id);
+ }
+
+ const Vendor *v = vendor_match(processor->vendor_id, NULL);
+ if (v)
+ tag_vendor(&model_name, 0, v->name_short ? v->name_short : v->name, v->ansi_color, params.fmt_opts);
+
+ tmp = g_strdup_printf("%s$CPU%d$cpu%d=%.2f %s|%s\n",
+ tmp, processor->id,
+ processor->id,
+ processor->cpu_mhz, _("MHz"),
+ model_name);
+
+ 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"
+ "ColumnTitle$TextValue=%s\n"
+ "ColumnTitle$Value=%s\n"
+ "ColumnTitle$Extra1=%s\n"
+ "ShowColumnHeaders=true\n"
+ "[Processors]\n"
+ "%s", _("Device"), _("Frequency"), _("Model"), tmp);
+ g_free(tmp);
+
+ return ret;
+}
diff --git a/modules/devices/firmware.c b/modules/devices/firmware.c
new file mode 100644
index 00000000..ea6ce532
--- /dev/null
+++ b/modules/devices/firmware.c
@@ -0,0 +1,261 @@
+/*
+ * HardInfo - Displays System Information
+ * Copyright (C) 2003-2019 L. A. F. Pereira <l@tia.mat.br>
+ * Copyright (C) 2019 Burt P. <pburt0@gmail.com>
+ * Copyright (C) 2020 Ondrej ÄŒerman
+ *
+ * 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 or later.
+ *
+ * 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 "hardinfo.h"
+#include "devices.h"
+#include <inttypes.h>
+#include <gio/gio.h>
+#include "util_sysobj.h" /* for SEQ() and appf() */
+
+#define fw_msg(msg, ...) fprintf (stderr, "[%s] " msg "\n", __FUNCTION__, ##__VA_ARGS__) /**/
+
+#define FWUPT_INTERFACE "org.freedesktop.fwupd"
+
+gboolean fail_no_fwupd = TRUE;
+
+char *decode_flags(guint64 flags) {
+ /* https://github.com/hughsie/fwupd/blob/master/libfwupd/fwupd-enums.{h,c} */
+ static const struct { guint64 b; char *flag, *def; } flag_defs[] = {
+ { (1u << 0), "internal", N_("Device cannot be removed easily") },
+ { (1u << 1), "updatable", N_("Device is updatable in this or any other mode") },
+ { (1u << 2), "only-offline", N_("Update can only be done from offline mode") },
+ { (1u << 3), "require-ac", N_("Requires AC power") },
+ { (1u << 4), "locked", N_("Is locked and can be unlocked") },
+ { (1u << 5), "supported", N_("Is found in current metadata") },
+ { (1u << 6), "needs-bootloader", N_("Requires a bootloader mode to be manually enabled by the user") },
+ { (1u << 7), "registered", N_("Has been registered with other plugins") },
+ { (1u << 8), "needs-reboot", N_("Requires a reboot to apply firmware or to reload hardware") },
+ { (1u << 17), "needs-shutdown", N_("Requires system shutdown to apply firmware") },
+ { (1u << 9), "reported", N_("Has been reported to a metadata server") },
+ { (1u << 10), "notified", N_("User has been notified") },
+ { (1u << 11), "use-runtime-version", N_("Always use the runtime version rather than the bootloader") },
+ { (1u << 12), "install-parent-first", N_("Install composite firmware on the parent before the child") },
+ { (1u << 13), "is-bootloader", N_("Is currently in bootloader mode") },
+ { (1u << 14), "wait-for-replug", N_("The hardware is waiting to be replugged") },
+ { (1u << 15), "ignore-validation", N_("Ignore validation safety checks when flashing this device") },
+ { (1u << 18), "another-write-required", N_("Requires the update to be retried with a new plugin") },
+ { (1u << 19), "no-auto-instance-ids", N_("Do not add instance IDs from the device baseclass") },
+ { (1u << 20), "needs-activation", N_("Device update needs to be separately activated") },
+ { (1u << 21), "ensure-semver", N_("Ensure the version is a valid semantic version, e.g. numbers separated with dots") },
+ { (1u << 16), "trusted", N_("Extra metadata can be exposed about this device") },
+ { 0, NULL }
+ };
+
+ gchar *flag_list = g_strdup("");
+
+ int i;
+ for (i = 0; flag_defs[i].flag; i++) {
+ if (flags & flag_defs[i].b)
+ flag_list = appfnl(flag_list, "[%s] %s", flag_defs[i].flag, flag_defs[i].def);
+ }
+ return flag_list;
+}
+
+const char *find_translation(const char *str) {
+ /* TODO: https://github.com/hughsie/fwupd/blob/master/src/README.md */
+ static const char *translatable[] = {
+ N_("DeviceId"), N_("Guid"), N_("Summary"), N_("Plugin"), N_("Flags"),
+ N_("Vendor"), N_("VendorId"), N_("Version"), N_("VersionBootloader"),
+ N_("Icon"), N_("InstallDuration"), N_("Created"),
+ NULL
+ };
+ int i;
+ if (!str) return NULL;
+ for (i = 0; translatable[i]; i++) {
+ if (SEQ(str, translatable[i]))
+ return _(translatable[i]);
+ }
+ return str;
+};
+
+/* map lvfs icon names to hardinfo icon names */
+const char *find_icon(const char *lvfs_name) {
+ /* icon names found by looking for fu_device_add_icon ()
+ * in the fwupd source. */
+ static const
+ struct { char *lvfs, *hi; } imap[] = {
+ { "applications-internet", "dns.png" },
+ { "audio-card", "audio.png" },
+ { "computer", "computer.png" },
+ { "drive-harddisk", "hdd.png" },
+ { "input-gaming", "joystick.png" },
+ { "input-tablet", NULL },
+ { "network-modem", "wireless.png" },
+ { "preferences-desktop-keyboard", "keyboard.png" },
+ { "thunderbolt", NULL },
+ { "touchpad-disabled", NULL },
+ /* default */
+ { NULL, "memory.png" } /* a device with firmware maybe */
+ };
+ unsigned int i = 0;
+ for(; imap[i].lvfs; i++) {
+ if (SEQ(imap[i].lvfs, lvfs_name) && imap[i].hi)
+ return imap[i].hi;
+ }
+ return imap[i].hi;
+}
+
+gchar *fwupdmgr_get_devices_info() {
+ struct Info *info = info_new();
+ struct InfoGroup *this_group = NULL;
+ gboolean has_vendor_field = FALSE;
+ gboolean updatable = FALSE;
+ const Vendor *gv = NULL;
+ int gc = 0;
+
+ GDBusConnection *conn;
+ GDBusProxy *proxy;
+ GVariant *devices, *value;
+ GVariantIter *deviter, *dictiter, *iter;
+ const gchar *key, *tmpstr;
+
+ conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, NULL);
+ if (!conn)
+ return g_strdup("");
+
+ proxy = g_dbus_proxy_new_sync(conn, G_DBUS_PROXY_FLAGS_NONE, NULL,
+ FWUPT_INTERFACE, "/", FWUPT_INTERFACE,
+ NULL, NULL);
+ if (!proxy) {
+ g_object_unref(conn);
+ return g_strdup("");
+ }
+
+ fail_no_fwupd = FALSE;
+ devices = g_dbus_proxy_call_sync(proxy, "GetDevices", NULL,
+ G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL);
+
+ if (devices) {
+ g_variant_get(devices, "(aa{sv})", &deviter);
+ while(g_variant_iter_loop(deviter, "a{sv}", &dictiter)){
+
+ this_group = info_add_group(info, _("Unknown"), info_field_last());
+ this_group->sort = INFO_GROUP_SORT_NAME_DESCENDING;
+ has_vendor_field = FALSE;
+ updatable = FALSE;
+ gv = NULL;
+
+ while (g_variant_iter_loop(dictiter, "{&sv}", &key, &value)) {
+ if (SEQ(key, "Name")) {
+ tmpstr = g_variant_get_string(value, NULL);
+ this_group->name = hardinfo_clean_grpname(tmpstr, 0);
+ gv = vendor_match(tmpstr, NULL);
+ } else if (SEQ(key, "Vendor")) {
+ has_vendor_field = TRUE;
+ tmpstr = g_variant_get_string(value, NULL);
+
+ const Vendor* v = vendor_match(tmpstr, NULL);
+ if (v) {
+ info_group_add_field(this_group,
+ info_field(_("Vendor"), v->name,
+ .value_has_vendor = TRUE,
+ .free_value_on_flatten = FALSE) );
+ } else {
+ info_group_add_field(this_group,
+ info_field(_("Vendor"), g_strdup(tmpstr),
+ .free_value_on_flatten = TRUE) );
+ }
+ } else if (SEQ(key, "Icon")) {
+ g_variant_get(value, "as", &iter);
+ while (g_variant_iter_loop(iter, "s", &tmpstr)) {
+ info_group_add_field(this_group,
+ info_field(_("Icon"), g_strdup(tmpstr),
+ .free_value_on_flatten = TRUE,
+ .icon = g_strdup(find_icon(tmpstr)) ) );
+ }
+ } else if (SEQ(key, "Guid")) {
+ g_variant_get(value, "as", &iter);
+ while (g_variant_iter_loop(iter, "s", &tmpstr)) {
+ info_group_add_field(this_group,
+ info_field(_("Guid"), g_strdup(tmpstr),
+ .tag = g_strdup_printf("guid%d", gc++),
+ .free_value_on_flatten = TRUE) );
+ }
+ g_variant_iter_free(iter);
+ } else if (SEQ(key, "Created")) {
+ guint64 created = g_variant_get_uint64(value);
+ GDateTime *dt = g_date_time_new_from_unix_local(created);
+ if (dt) {
+ info_group_add_field(this_group,
+ info_field(_("Created"), g_date_time_format(dt, "%x"),
+ .free_value_on_flatten = TRUE) );
+ g_date_time_unref(dt);
+ }
+ } else if (SEQ(key, "Flags")) {
+ guint64 flags = g_variant_get_uint64(value);
+ updatable = (gboolean)(flags & (1u << 1));
+ info_group_add_field(this_group,
+ info_field(_("Flags"), decode_flags(flags),
+ .free_value_on_flatten = TRUE) );
+ } else {
+ if (g_variant_is_of_type(value, G_VARIANT_TYPE_STRING)) {
+ info_group_add_field(this_group,
+ info_field(find_translation(key),
+ g_variant_dup_string(value, NULL),
+ .free_value_on_flatten = TRUE) );
+ }
+ }
+ }
+
+ if (gv && !has_vendor_field) {
+ info_group_add_field(this_group,
+ info_field(_("Vendor"), gv->name,
+ .value_has_vendor = TRUE,
+ .free_value_on_flatten = FALSE) );
+ }
+
+ // hide devices that are not updatable
+ if (!updatable) {
+ info_remove_group(info, info->groups->len - 1);
+ }
+ }
+ g_variant_iter_free(deviter);
+ g_variant_unref(devices);
+ }
+
+ g_object_unref(proxy);
+ g_object_unref(conn);
+
+ gchar *ret = NULL;
+ if (info->groups->len) {
+ info_set_view_type(info, SHELL_VIEW_DETAIL);
+ //fw_msg("flatten...");
+ ret = info_flatten(info);
+ //fw_msg("ret: %s", ret);
+ } else {
+ ret = g_strdup_printf("[%s]\n%s=%s\n" "[$ShellParam$]\nViewType=0\n",
+ _("Firmware List"),
+ _("Result"), _("(Not available)") );
+ }
+ return ret;
+}
+
+gchar *firmware_get_info() {
+ return fwupdmgr_get_devices_info();
+}
+
+gboolean firmware_hinote(const char **msg) {
+ if (fail_no_fwupd) {
+ *msg = g_strdup(
+ _("Requires the <i><b>fwupd</b></i> daemon."));
+ return TRUE;
+ }
+ return FALSE;
+}
diff --git a/modules/devices/gpu.c b/modules/devices/gpu.c
new file mode 100644
index 00000000..96520161
--- /dev/null
+++ b/modules/devices/gpu.c
@@ -0,0 +1,291 @@
+/*
+ * HardInfo - Displays System Information
+ * Copyright (C) 2003-2017 L. A. F. Pereira <l@tia.mat.br>
+ * This file
+ * Copyright (C) 2018 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 or later.
+ *
+ * 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 "devices.h"
+#include "gpu_util.h"
+
+gchar *gpu_list = NULL;
+gchar *gpu_summary = NULL;
+
+void gpu_summary_add(const char *gpu_name) {
+ if (strlen(gpu_summary) == 0) {
+ /* first one */
+ gpu_summary = h_strdup_cprintf("%s", gpu_summary, gpu_name);
+ } else {
+ /* additional */
+ gpu_summary = h_strdup_cprintf(" + %s", gpu_summary, gpu_name);
+ }
+}
+
+#define UNKIFNULL_AC(f) (f != NULL) ? f : _("(Unknown)");
+
+static void _gpu_pci_dev(gpud* gpu) {
+ pcid *p = gpu->pci_dev;
+ gchar *str;
+ gchar *vendor, *svendor, *product, *sproduct;
+ gchar *name, *key;
+ gchar *drm_path = NULL;
+
+ gboolean vendor_is_svendor = (p->vendor_id == p->sub_vendor_id && p->device_id == p->sub_device_id);
+
+ vendor = UNKIFNULL_AC(p->vendor_id_str);
+ svendor = UNKIFNULL_AC(p->sub_vendor_id_str);
+ product = UNKIFNULL_AC(p->device_id_str);
+ sproduct = UNKIFNULL_AC(p->sub_device_id_str);
+ if (gpu->drm_dev)
+ drm_path = g_strdup_printf("/dev/dri/%s", gpu->drm_dev);
+ else
+ drm_path = g_strdup(_("(Unknown)"));
+
+ gchar *ven_tag = vendor_match_tag(p->vendor_id_str, params.fmt_opts);
+ gchar *sven_tag = vendor_match_tag(p->sub_vendor_id_str, params.fmt_opts);
+ if (ven_tag) {
+ if (sven_tag && !vendor_is_svendor) {
+ name = g_strdup_printf("%s %s %s", sven_tag, ven_tag, product);
+ } else {
+ name = g_strdup_printf("%s %s", ven_tag, product);
+ }
+ } else {
+ name = g_strdup_printf("%s %s", vendor, product);
+ }
+ g_free(ven_tag);
+ g_free(sven_tag);
+
+ key = g_strdup_printf("GPU%s", gpu->id);
+
+ gpu_summary_add((gpu->nice_name) ? gpu->nice_name : name);
+ gpu_list = h_strdup_cprintf("$!%s$%s=%s\n", gpu_list, key, gpu->id, name);
+
+ gchar *vendor_device_str;
+ if (p->vendor_id == p->sub_vendor_id && p->device_id == p->sub_device_id) {
+ vendor_device_str = g_strdup_printf(
+ /* Vendor */ "$^$%s=[%04x] %s\n"
+ /* Device */ "%s=[%04x] %s\n",
+ _("Vendor"), p->vendor_id, vendor,
+ _("Device"), p->device_id, product);
+ } else {
+ vendor_device_str = g_strdup_printf(
+ /* Vendor */ "$^$%s=[%04x] %s\n"
+ /* Device */ "%s=[%04x] %s\n"
+ /* Sub-device vendor */ "$^$%s=[%04x] %s\n"
+ /* Sub-device */ "%s=[%04x] %s\n",
+ _("Vendor"), p->vendor_id, vendor,
+ _("Device"), p->device_id, product,
+ _("SVendor"), p->sub_vendor_id, svendor,
+ _("SDevice"), p->sub_device_id, sproduct);
+ }
+
+ gchar *pcie_str;
+ if (p->pcie_width_curr) {
+ pcie_str = g_strdup_printf("[%s]\n"
+ /* Width (max) */ "%s=x%u\n"
+ /* Speed (max) */ "%s=%0.1f %s\n",
+ _("PCI Express"),
+ _("Maximum Link Width"), p->pcie_width_max,
+ _("Maximum Link Speed"), p->pcie_speed_max, _("GT/s") );
+ } else
+ pcie_str = strdup("");
+
+ gchar *nv_str;
+ if (gpu->nv_info) {
+ nv_str = g_strdup_printf("[%s]\n"
+ /* model */ "%s=%s\n"
+ /* bios */ "%s=%s\n"
+ /* uuid */ "%s=%s\n",
+ _("NVIDIA"),
+ _("Model"), gpu->nv_info->model,
+ _("BIOS Version"), gpu->nv_info->bios_version,
+ _("UUID"), gpu->nv_info->uuid );
+ } else
+ nv_str = strdup("");
+
+ gchar *freq = g_strdup(_("(Unknown)"));
+ if (gpu->khz_max > 0) {
+ if (gpu->khz_min > 0 && gpu->khz_min != gpu->khz_max)
+ freq = g_strdup_printf("%0.2f-%0.2f %s", (double) gpu->khz_min / 1000, (double) gpu->khz_max / 1000, _("MHz"));
+ else
+ freq = g_strdup_printf("%0.2f %s", (double) gpu->khz_max / 1000, _("MHz"));
+ }
+
+ gchar *mem_freq = g_strdup(_("(Unknown)"));
+ if (gpu->mem_khz_max > 0) {
+ if (gpu->mem_khz_min > 0 && gpu->mem_khz_min != gpu->mem_khz_max)
+ mem_freq = g_strdup_printf("%0.2f-%0.2f %s", (double) gpu->mem_khz_min / 1000, (double) gpu->mem_khz_max / 1000, _("MHz"));
+ else
+ mem_freq = g_strdup_printf("%0.2f %s", (double) gpu->mem_khz_max / 1000, _("MHz"));
+ }
+
+ str = g_strdup_printf("[%s]\n"
+ /* Location */ "%s=%s\n"
+ /* DRM Dev */ "%s=%s\n"
+ /* Class */ "%s=[%04x] %s\n"
+ "%s"
+ /* Revision */ "%s=%02x\n"
+ "[%s]\n"
+ /* Core freq */ "%s=%s\n"
+ /* Mem freq */ "%s=%s\n"
+ /* NV */ "%s"
+ /* PCIe */ "%s"
+ "[%s]\n"
+ /* Driver */ "%s=%s\n"
+ /* Modules */ "%s=%s\n",
+ _("Device Information"),
+ _("Location"), gpu->location,
+ _("DRM Device"), drm_path,
+ _("Class"), p->class, p->class_str,
+ vendor_device_str,
+ _("Revision"), p->revision,
+ _("Clocks"),
+ _("Core"), freq,
+ _("Memory"), mem_freq,
+ nv_str,
+ pcie_str,
+ _("Driver"),
+ _("In Use"), (p->driver) ? p->driver : _("(Unknown)"),
+ _("Kernel Modules"), (p->driver_list) ? p->driver_list : _("(Unknown)")
+ );
+
+ moreinfo_add_with_prefix("DEV", key, str); /* str now owned by morinfo */
+
+ g_free(drm_path);
+ g_free(pcie_str);
+ g_free(nv_str);
+ g_free(vendor_device_str);
+ g_free(name);
+ g_free(key);
+}
+
+int _dt_soc_gpu(gpud *gpu) {
+ static char UNKSOC[] = "(Unknown)"; /* don't translate this */
+ gchar *vendor = gpu->vendor_str;
+ gchar *device = gpu->device_str;
+ if (vendor == NULL) vendor = UNKSOC;
+ if (device == NULL) device = UNKSOC;
+ gchar *freq = g_strdup(_("(Unknown)"));
+ if (gpu->khz_max > 0) {
+ if (gpu->khz_min > 0)
+ freq = g_strdup_printf("%0.2f-%0.2f %s", (double) gpu->khz_min / 1000, (double) gpu->khz_max / 1000, _("MHz"));
+ else
+ freq = g_strdup_printf("%0.2f %s", (double) gpu->khz_max / 1000, _("MHz"));
+ }
+ gchar *key = g_strdup(gpu->id);
+
+ gchar *name = NULL;
+ gchar *vtag = vendor_match_tag(gpu->vendor_str, params.fmt_opts);
+ if (vtag) {
+ name = g_strdup_printf("%s %s", vtag, device);
+ } else {
+ name = (vendor == UNKSOC && device == UNKSOC)
+ ? g_strdup(_("Unknown integrated GPU"))
+ : g_strdup_printf("%s %s", vendor, device);
+ }
+ g_free(vtag);
+
+ gchar *opp_str;
+ if (gpu->dt_opp) {
+ static const char *freq_src[] = {
+ N_("clock-frequency property"),
+ N_("Operating Points (OPPv1)"),
+ N_("Operating Points (OPPv2)"),
+ };
+ opp_str = g_strdup_printf("[%s]\n"
+ /* MinFreq */ "%s=%d %s\n"
+ /* MaxFreq */ "%s=%d %s\n"
+ /* Latency */ "%s=%d %s\n"
+ /* Source */ "%s=%s\n",
+ _("Frequency Scaling"),
+ _("Minimum"), gpu->dt_opp->khz_min, _("kHz"),
+ _("Maximum"), gpu->dt_opp->khz_max, _("kHz"),
+ _("Transition Latency"), gpu->dt_opp->clock_latency_ns, _("ns"),
+ _("Source"), _(freq_src[gpu->dt_opp->version]) );
+ } else
+ opp_str = strdup("");
+
+ gpu_summary_add((gpu->nice_name) ? gpu->nice_name : name);
+ gpu_list = h_strdup_cprintf("$!%s$%s=%s\n", gpu_list, key, key, name);
+ gchar *str = g_strdup_printf("[%s]\n"
+ /* Location */ "%s=%s\n"
+ /* Vendor */ "$^$%s=%s\n"
+ /* Device */ "%s=%s\n"
+ "[%s]\n"
+ /* Freq */ "%s=%s\n"
+ /* opp-v2 */ "%s"
+ "[%s]\n"
+ /* Path */ "%s=%s\n"
+ /* Compat */ "%s=%s\n"
+ /* Status */ "%s=%s\n"
+ /* Name */ "%s=%s\n",
+ _("Device Information"),
+ _("Location"), gpu->location,
+ _("Vendor"), vendor,
+ _("Device"), device,
+ _("Clocks"),
+ _("Core"), freq,
+ opp_str,
+ _("Device Tree Node"),
+ _("Path"), gpu->dt_path,
+ _("Compatible"), gpu->dt_compat,
+ _("Status"), gpu->dt_status,
+ _("Name"), gpu->dt_name
+ );
+ moreinfo_add_with_prefix("DEV", key, str); /* str now owned by morinfo */
+ g_free(freq);
+ g_free(opp_str);
+ return 1;
+}
+
+void scan_gpu_do(void) {
+ if (gpu_summary)
+ g_free(gpu_summary);
+ if (gpu_list) {
+ moreinfo_del_with_prefix("DEV:GPU");
+ g_free(gpu_list);
+ }
+ gpu_summary = strdup("");
+ gpu_list = g_strdup_printf("[%s]\n", _("GPUs"));
+
+ gpud *gpus = gpu_get_device_list();
+ gpud *curr = gpus;
+
+ int c = gpud_list_count(gpus);
+
+ if (c > 0) {
+ while(curr) {
+ if (curr->pci_dev) {
+ _gpu_pci_dev(curr);
+ }
+ if (curr->dt_compat) {
+ _dt_soc_gpu(curr);
+ }
+ curr=curr->next;
+ }
+ }
+ gpud_list_free(gpus);
+
+ if (c)
+ gpu_list = g_strconcat(gpu_list, "[$ShellParam$]\n", "ViewType=1\n", NULL);
+ else {
+ /* NO GPU? */
+ gpu_list = g_strconcat(gpu_list, _("No GPU devices found"), "=\n", NULL);
+ }
+}
diff --git a/modules/devices/ia64/processor.c b/modules/devices/ia64/processor.c
index c4d06a71..f31813bc 100644
--- a/modules/devices/ia64/processor.c
+++ b/modules/devices/ia64/processor.c
@@ -1,10 +1,10 @@
/*
* HardInfo - Displays System Information
- * Copyright (C) 2003-2006 Leandro A. F. Pereira <leandro@hardinfo.org>
+ * Copyright (C) 2003-2006 L. A. F. Pereira <l@tia.mat.br>
*
* 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.
+ * the Free Software Foundation, version 2 or later.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/modules/devices/inputdevices.c b/modules/devices/inputdevices.c
index cf1728a9..301641d4 100644
--- a/modules/devices/inputdevices.c
+++ b/modules/devices/inputdevices.c
@@ -1,10 +1,10 @@
/*
* HardInfo - Displays System Information
- * Copyright (C) 2003-2006 Leandro A. F. Pereira <leandro@hardinfo.org>
+ * Copyright (C) 2003-2006 L. A. F. Pereira <l@tia.mat.br>
*
* 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.
+ * the Free Software Foundation, version 2 or later.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -20,6 +20,7 @@
#include "hardinfo.h"
#include "devices.h"
+#include "usb_util.h"
gchar *input_icons = NULL;
@@ -27,113 +28,143 @@ static struct {
char *name;
char *icon;
} input_devices[] = {
+ { NULL, "module.png" }, // UNKNOWN
{ "Keyboard", "keyboard.png" },
{ "Joystick", "joystick.png" },
{ "Mouse", "mouse.png" },
- { "Speaker", "audio.png" },
- { "Unknown", "module.png" },
+ { "Speaker", "audio.png" },
+ { "Audio", "audio.png" }
};
+// source: https://elixir.bootlin.com/linux/v5.9/source/include/uapi/linux/input.h#L251
+static const gchar *bus_types[] = {
+ NULL, "PCI", "ISA PnP", "USB", // 0x0 - 0x3
+ "HIL", "Bluetooth", "Virtual", NULL, // 0x4 - 0x7
+ NULL, NULL, NULL, NULL, // 0x8 - 0xB
+ NULL, NULL, NULL, NULL, // 0xC - 0xF
+ "ISA", "i8042", "XT Keyboard bus", "RS232", // 0x10 - 0x13
+ "Game port", "Parallel port", "Amiga bus", "ADB", // 0x14 - 0x17
+ "I²C", "HOST", "GSC", "Atari bus", // 0x18 - 0x1B
+ "SPI", "RMI", "CEC", "Intel ISHTP" // 0x1C - 0x1F
+};
+
+#define UNKWNIFNULL(f) ((f) ? f : _("(Unknown)"))
+#define EMPTYIFNULL(f) ((f) ? f : "")
+
void
__scan_input_devices(void)
{
FILE *dev;
gchar buffer[1024];
+ vendor_list vl = NULL;
gchar *tmp, *name = NULL, *phys = NULL;
+ gchar *vendor_str = NULL, *product_str = NULL, *vendor_tags = NULL;
gint bus = 0, vendor = 0, product = 0, version = 0;
+ const gchar *bus_str = NULL;
int d = 0, n = 0;
dev = fopen("/proc/bus/input/devices", "r");
if (!dev)
- return;
+ return;
if (input_list) {
moreinfo_del_with_prefix("DEV:INP");
- g_free(input_list);
- g_free(input_icons);
+ g_free(input_list);
+ g_free(input_icons);
}
input_list = g_strdup("");
input_icons = g_strdup("");
while (fgets(buffer, sizeof(buffer), dev)) {
- tmp = buffer;
-
- switch (*tmp) {
- case 'N':
- tmp = strreplacechr(tmp + strlen("N: Name="), "=", ':');
- name = g_strdup(tmp);
- remove_quotes(name);
- break;
- case 'P':
- phys = g_strdup(tmp + strlen("P: Phys="));
- break;
- case 'I':
- sscanf(tmp, "I: Bus=%x Vendor=%x Product=%x Version=%x",
- &bus, &vendor, &product, &version);
- break;
- case 'H':
- if (strstr(tmp, "kbd"))
- d = 0; //INPUT_KEYBOARD;
- else if (strstr(tmp, "js"))
- d = 1; //INPUT_JOYSTICK;
- else if (strstr(tmp, "mouse"))
- d = 2; //INPUT_MOUSE;
- else
- d = 4; //INPUT_UNKNOWN;
- break;
- case '\n':
- 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);
-
- 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 );
-
- if (phys && phys[1] != 0) {
- strhash = h_strdup_cprintf("%s=%s\n", strhash, _("Connected to"), phys);
+ tmp = buffer;
+
+ switch (*tmp) {
+ case 'N':
+ tmp = strreplacechr(tmp + strlen("N: Name="), "=", ':');
+ name = g_strdup(tmp);
+ remove_quotes(name);
+ break;
+ case 'P':
+ phys = g_strdup(tmp + strlen("P: Phys="));
+ break;
+ case 'I':
+ sscanf(tmp, "I: Bus=%x Vendor=%x Product=%x Version=%x",
+ &bus, &vendor, &product, &version);
+ break;
+ case 'H':
+ if (strstr(tmp, "kbd"))
+ d = 1; //INPUT_KEYBOARD;
+ else if (strstr(tmp, "js"))
+ d = 2; //INPUT_JOYSTICK;
+ else if (strstr(tmp, "mouse"))
+ d = 3; //INPUT_MOUSE;
+ else
+ d = 0; //INPUT_UNKNOWN;
+ break;
+ case '\n':
+ if (name && strstr(name, "PC Speaker")) {
+ d = 4; // INPUT_PCSPKR
+ }
+ if (d == 0 && g_strcmp0(phys, "ALSA")) {
+ d = 5; // INPUT_AUDIO
+ }
+
+ if (vendor > 0 && product > 0 && g_str_has_prefix(phys, "usb-")) {
+ usb_lookup_ids_vendor_product_str(vendor, product, &vendor_str, &product_str);
+ }
+
+ if (bus >= 0 && (guint)bus < sizeof(bus_types) / sizeof(gchar*)) {
+ bus_str = bus_types[bus];
+ }
+
+ vl = vendor_list_remove_duplicates_deep(vendors_match(name, vendor_str, NULL));
+ vendor_tags = vendor_list_ribbon(vl, params.fmt_opts);
+
+ tmp = g_strdup_printf("INP%d", ++n);
+ input_list = h_strdup_cprintf("$%s$%s=%s|%s\n",
+ input_list,
+ tmp, name, EMPTYIFNULL(vendor_tags),
+ EMPTYIFNULL(input_devices[d].name));
+ input_icons = h_strdup_cprintf("Icon$%s$%s=%s\n",
+ input_icons,
+ tmp, name,
+ input_devices[d].icon);
+
+ gchar *strhash = g_strdup_printf("[%s]\n"
+ /* Name */ "$^$%s=%s\n"
+ /* Type */ "%s=%s\n"
+ /* Bus */ "%s=[0x%x] %s\n"
+ /* Vendor */ "$^$%s=[0x%x] %s\n"
+ /* Product */"%s=[0x%x] %s\n"
+ /* Version */"%s=0x%x\n",
+ _("Device Information"),
+ _("Name"), name,
+ _("Type"), UNKWNIFNULL(input_devices[d].name),
+ _("Bus"), bus, UNKWNIFNULL(bus_str),
+ _("Vendor"), vendor, UNKWNIFNULL(vendor_str),
+ _("Product"), product, UNKWNIFNULL(product_str),
+ _("Version"), version );
+
+ 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(phys);
+ g_free(name);
+ g_free(vendor_str);
+ g_free(vendor_tags);
+ g_free(product_str);
+ bus_str = NULL;
+ vendor_str = NULL;
+ product_str = NULL;
+ vendor_tags = NULL;
}
-
- 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/loongarch64/processor.c b/modules/devices/loongarch64/processor.c
new file mode 100644
index 00000000..08f3645e
--- /dev/null
+++ b/modules/devices/loongarch64/processor.c
@@ -0,0 +1,90 @@
+/*
+ * HardInfo - Displays System Information
+ * Copyright (C) 2003-2006 L. A. F. Pereira <l@tia.mat.br>
+ *
+ * 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 or later.
+ *
+ * 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 "hardinfo.h"
+#include "devices.h"
+#include "cpu_util.h"
+
+GSList *
+processor_scan(void)
+{
+ Processor *processor;
+ FILE *cpuinfo;
+ gchar buffer[128];
+
+ cpuinfo = fopen(PROC_CPUINFO, "r");
+ if (!cpuinfo)
+ return NULL;
+
+ processor = g_new0(Processor, 1);
+ 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("system type", processor->vendor_id);
+ get_str("CPU Family", processor->family);
+ get_str("Model Name", processor->model_name);
+ get_int("CPU Revision", processor->revision);
+ get_float("CPU MHz", processor->cpu_mhz);
+ get_float("BogoMIPS", processor->bogomips);
+ get_str("Features", processor->features);
+ }
+ g_strfreev(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("[%s]\n"
+ "%s=%s\n" /* vendor */
+ "%s=%s\n" /* family */
+ "%s=%s\n" /* name */
+ "%s=%d\n" /* revision */
+ "%s=%.2f %s\n" /* frequency */
+ "%s=%.2f\n" /* bogoMIPS */
+ "%s=%s\n" /* features */
+ "%s=%s\n", /* byte order */
+ _("Processor"),
+ _("System Type"), processor->vendor_id,
+ _("Family"), processor->family,
+ _("Model"), processor->model_name,
+ _("Revision"), processor->revision,
+ _("Frequency"), processor->cpu_mhz, _("MHz"),
+ _("BogoMIPS"), processor->bogomips,
+ _("Features"), processor->features,
+ _("Byte Order"), byte_order_str()
+ );
+}
diff --git a/modules/devices/m68k/processor.c b/modules/devices/m68k/processor.c
index e030732a..a9d71835 100644
--- a/modules/devices/m68k/processor.c
+++ b/modules/devices/m68k/processor.c
@@ -1,10 +1,10 @@
/*
* HardInfo - Displays System Information
- * Copyright (C) 2003-2006 Leandro A. F. Pereira <leandro@hardinfo.org>
+ * Copyright (C) 2003-2006 L. A. F. Pereira <l@tia.mat.br>
*
* 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.
+ * the Free Software Foundation, version 2 or later.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/modules/devices/mips/processor.c b/modules/devices/mips/processor.c
index b31af7dd..112a3c3b 100644
--- a/modules/devices/mips/processor.c
+++ b/modules/devices/mips/processor.c
@@ -1,10 +1,10 @@
/*
* HardInfo - Displays System Information
- * Copyright (C) 2003-2006 Leandro A. F. Pereira <leandro@hardinfo.org>
+ * Copyright (C) 2003-2006 L. A. F. Pereira <l@tia.mat.br>
*
* 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.
+ * the Free Software Foundation, version 2 or later.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/modules/devices/monitors.c b/modules/devices/monitors.c
new file mode 100644
index 00000000..02fb1d67
--- /dev/null
+++ b/modules/devices/monitors.c
@@ -0,0 +1,515 @@
+/*
+ * HardInfo - Displays System Information
+ * Copyright (C) 2003-2019 L. A. F. Pereira <l@tia.mat.br>
+ * Copyright (C) 2019 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 or later.
+ *
+ * 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 "devices.h"
+#include "util_sysobj.h"
+#include "util_edid.h"
+#include "util_ids.h"
+
+static const char monitor_icon[] = "monitor.png";
+
+#define UNKIFNULL2(f) ((f) ? f : _("(Unknown)"))
+#define UNKIFEMPTY2(f) ((*f) ? f : _("(Unknown)"))
+#define UNSPECIFNULL2(f) ((f) ? f : _("(Unspecified)"))
+
+gboolean no_monitors = FALSE;
+
+gchar *edid_ids_file = NULL;
+gchar *ieee_oui_ids_file = NULL;
+
+void find_edid_ids_file() {
+ if (edid_ids_file) return;
+ char *file_search_order[] = {
+ g_build_filename(g_get_user_config_dir(), "hardinfo2", "edid.ids", NULL),
+ g_build_filename(params.path_data, "edid.ids", NULL),
+ NULL
+ };
+ int n;
+ for(n = 0; file_search_order[n]; n++) {
+ if (!edid_ids_file && !access(file_search_order[n], R_OK))
+ edid_ids_file = file_search_order[n];
+ else
+ g_free(file_search_order[n]);
+ }
+ auto_free(edid_ids_file);
+}
+
+void find_ieee_oui_ids_file() {
+ if (ieee_oui_ids_file) return;
+ char *file_search_order[] = {
+ g_build_filename(g_get_user_config_dir(), "hardinfo2", "ieee_oui.ids", NULL),
+ g_build_filename(params.path_data, "ieee_oui.ids", NULL),
+ NULL
+ };
+ int n;
+ for(n = 0; file_search_order[n]; n++) {
+ if (!ieee_oui_ids_file && !access(file_search_order[n], R_OK))
+ ieee_oui_ids_file = file_search_order[n];
+ else
+ g_free(file_search_order[n]);
+ }
+ auto_free(ieee_oui_ids_file);
+}
+
+typedef struct {
+ gchar *drm_path;
+ gchar *drm_connection;
+ gchar *drm_status;
+ gchar *drm_enabled;
+ edid *e;
+ gchar *_vstr; /* use monitor_vendor_str() */
+} monitor;
+#define monitor_new() g_new0(monitor, 1)
+
+monitor *monitor_new_from_sysfs(const gchar *sysfs_edid_file) {
+ gchar *edid_bin = NULL;
+ gsize edid_len = 0;
+ if (!sysfs_edid_file || !*sysfs_edid_file) return NULL;
+ monitor *m = monitor_new();
+ m->drm_path = g_path_get_dirname(sysfs_edid_file);
+ m->drm_connection = g_path_get_basename(m->drm_path);
+ gchar *drm_enabled_file = g_strdup_printf("%s/%s", m->drm_path, "enabled");
+ gchar *drm_status_file = g_strdup_printf("%s/%s", m->drm_path, "status");
+ g_file_get_contents(drm_enabled_file, &m->drm_enabled, NULL, NULL);
+ if (m->drm_enabled) g_strstrip(m->drm_enabled);
+ g_file_get_contents(drm_status_file, &m->drm_status, NULL, NULL);
+ if (m->drm_status) g_strstrip(m->drm_status);
+ g_file_get_contents(sysfs_edid_file, &edid_bin, &edid_len, NULL);
+ if (edid_len)
+ m->e = edid_new(edid_bin, edid_len);
+ g_free(drm_enabled_file);
+ g_free(drm_status_file);
+ return m;
+}
+
+void monitor_free(monitor *m) {
+ if (m) {
+ g_free(m->_vstr);
+ g_free(m->drm_connection);
+ edid_free(m->e);
+ g_free(m);
+ }
+}
+
+gchar *monitor_vendor_str(monitor *m, gboolean include_value, gboolean link_name) {
+ if (!m || !m->e) return NULL;
+ edid_ven ven = m->e->ven;
+ gchar v[20] = "", t[4] = "";
+ ids_query_result result;// = {};
+
+ memset(&result,0,sizeof(ids_query_result));
+ if (ven.type == VEN_TYPE_PNP) {
+ strcpy(v, ven.pnp);
+ strcpy(t, "PNP");
+ } else if (ven.type == VEN_TYPE_OUI) {
+ strcpy(v, ven.oui_str);
+ strcpy(t, "OUI");
+ }
+
+ if (!m->_vstr) {
+ if (ven.type == VEN_TYPE_PNP) {
+ if (!edid_ids_file)
+ find_edid_ids_file();
+ scan_ids_file(edid_ids_file, v, &result, -1);
+ if (result.results[0])
+ m->_vstr = g_strdup(result.results[0]);
+ } else if (ven.type == VEN_TYPE_OUI) {
+ if (!ieee_oui_ids_file)
+ find_ieee_oui_ids_file();
+ scan_ids_file(ieee_oui_ids_file, v, &result, -1);
+ if (result.results[0])
+ m->_vstr = g_strdup(result.results[0]);
+ }
+ }
+
+ gchar *ret = NULL;
+ if (include_value)
+ ret = g_strdup_printf("[%s:%s]", t, v);
+ if (m->_vstr) {
+ if (link_name) {
+ gchar *lv = vendor_get_link(m->_vstr);
+ ret = appfsp(ret, "%s", lv);
+ g_free(lv);
+ } else
+ ret = appfsp(ret, "%s", m->_vstr);
+ } else if (!include_value && ven.type == VEN_TYPE_PNP) {
+ ret = appfsp(ret, "%s", ven.pnp);
+ } else
+ ret = appfsp(ret, "%s", _("(Unknown)"));
+ return ret;
+}
+
+gchar *monitor_name(monitor *m, gboolean include_vendor) {
+ if (!m) return NULL;
+ gchar *desc = NULL;
+ edid *e = m->e;
+ if (!e)
+ return g_strdup(_("(Unknown)"));
+
+ if (include_vendor) {
+ if (e->ven.type != VEN_TYPE_INVALID) {
+ gchar *vstr = monitor_vendor_str(m, FALSE, FALSE);
+ gchar *vtag = vendor_match_tag(vstr, params.fmt_opts);
+ desc = appfsp(desc, "%s", vtag ? vtag : vstr);
+ g_free(vstr);
+ g_free(vtag);
+ } else
+ desc = appfsp(desc, "%s", "Unknown");
+ }
+
+ if (e->img_max.diag_in)
+ desc = appfsp(desc, "%s", e->img_max.class_inch);
+
+ if (e->name)
+ desc = appfsp(desc, "%s", e->name);
+ else
+ desc = appfsp(desc, "%s %s", e->a_or_d ? "Digital" : "Analog", "Display");
+
+ return desc;
+}
+
+gchar **get_output_lines(const char *cmd_line) {
+ gboolean spawned;
+ gchar *out, *err;
+ gchar **ret = NULL;
+
+ spawned = g_spawn_command_line_sync(cmd_line,
+ &out, &err, NULL, NULL);
+ if (spawned) {
+ ret = g_strsplit(out, "\n", -1);
+ g_free(out);
+ g_free(err);
+ }
+ return ret;
+}
+
+static gchar *tag_make_safe_inplace(gchar *tag) {
+ if (!tag)
+ return tag;
+ if (!g_utf8_validate(tag, -1, NULL))
+ return tag; //TODO: reconsider
+ gchar *p = tag, *pd = tag;
+ while(*p) {
+ gchar *np = g_utf8_next_char(p);
+ gunichar c = g_utf8_get_char_validated(p, -1);
+ int l = g_unichar_to_utf8(c, NULL);
+ if (l == 1 && g_unichar_isalnum(c)) {
+ g_unichar_to_utf8(c, pd);
+ } else {
+ *pd = '_';
+ }
+ p = np;
+ pd++;
+ }
+ return tag;
+}
+
+static gchar *make_edid_section(monitor *m) {
+ int i;
+ edid *e = m->e;
+ if (e->len) {
+ gchar *vstr = monitor_vendor_str(m, TRUE, FALSE);
+
+ gchar *dom = NULL;
+ if (!e->dom.is_model_year && e->dom.week && e->dom.year)
+ dom = g_strdup_printf(_("Week %d of %d"), e->dom.week, e->dom.year);
+ else if (e->dom.year)
+ dom = g_strdup_printf("%d", e->dom.year);
+
+ gchar *bpcc = NULL;
+ if (e->bpc)
+ bpcc = g_strdup_printf("%d", e->bpc);
+
+ int aok = e->checksum_ok;
+ if (e->ext_blocks_fail) aok = 0;
+ gchar *csum = aok ? _("Ok") : _("Fail");
+
+ gchar *iface;
+ if (e->interface && e->di.exists) {
+ gchar *tmp = g_strdup_printf("[%x] %s\n[DI-EXT:%x] %s",
+ e->interface, _(edid_interface(e->interface)),
+ e->di.interface, _(edid_di_interface(e->di.interface)) );
+ iface = gg_key_file_parse_string_as_value(tmp, '|');
+ g_free(tmp);
+ } else if (e->di.exists) {
+ iface = g_strdup_printf("[DI-EXT:%x] %s",
+ e->di.interface, _(edid_di_interface(e->di.interface)) );
+ } else {
+ iface = g_strdup_printf("[%x] %s",
+ e->interface,
+ e->interface ? _(edid_interface(e->interface)) : _("(Unspecified)") );
+ }
+
+ gchar *d_list, *ext_list, *dtd_list, *cea_list,
+ *etb_list, *std_list, *svd_list, *sad_list,
+ *didt_list, *did_string_list;
+
+ etb_list = NULL;
+ for(i = 0; i < e->etb_count; i++) {
+ char *desc = edid_output_describe(&e->etbs[i]);
+ etb_list = appfnl(etb_list, "etb%d=%s", i, desc);
+ g_free(desc);
+ }
+ if (!etb_list) etb_list = g_strdup_printf("%s=\n", _("(Empty List)"));
+
+ std_list = NULL;
+ for(i = 0; i < e->std_count; i++) {
+ char *desc = edid_output_describe(&e->stds[i].out);
+ std_list = appfnl(std_list, "std%d=%s", i, desc);
+ g_free(desc);
+ }
+ if (!std_list) std_list = g_strdup_printf("%s=\n", _("(Empty List)"));
+
+ d_list = NULL;
+ for(i = 0; i < 4; i++) {
+ char *desc = edid_base_descriptor_describe(&e->d[i]);
+ d_list = appfnl(d_list, "descriptor%d=%s", i, desc);
+ g_free(desc);
+ }
+ if (!d_list) d_list = g_strdup_printf("%s=\n", _("(Empty List)"));
+
+ ext_list = NULL;
+ for(i = 0; i < e->ext_blocks; i++) {
+ int type = e->u8[(i+1)*128];
+ int version = e->u8[(i+1)*128 + 1];
+ ext_list = appfnl(ext_list, "ext%d = ([%02x:v%02x] %s) %s", i,
+ type, version, _(edid_ext_block_type(type)),
+ e->ext_ok[i] ? "ok" : "fail"
+ );
+ }
+ if (!ext_list) ext_list = g_strdup_printf("%s=\n", _("(Empty List)"));
+
+ dtd_list = NULL;
+ for(i = 0; i < e->dtd_count; i++) {
+ char *desc = edid_dtd_describe(&e->dtds[i], 0);
+ dtd_list = appfnl(dtd_list, "dtd%d = %s", i, desc);
+ free(desc);
+ }
+ if (!dtd_list) dtd_list = g_strdup_printf("%s=\n", _("(Empty List)"));
+
+ cea_list = NULL;
+ for(i = 0; i < e->cea_block_count; i++) {
+ char *desc = edid_cea_block_describe(&e->cea_blocks[i]);
+ cea_list = appfnl(cea_list, "cea_block%d = %s", i, desc);
+ }
+ if (!cea_list) cea_list = g_strdup_printf("%s=\n", _("(Empty List)"));
+
+ svd_list = NULL;
+ for(i = 0; i < e->svd_count; i++) {
+ char *desc = edid_output_describe(&e->svds[i].out);
+ svd_list = appfnl(svd_list, "svd%d=%s", i, desc);
+ g_free(desc);
+ }
+ if (!svd_list) svd_list = g_strdup_printf("%s=\n", _("(Empty List)"));
+
+ sad_list = NULL;
+ for(i = 0; i < e->sad_count; i++) {
+ char *desc = edid_cea_audio_describe(&e->sads[i]);
+ sad_list = appfnl(sad_list, "sad%d=%s", i, desc);
+ g_free(desc);
+ }
+ if (!sad_list) sad_list = g_strdup_printf("%s=\n", _("(Empty List)"));
+
+ didt_list = NULL;
+ for(i = 0; i < e->didt_count; i++) {
+ char *desc = edid_output_describe(&e->didts[i]);
+ didt_list = appfnl(didt_list, "didt%d=%s", i, desc);
+ g_free(desc);
+ }
+ if (!didt_list) didt_list = g_strdup_printf("%s=\n", _("(Empty List)"));
+
+ did_string_list = NULL;
+ for(i = 0; i < e->did_string_count; i++) {
+ did_string_list = appfnl(did_string_list, "did_string%d=%s", i, e->did_strings[i].str);
+ }
+ if (!did_string_list) did_string_list = g_strdup_printf("%s=\n", _("(Empty List)"));
+
+ gchar *speakers = NULL;
+ if (e->speaker_alloc_bits) {
+ gchar *spk_tmp = edid_cea_speaker_allocation_describe(e->speaker_alloc_bits, 0);
+ speakers = gg_key_file_parse_string_as_value(spk_tmp, '|');
+ g_free(spk_tmp);
+ } else
+ speakers = g_strdup(_("(Unspecified)"));
+
+ gchar *hex = edid_dump_hex(e, 0, 1);
+ gchar *hex_esc = gg_key_file_parse_string_as_value(hex, '|');
+ g_free(hex);
+ if (params.markup_ok)
+ hex = g_strdup_printf("<tt>%s</tt>", hex_esc);
+ else
+ hex = g_strdup(hex_esc);
+ g_free(hex_esc);
+
+ gchar *ret = g_strdup_printf(
+ /* extending "Connection" section */
+ "%s=%s\n" /* sig type */
+ "%s=%s\n" /* interface */
+ "%s=%s\n" /* bpcc */
+ "%s=%s\n" /* speakers */
+ "[%s]\n"
+ "%s=%s\n" /* base out */
+ "%s=%s\n" /* ext out */
+ "[%s]\n"
+ "$^$%s=%s\n" /* vendor */
+ "%s=%s\n" /* name */
+ "%s=[%04x-%08x] %u-%u\n" /* model, n_serial */
+ "%s=%s\n" /* serial */
+ "%s=%s\n" /* dom */
+ "[%s]\n"
+ "%s=%d %s\n" /* size */
+ "%s=%d.%d\n" /* version */
+ "%s=%d\n" /* ext block */
+ "%s=%s\n" /* ext to */
+ "%s=%s %s\n" /* checksum */
+ "[%s]\n%s\n"
+ "[%s]\n%s\n"
+ "[%s]\n%s\n"
+ "[%s]\n%s\n"
+ "[%s]\n%s\n"
+ "[%s]\n%s\n"
+ "[%s]\n%s\n"
+ "[%s]\n%s\n"
+ "[%s]\n%s\n"
+ "[%s]\n%s\n"
+ "[%s]\n%s=%s\n"
+ ,
+ _("Signal Type"), e->a_or_d ? _("Digital") : _("Analog"),
+ _("Interface"), iface,
+ _("Bits per Color Channel"), UNSPECIFNULL2(bpcc),
+ _("Speaker Allocation"), speakers,
+ _("Output (Max)"),
+ edid_output_src(e->img.src), edid_output_describe(&e->img),
+ edid_output_src(e->img_max.src), edid_output_describe(&e->img_max),
+ _("EDID Device"),
+ _("Vendor"), vstr,
+ _("Name"), e->name,
+ _("Model"), e->product, e->n_serial, e->product, e->n_serial,
+ _("Serial"), UNKIFNULL2(e->serial),
+ _("Manufacture Date"), UNKIFNULL2(dom),
+ _("EDID Meta"),
+ _("Data Size"), e->len, _("bytes"),
+ _("Version"), (int)e->ver_major, (int)e->ver_minor,
+ _("Extension Blocks"), e->ext_blocks,
+ _("Extended to"), e->std ? _(edid_standard(e->std)) : _("(None)"),
+ _("Checksum"), csum, aok ? "" : problem_marker(),
+ _("EDID Descriptors"), d_list,
+ _("Detailed Timing Descriptors (DTD)"), dtd_list,
+ _("Established Timings Bitmap (ETB)"), etb_list,
+ _("Standard Timings (STD)"), std_list,
+ _("E-EDID Extension Blocks"), ext_list,
+ _("EIA/CEA-861 Data Blocks"), cea_list,
+ _("EIA/CEA-861 Short Audio Descriptors"), sad_list,
+ _("EIA/CEA-861 Short Video Descriptors"), svd_list,
+ _("DisplayID Timings"), didt_list,
+ _("DisplayID Strings"), did_string_list,
+ _("Hex Dump"), _("Data"), hex
+ );
+ g_free(bpcc);
+ g_free(dom);
+
+ g_free(d_list);
+ g_free(ext_list);
+ g_free(etb_list);
+ g_free(std_list);
+ g_free(dtd_list);
+ g_free(cea_list);
+ g_free(sad_list);
+ g_free(svd_list);
+ g_free(didt_list);
+ g_free(did_string_list);
+ g_free(iface);
+ g_free(vstr);
+ g_free(hex);
+ //printf("ret: %s\n", ret);
+ return ret;
+ } else
+ return g_strdup("");
+}
+
+gchar *monitors_get_info() {
+ gchar *icons = g_strdup("");
+ gchar *ret = g_strdup_printf("[%s]\n", _("Monitors"));
+ gchar tag_prefix[] = "DEV";
+
+ gchar **edid_files = get_output_lines("find /sys/devices -name edid");
+ //gchar **edid_files = get_output_lines("find /home/pburt/github/verbose-spork/junk/testing/.testing/edid2/ -name edid.*");
+ int i, found = 0;
+ for(i = 0; edid_files[i]; i++) {
+ monitor *m = monitor_new_from_sysfs(edid_files[i]);
+ //if (m && m->e->std < STD_DISPLAYID) continue;
+ //if (m && !m->e->interface) continue;
+ //if (m && m->e->interface != 1) continue;
+ if (m && !SEQ(m->drm_status, "disconnected")) {
+ gchar *tag = g_strdup_printf("%d-%s", found, m->drm_connection);
+ tag_make_safe_inplace(tag);
+ gchar *desc = monitor_name(m, TRUE);
+ gchar *edid_section = NULL;
+ edid *e = m->e;
+ if (e && e->checksum_ok)
+ edid_section = make_edid_section(m);
+
+ gchar *details = g_strdup_printf("[%s]\n"
+ "%s=%s\n"
+ "%s=%s %s\n"
+ "%s\n",
+ _("Connection"),
+ _("DRM"), m->drm_connection,
+ _("Status"), m->drm_status, m->drm_enabled,
+ edid_section ? edid_section : ""
+ );
+ moreinfo_add_with_prefix(tag_prefix, tag, details); /* moreinfo now owns *details */
+ ret = h_strdup_cprintf("$!%s$%s=%s\n",
+ ret, tag, m->drm_connection, desc);
+ icons = h_strdup_cprintf("Icon$%s$=%s\n", icons, tag, monitor_icon);
+ g_free(desc);
+ g_free(edid_section);
+ found++;
+ }
+ monitor_free(m);
+ }
+ g_strfreev(edid_files);
+
+ no_monitors = FALSE;
+ if(!found) {
+ no_monitors = TRUE;
+ g_free(ret);
+ ret = g_strdup_printf("[%s]\n%s=%s\n" "[$ShellParam$]\nViewType=0\n",
+ _("Monitors"), _("Result"), _("(Empty)") );
+ } else {
+ ret = h_strdup_cprintf(
+ "[$ShellParam$]\nViewType=1\n"
+ "ColumnTitle$TextValue=%s\n" /* DRM connection */
+ "ColumnTitle$Value=%s\n" /* Name */
+ "ShowColumnHeaders=true\n"
+ "%s",
+ ret,
+ _("Connection"),
+ _("Name"),
+ icons
+ );
+ }
+
+ return ret;
+}
+
+gboolean monitors_hinote(const char **msg) {
+ PARAM_NOT_UNUSED(msg);
+ return FALSE;
+}
diff --git a/modules/devices/parisc/processor.c b/modules/devices/parisc/processor.c
index 9ca38d12..c749bc5a 100644
--- a/modules/devices/parisc/processor.c
+++ b/modules/devices/parisc/processor.c
@@ -1,10 +1,10 @@
/*
* HardInfo - Displays System Information
- * Copyright (C) 2003-2006 Leandro A. F. Pereira <leandro@hardinfo.org>
+ * Copyright (C) 2003-2006 L. A. F. Pereira <l@tia.mat.br>
*
* 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.
+ * the Free Software Foundation, version 2 or later.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/modules/devices/pci.c b/modules/devices/pci.c
index c1965a63..859fa339 100644
--- a/modules/devices/pci.c
+++ b/modules/devices/pci.c
@@ -1,10 +1,10 @@
/*
* HardInfo - Displays System Information
- * Copyright (C) 2003-2006 Leandro A. F. Pereira <leandro@hardinfo.org>
+ * Copyright (C) 2003-2006 L. A. F. Pereira <l@tia.mat.br>
*
* 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.
+ * the Free Software Foundation, version 2 or later.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -16,239 +16,185 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
-/*
- * TODO: This thing must be rewritten. We really should have a struct with all the
- * PCI stuff we'll present to the user, and hash them by the PCI ID
- * (domain:bus:device.function).
- * This way we'll have ways to better organize the output, instead of relying
- * on the order the information appears on lspci's output.
- * Also, the "Resources" thing might be better implemented (and we won't need
- * copies of information scattered everywhere like we do today).
- */
-
#include <string.h>
#include "hardinfo.h"
#include "devices.h"
-
-GHashTable *_pci_devices = NULL;
-
-void
-scan_pci_do(void)
+#include "pci_util.h"
+
+#define UNKIFNULL_AC(f) (f != NULL) ? f : _("(Unknown)");
+
+static const struct {
+ const gchar *icon;
+ uint32_t class;
+} class2icon[] = {
+ { .class = 0x0200, .icon = "network-interface.png" },
+ { .class = 0x0c03, .icon = "usb.png" },
+ { .class = 0x0403, .icon = "audio.png" },
+ { .class = 0x0805, .icon = "usbfldisk.png" },
+ { .class = 0x0d11, .icon = "bluetooth.png" },
+ { .class = 0x0703, .icon = "modem.png" },
+ { .class = 0x01, .icon = "hdd.png" },
+ { .class = 0x02, .icon = "network.png" },
+ { .class = 0x03, .icon = "monitor.png" },
+ { .class = 0x05, .icon = "memory.png" },
+ { .class = 0x07, .icon = "network-connections.png" },
+ { .class = 0x09, .icon = "inputdevices.png" },
+ { .class = 0x10, .icon = "cryptohash.png" },
+};
+
+static const gchar *find_icon_for_class(uint32_t class)
{
- FILE *lspci;
- gchar buffer[256], *buf, *strhash = NULL, *strdevice = NULL;
- gchar *category = NULL, *name = NULL, *icon, *lspci_path, *command_line = NULL;
- gint n = 0, x = 0;
+ guint i;
+
+ for (i = 0; i < G_N_ELEMENTS(class2icon); i++) {
+ if (class2icon[i].class <= 0xff) {
+ if ((class & 0xff00) == class2icon[i].class << 8)
+ return class2icon[i].icon;
+ } else if (class == class2icon[i].class) {
+ return class2icon[i].icon;
+ }
+ }
- if ((lspci_path = find_program("lspci")) == NULL) {
- goto pci_error;
+ return "devices.png";
+}
+
+static gchar *_pci_dev(const pcid *p, gchar *icons) {
+ gchar *str;
+ const gchar *class, *vendor, *svendor, *product, *sproduct, *lproduct;
+ gchar *name, *key;
+
+ gboolean device_is_sdevice = (p->vendor_id == p->sub_vendor_id && p->device_id == p->sub_device_id);
+
+ class = UNKIFNULL_AC(p->class_str);
+ vendor = UNKIFNULL_AC(p->vendor_id_str);
+ svendor = UNKIFNULL_AC(p->sub_vendor_id_str);
+ product = UNKIFNULL_AC(p->device_id_str);
+ sproduct = UNKIFNULL_AC(p->sub_device_id_str);
+ lproduct = p->device_id_str ? p->device_id_str : p->class_str;
+ lproduct = UNKIFNULL_AC(lproduct);
+
+ gchar *ven_tag = vendor_match_tag(p->vendor_id_str, params.fmt_opts);
+ gchar *sven_tag = vendor_match_tag(p->sub_vendor_id_str, params.fmt_opts);
+ if (ven_tag) {
+ if (sven_tag && p->vendor_id != p->sub_vendor_id) {
+ name = g_strdup_printf("%s %s %s", sven_tag, ven_tag, lproduct);
+ } else {
+ name = g_strdup_printf("%s %s", ven_tag, lproduct);
+ }
} else {
- command_line = g_strdup_printf("%s -v", lspci_path);
+ name = g_strdup_printf("%s %s", vendor, lproduct);
}
+ g_free(ven_tag);
+ g_free(sven_tag);
- if (!_pci_devices) {
- _pci_devices = g_hash_table_new(g_str_hash, g_str_equal);
- }
+ key = g_strdup_printf("PCI%04x:%02x:%02x.%01x", p->domain, p->bus, p->device, p->function);
- buf = g_build_filename(g_get_home_dir(), ".hardinfo", "pci.ids", NULL);
- if (!g_file_test(buf, G_FILE_TEST_EXISTS)) {
- DEBUG("using system-provided PCI IDs");
- g_free(buf);
- if (!(lspci = popen(command_line, "r"))) {
- goto pci_error;
- }
+ pci_list = h_strdup_cprintf("$%s$%04x:%02x:%02x.%01x=%s\n", pci_list, key, p->domain, p->bus, p->device, p->function, name);
+ icons = h_strdup_cprintf("Icon$%s$%04x:%02x:%02x.%01x=%s\n", icons, key, p->domain, p->bus, p->device, p->function, find_icon_for_class(p->class));
+
+ gchar *vendor_device_str;
+ if (device_is_sdevice) {
+ vendor_device_str = g_strdup_printf(
+ /* Vendor */ "$^$%s=[%04x] %s\n"
+ /* Device */ "%s=[%04x] %s\n",
+ _("Vendor"), p->vendor_id, vendor,
+ _("Device"), p->device_id, product);
} 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);
- goto pci_error;
- } else {
- g_free(buf);
- }
+ vendor_device_str = g_strdup_printf(
+ /* Vendor */ "$^$%s=[%04x] %s\n"
+ /* Device */ "%s=[%04x] %s\n"
+ /* Sub-device vendor */ "$^$%s=[%04x] %s\n"
+ /* Sub-device */ "%s=[%04x] %s\n",
+ _("Vendor"), p->vendor_id, vendor,
+ _("Device"), p->device_id, product,
+ _("SVendor"), p->sub_vendor_id, svendor,
+ _("SDevice"), p->sub_device_id, sproduct);
}
- while (fgets(buffer, 256, lspci)) {
- buf = g_strstrip(buffer);
-
- if (!strncmp(buf, "Flags", 5)) {
- gint irq = 0, freq = 0, latency = 0, i;
- gchar **list;
- gboolean bus_master;
-
- buf += 7;
-
- bus_master = FALSE;
-
- list = g_strsplit(buf, ", ", 10);
- for (i = 0; i <= 10; i++) {
- if (!list[i])
- break;
-
- if (!strncmp(list[i], "IRQ", 3))
- sscanf(list[i], "IRQ %d", &irq);
- else if (strstr(list[i], "Mhz"))
- sscanf(list[i], "%dMhz", &freq);
- else if (!strncmp(list[i], "bus master", 10))
- bus_master = TRUE;
- else if (!strncmp(list[i], "latency", 7))
- sscanf(list[i], "latency %d", &latency);
- }
- g_strfreev(list);
-
- if (irq)
- strdevice = h_strdup_cprintf("%s=%d\n", strdevice, _("IRQ"), irq);
- if (freq)
- strdevice = h_strdup_cprintf("%s=%d %s\n", strdevice, _("Frequency"), freq, _("MHz") );
- if (latency)
- strdevice = h_strdup_cprintf("%s=%d\n", strdevice, _("Latency"), latency);
-
- 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("%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(_("%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, "access denied")) {
- WALK_UNTIL(' ');
- WALK_UNTIL(']');
- buf++;
- strdevice = h_strdup_cprintf("Capability#%d=%s\n", strdevice, ++x, buf);
- } else if (!strncmp(buf, "Memory at", 9) && strstr(buf, "[size=")) {
- gint mem;
- gchar unit;
- gboolean prefetch;
- gboolean _32bit;
-
- prefetch = strstr(buf, "non-prefetchable") ? FALSE : TRUE;
- _32bit = strstr(buf, "32-bit") ? TRUE : FALSE;
-
- WALK_UNTIL('[');
- sscanf(buf, "[size=%d%c", &mem, &unit);
-
- strdevice = h_strdup_cprintf("%s#%d=%d%cB (%s%s)\n",
- strdevice, _("Memory"), ++x,
- mem,
- (unit == ']') ? ' ' : unit,
- _32bit ? "32-bit, " : "",
- prefetch ? _("prefetchable") :
- _("non-prefetchable") );
-
- } else if (!strncmp(buf, "I/O ports at", 12)) {
- guint io_addr, io_size;
-
- sscanf(buf, "I/O ports at %x [size=%d]", &io_addr, &io_size);
-
- strdevice =
- 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;
- gpointer start, end;
-
- if (strdevice != NULL && strhash != NULL) {
- moreinfo_add_with_prefix("DEV", strhash, strdevice);
- g_free(strhash);
- g_free(category);
- g_free(name);
- }
-
- if (buf[4] == ':') {
- sscanf(buf, "%x:%x:%x.%d", &domain, &bus, &device, &function);
- } else {
- /* lspci without domain field */
- sscanf(buf, "%x:%x.%x", &bus, &device, &function);
- domain = 0;
- }
-
- WALK_UNTIL(' ');
-
- start = buf;
-
- WALK_UNTIL(':');
- end = buf + 1;
- *buf = 0;
-
- buf = start + 1;
- category = g_strdup(buf);
-
- buf = end;
-
- if (strstr(category, "RAM memory")) icon = "mem";
- 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("[%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("%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++;
- }
+ gchar *pcie_str;
+ if (p->pcie_width_curr) {
+ pcie_str = g_strdup_printf("[%s]\n"
+ /* Width */ "%s=x%u\n"
+ /* Width (max) */ "%s=x%u\n"
+ /* Speed */ "%s=%0.1f %s\n"
+ /* Speed (max) */ "%s=%0.1f %s\n",
+ _("PCI Express"),
+ _("Link Width"), p->pcie_width_curr,
+ _("Maximum Link Width"), p->pcie_width_max,
+ _("Link Speed"), p->pcie_speed_curr, _("GT/s"),
+ _("Maximum Link Speed"), p->pcie_speed_max, _("GT/s") );
+ } else
+ pcie_str = strdup("");
+
+ str = g_strdup_printf("[%s]\n"
+ /* Class */ "%s=[%04x] %s\n"
+ "%s"
+ /* Revision */ "%s=%02x\n"
+ /* PCIE? */ "%s"
+ "[%s]\n"
+ /* Driver */ "%s=%s\n"
+ /* Modules */ "%s=%s\n"
+ "[%s]\n"
+ /* Domain */ "%s=%04x\n"
+ /* Bus */ "%s=%02x\n"
+ /* Device */ "%s=%02x\n"
+ /* Function */ "%s=%01x\n",
+ _("Device Information"),
+ _("Class"), p->class, class,
+ vendor_device_str,
+ _("Revision"), p->revision,
+ pcie_str,
+ _("Driver"),
+ _("In Use"), (p->driver) ? p->driver : _("(Unknown)"),
+ _("Kernel Modules"), (p->driver_list) ? p->driver_list : _("(Unknown)"),
+ _("Connection"),
+ _("Domain"), p->domain,
+ _("Bus"), p->bus,
+ _("Device"), p->device,
+ _("Function"), p->function
+ );
+
+ g_free(pcie_str);
+
+ moreinfo_add_with_prefix("DEV", key, str); /* str now owned by morinfo */
+
+ g_free(vendor_device_str);
+ g_free(name);
+ g_free(key);
+
+ return icons;
+}
+
+void scan_pci_do(void) {
+
+ if (pci_list) {
+ moreinfo_del_with_prefix("DEV:PCI");
+ g_free(pci_list);
+ }
+ pci_list = g_strdup_printf("[%s]\n", _("PCI Devices"));
+
+ gchar *pci_icons = g_strdup("");
+
+ pcid_list list = pci_get_device_list(0,0);
+ list = g_slist_sort(list, (GCompareFunc)pcid_cmp_by_addy);
+ GSList *l = list;
+
+ int c = 0;
+ while(l) {
+ pcid *curr = (pcid*)l->data;
+ pci_icons = _pci_dev(curr, pci_icons);
+ c++;
+ l=l->next;
}
+ pcid_list_free(list);
- if (pclose(lspci)) {
-pci_error:
- /* error (no pci, perhaps?) */
+ if (c) {
+ pci_list = g_strconcat(pci_list, "[$ShellParam$]\n", "ViewType=1\n", pci_icons, NULL);
+ } else {
+ /* NO PCI? */
pci_list = g_strconcat(pci_list, _("No PCI devices found"), "=\n", NULL);
- } else if (strhash) {
- /* 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);
+ g_free(pci_icons);
}
diff --git a/modules/devices/ppc/processor.c b/modules/devices/ppc/processor.c
index 3360a136..12c575a6 100644
--- a/modules/devices/ppc/processor.c
+++ b/modules/devices/ppc/processor.c
@@ -1,10 +1,10 @@
/*
* HardInfo - Displays System Information
- * Copyright (C) 2003-2006 Leandro A. F. Pereira <leandro@hardinfo.org>
+ * Copyright (C) 2003-2006 L. A. F. Pereira <l@tia.mat.br>
*
* 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.
+ * the Free Software Foundation, version 2 or later.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/modules/devices/printers.c b/modules/devices/printers.c
index 77b52a43..fb9389ac 100644
--- a/modules/devices/printers.c
+++ b/modules/devices/printers.c
@@ -1,10 +1,10 @@
/*
* HardInfo - Displays System Information
- * Copyright (C) 2003-2007 Leandro A. F. Pereira <leandro@hardinfo.org>
+ * Copyright (C) 2003-2007 L. A. F. Pereira <l@tia.mat.br>
*
* 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.
+ * the Free Software Foundation, version 2 or later.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -16,6 +16,10 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#ifndef _XOPEN_SOURCE
+ #define _XOPEN_SOURCE
+#endif
+
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
@@ -33,7 +37,7 @@ struct _CUPSDest {
char *name, *instance;
int is_default;
int num_options;
- CUPSOption *options;
+ CUPSOption *options;
};
static int (*cups_dests_get) (CUPSDest **dests) = NULL;
@@ -49,13 +53,13 @@ init_cups(void)
if (!(cups_dests_get && cups_dests_free)) {
int i;
-
+
for (i = 0; libcups[i] != NULL; i++) {
cups = g_module_open(libcups[i], G_MODULE_BIND_LAZY);
if (cups)
- break;
+ break;
}
-
+
if (!cups) {
cups_init = FALSE;
return;
@@ -63,11 +67,11 @@ init_cups(void)
if (!g_module_symbol(cups, "cupsGetDests", (gpointer) & cups_dests_get)
|| !g_module_symbol(cups, "cupsFreeDests", (gpointer) & cups_dests_free)) {
- g_module_close(cups);
+ if(cups) g_module_close(cups);
cups_init = FALSE;
}
}
-
+
cups_init = TRUE;
}
@@ -76,7 +80,7 @@ gchar *__cups_callback_ptype(gchar *strvalue)
if (strvalue) {
unsigned value = atoi(strvalue);
gchar *output = g_strdup("\n");
-
+
if (value & 0x0004)
output = h_strdup_cprintf(_("\342\232\254 Can do black and white printing=\n"), output);
if (value & 0x0008)
@@ -121,7 +125,7 @@ gchar *__cups_callback_state_change_time(gchar *value)
{
struct tm tm;
char buf[255];
-
+
if (value) {
strptime(value, "%s", &tm);
strftime(buf, sizeof(buf), "%c", &tm);
@@ -144,29 +148,30 @@ gchar *__cups_callback_boolean(gchar *value)
const struct {
char *key, *name;
gchar *(*callback)(gchar *value);
+ gboolean maybe_vendor;
} cups_fields[] = {
{ "Printer Information", NULL, NULL },
{ "printer-info", "Destination Name", NULL },
- { "printer-make-and-model", "Make and Model", NULL },
-
+ { "printer-make-and-model", "Make and Model", NULL, TRUE },
+
{ "Capabilities", NULL, NULL },
{ "printer-type", "#", __cups_callback_ptype },
-
+
{ "Printer State", NULL, NULL },
{ "printer-state", "State", __cups_callback_state },
{ "printer-state-change-time", "Change Time", __cups_callback_state_change_time },
{ "printer-state-reasons", "State Reasons" },
-
+
{ "Sharing Information", NULL, NULL },
{ "printer-is-shared", "Shared?", __cups_callback_boolean },
{ "printer-location", "Physical Location" },
{ "auth-info-required", "Authentication Required", __cups_callback_boolean },
-
+
{ "Jobs", NULL, NULL },
{ "job-hold-until", "Hold Until", NULL },
{ "job-priority", "Priority", NULL },
{ "printer-is-accepting-jobs", "Accepting Jobs", __cups_callback_boolean },
-
+
{ "Media", NULL, NULL },
{ "media", "Media", NULL },
{ "finishings", "Finishings", NULL },
@@ -176,7 +181,7 @@ const struct {
void
scan_printers_do(void)
{
- int num_dests, i, j;
+ guint num_dests, j, i;
CUPSDest *dests;
gchar *prn_id, *prn_moreinfo;
@@ -185,7 +190,7 @@ scan_printers_do(void)
if (!cups_init) {
init_cups();
-
+
printer_icons = g_strdup("");
printer_list = g_strdup(_("[Printers]\n"
"No suitable CUPS library found="));
@@ -201,22 +206,22 @@ scan_printers_do(void)
printer_icons = g_strdup("");
for (i = 0; i < num_dests; i++) {
GHashTable *options;
-
+
options = g_hash_table_new(g_str_hash, g_str_equal);
-
- for (j = 0; j < dests[i].num_options; j++) {
+
+ for (j = 0; (int)j < dests[i].num_options; j++) {
g_hash_table_insert(options,
g_strdup(dests[i].options[j].name),
g_strdup(dests[i].options[j].value));
}
-
+
prn_id = g_strdup_printf("PRN%d", i);
-
+
printer_list = h_strdup_cprintf("\n$%s$%s=%s\n",
printer_list,
- prn_id,
+ prn_id,
dests[i].name,
- dests[i].is_default ? "<i>Default</i>" : "");
+ dests[i].is_default ? ((params.markup_ok) ? "<i>Default</i>" : "(Default)") : "");
printer_icons = h_strdup_cprintf("\nIcon$%s$%s=printer.png",
printer_icons,
prn_id,
@@ -230,9 +235,9 @@ scan_printers_do(void)
cups_fields[j].key);
} else {
gchar *temp;
-
+
temp = g_hash_table_lookup(options, cups_fields[j].key);
-
+
if (cups_fields[j].callback) {
temp = cups_fields[j].callback(temp);
} else {
@@ -243,21 +248,22 @@ scan_printers_do(void)
temp = g_strdup(_("Unknown"));
}
}
-
- prn_moreinfo = h_strdup_cprintf("%s=%s\n",
+
+ prn_moreinfo = h_strdup_cprintf("%s%s=%s\n",
prn_moreinfo,
+ cups_fields[j].maybe_vendor ? "$^$" : "",
cups_fields[j].name,
temp);
-
+
g_free(temp);
}
}
-
+
moreinfo_add_with_prefix("DEV", prn_id, prn_moreinfo);
g_free(prn_id);
g_hash_table_destroy(options);
}
-
+
cups_dests_free(num_dests, dests);
} else {
printer_list = g_strdup(_("[Printers]\n"
diff --git a/modules/devices/resources.c b/modules/devices/resources.c
index 15cb8f21..c9d1ccb5 100644
--- a/modules/devices/resources.c
+++ b/modules/devices/resources.c
@@ -1,10 +1,10 @@
/*
* HardInfo - Displays System Information
- * Copyright (C) 2003-2008 Leandro A. F. Pereira <leandro@hardinfo.org>
+ * Copyright (C) 2003-2008 L. A. F. Pereira <l@tia.mat.br>
*
* 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.
+ * the Free Software Foundation, version 2 or later.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -37,21 +37,27 @@ static gchar *_resource_obtain_name(gchar *name)
0, 0, NULL);
_regex_module = g_regex_new("^[0-9a-zA-Z\\_\\-]+$", 0, 0, NULL);
}
-
+
name = g_strstrip(name);
-
+
if (g_regex_match(_regex_pci, name, 0, NULL)) {
temp = module_call_method_param("devices::getPCIDeviceDescription", name);
if (temp) {
+ if (params.markup_ok)
return g_strdup_printf("<b><small>PCI</small></b> %s", (gchar *)idle_free(temp));
+ else
+ return g_strdup_printf("PCI %s", (gchar *)idle_free(temp));
}
} else if (g_regex_match(_regex_module, name, 0, NULL)) {
temp = module_call_method_param("computer::getKernelModuleDescription", name);
if (temp) {
+ if (params.markup_ok)
return g_strdup_printf("<b><small>Module</small></b> %s", (gchar *)idle_free(temp));
+ else
+ return g_strdup_printf("Module %s", (gchar *)idle_free(temp));
}
}
-
+
return g_strdup(name);
}
#else
@@ -66,7 +72,7 @@ void scan_device_resources(gboolean reload)
SCAN_START();
FILE *io;
gchar buffer[256];
- gint i;
+ guint i;
gint zero_to_zero_addr = 0;
struct {
@@ -77,10 +83,10 @@ void scan_device_resources(gboolean reload)
{ "/proc/iomem", "[Memory]\n" },
{ "/proc/dma", "[DMA]\n" }
};
-
+
g_free(_resources);
_resources = g_strdup("");
-
+
for (i = 0; i < G_N_ELEMENTS(resources); i++) {
if ((io = fopen(resources[i].file, "r"))) {
_resources = h_strconcat(_resources, resources[i].description, NULL);
@@ -92,8 +98,12 @@ void scan_device_resources(gboolean reload)
if (strstr(temp[0], "0000-0000"))
zero_to_zero_addr++;
- _resources = h_strdup_cprintf("<tt>%s</tt>=%s\n", _resources,
- temp[0], name);
+ if (params.markup_ok)
+ _resources = h_strdup_cprintf("<tt>%s</tt>=%s\n", _resources,
+ temp[0], name);
+ else
+ _resources = h_strdup_cprintf(">%s=%s\n", _resources,
+ temp[0], name);
g_strfreev(temp);
g_free(name);
diff --git a/modules/devices/riscv/processor.c b/modules/devices/riscv/processor.c
index afddf89d..f2e51c91 100644
--- a/modules/devices/riscv/processor.c
+++ b/modules/devices/riscv/processor.c
@@ -1,10 +1,10 @@
/*
* HardInfo - Displays System Information
- * Copyright (C) 2003-2006 Leandro A. F. Pereira <leandro@hardinfo.org>
+ * Copyright (C) 2003-2006 L. A. F. Pereira <l@tia.mat.br>
*
* 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.
+ * the Free Software Foundation, version 2 or later.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/modules/devices/riscv/riscv_data.c b/modules/devices/riscv/riscv_data.c
index 4ae68ef4..917e8e06 100644
--- a/modules/devices/riscv/riscv_data.c
+++ b/modules/devices/riscv/riscv_data.c
@@ -93,7 +93,7 @@ const char *riscv_ext_meaning(const char *ext) {
/* see RISC-V spec 2.2: Chapter 22: ISA Subset Naming Conventions */
-/* Spec says case-insensitve, but I prefer single-letter extensions
+/* Spec says case-insensitive, 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++; } \
diff --git a/modules/devices/s390/processor.c b/modules/devices/s390/processor.c
index cf45c33c..e4f2b303 100644
--- a/modules/devices/s390/processor.c
+++ b/modules/devices/s390/processor.c
@@ -1,10 +1,10 @@
/*
* HardInfo - Displays System Information
- * Copyright (C) 2003-2006 Leandro A. F. Pereira <leandro@hardinfo.org>
+ * Copyright (C) 2003-2006 L. A. F. Pereira <l@tia.mat.br>
*
* 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.
+ * the Free Software Foundation, version 2 or later.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/modules/devices/sensors.c b/modules/devices/sensors.c
index c9d78ff7..095f0bc4 100644
--- a/modules/devices/sensors.c
+++ b/modules/devices/sensors.c
@@ -1,10 +1,10 @@
/*
* HardInfo - Displays System Information
- * Copyright (C) 2003-2006 Leandro A. F. Pereira <leandro@hardinfo.org>
+ * Copyright (C) 2003-2006 L. A. F. Pereira <l@tia.mat.br>
*
* 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.
+ * the Free Software Foundation, version 2 or later.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -22,12 +22,21 @@
#include "expr.h"
#include "hardinfo.h"
#include "socket.h"
+#include "udisks2_util.h"
+
+#if defined(HAS_LIBSENSORS) && HAS_LIBSENSORS
+#include <sensors/sensors.h>
+#endif
gchar *sensors = NULL;
+gchar *sensor_icons = NULL;
GHashTable *sensor_compute = NULL;
GHashTable *sensor_labels = NULL;
+gboolean hwmon_first_run = TRUE;
+
+static gchar *last_group = NULL;
-static void read_sensor_labels(gchar *driver) {
+static void read_sensor_labels(gchar *devname) {
FILE *conf;
gchar buf[256], *line, *p;
gboolean lock = FALSE;
@@ -55,14 +64,14 @@ static void read_sensor_labels(gchar *driver) {
continue;
} else if (lock && strstr(line, "label")) { /* label lines */
gchar **names = g_strsplit(strstr(line, "label") + 5, " ", 0);
- gchar *name = NULL, *value = NULL;
+ gchar *key = NULL, *value = NULL;
for (i = 0; names[i]; i++) {
if (names[i][0] == '\0')
continue;
- if (!name)
- name = g_strdup(names[i]);
+ if (!key)
+ key = g_strdup_printf("%s/%s", devname, names[i]);
else if (!value)
value = g_strdup(names[i]);
else
@@ -70,7 +79,7 @@ static void read_sensor_labels(gchar *driver) {
}
remove_quotes(value);
- g_hash_table_insert(sensor_labels, name, value);
+ g_hash_table_insert(sensor_labels, key, g_strstrip(value));
g_strfreev(names);
} else if (lock && strstr(line, "ignore")) { /* ignore lines */
@@ -80,19 +89,18 @@ static void read_sensor_labels(gchar *driver) {
while (*p == ' ')
p++;
- g_hash_table_insert(sensor_labels, g_strdup(p), "ignore");
+ g_hash_table_insert(sensor_labels, g_strdup_printf("%s/%s", devname, p), "ignore");
} else if (lock && strstr(line, "compute")) { /* compute lines */
+ strend(line, ',');
gchar **formulas = g_strsplit(strstr(line, "compute") + 7, " ", 0);
- gchar *name = NULL, *formula = NULL;
+ gchar *key = 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]);
+ if (!key)
+ key = g_strdup_printf("%s/%s", devname, formulas[i]);
else if (!formula)
formula = g_strdup(formulas[i]);
else
@@ -100,7 +108,7 @@ static void read_sensor_labels(gchar *driver) {
}
g_strfreev(formulas);
- g_hash_table_insert(sensor_compute, name,
+ g_hash_table_insert(sensor_compute, key,
math_string_to_postfix(formula));
} else if (g_str_has_prefix(line,
"chip")) { /* chip lines (delimiter) */
@@ -110,7 +118,7 @@ static void read_sensor_labels(gchar *driver) {
for (i = 1; chips[i]; i++) {
strend(chips[i], '*');
- if (g_str_has_prefix(chips[i] + 1, driver)) {
+ if (g_str_has_prefix(chips[i] + 1, devname)) {
lock = TRUE;
break;
}
@@ -128,36 +136,59 @@ static void read_sensor_labels(gchar *driver) {
static void add_sensor(const char *type,
const char *sensor,
- const char *driver,
+ const char *parent,
double value,
- const char *unit) {
+ const char *unit,
+ const char *icon) {
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", parent, sensor);
+
+ if (SENSORS_GROUP_BY_TYPE) {
+ // group by type
+ if (g_strcmp0(last_group, type) != 0) {
+ sensors = h_strdup_cprintf("[%s]\n", sensors, type);
+ g_free(last_group);
+ last_group = g_strdup(type);
+ }
+ sensors = h_strdup_cprintf("$%s$%s=%.2f%s|%s\n", sensors,
+ key, sensor, value, unit, parent);
+ }
+ else {
+ // group by device source / driver
+ if (g_strcmp0(last_group, parent) != 0) {
+ sensors = h_strdup_cprintf("[%s]\n", sensors, parent);
+ g_free(last_group);
+ last_group = g_strdup(parent);
+ }
+ sensors = h_strdup_cprintf("$%s$%s=%.2f%s|%s\n", sensors,
+ key, sensor, value, unit, type);
+ }
+
+ if (icon != NULL) {
+ sensor_icons = h_strdup_cprintf("Icon$%s$%s=%s.png\n", sensor_icons,
+ key, sensor, icon);
+ }
- 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) {
+static gchar *get_sensor_label_from_conf(gchar *key) {
gchar *ret;
+ ret = g_hash_table_lookup(sensor_labels, key);
- ret = g_hash_table_lookup(sensor_labels, sensor);
- if (!ret)
- ret = g_strdup(sensor);
- else
- ret = g_strdup(ret);
+ if (ret)
+ return g_strdup(ret);
- return ret;
+ return NULL;
}
-static float adjust_sensor(gchar *name, float value) {
+static float adjust_sensor(gchar *key, float value) {
GSList *postfix;
- postfix = g_hash_table_lookup(sensor_compute, name);
+ postfix = g_hash_table_lookup(sensor_compute, key);
if (!postfix)
return value;
@@ -168,79 +199,137 @@ 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) {
- char *tmp, *driver;
+static char *determine_devname_for_hwmon_path(char *path) {
+ char *tmp, *devname = NULL;
+
+ // device name
+ tmp = g_strdup_printf("%s/name", path);
+ g_file_get_contents(tmp, &devname, NULL, NULL);
+ g_free(tmp);
+ if (devname)
+ return g_strstrip(devname);
+ // fallback: driver name (from driver link)
tmp = g_strdup_printf("%s/device/driver", path);
- driver = g_file_read_link(tmp, NULL);
+ devname = g_file_read_link(tmp, NULL);
g_free(tmp);
- if (driver) {
- tmp = g_path_get_basename(driver);
- g_free(driver);
- driver = tmp;
- } else {
+ if (!devname) {
+ // fallback: device folder name (from device link)
tmp = g_strdup_printf("%s/device", path);
- driver = g_file_read_link(tmp, NULL);
+ devname = g_file_read_link(tmp, NULL);
g_free(tmp);
}
- if (!driver) {
- tmp = g_strdup_printf("%s/name", path);
- if (!g_file_get_contents(tmp, &driver, NULL, NULL)) {
- driver = g_strdup("unknown");
- } else {
- driver = g_strstrip(driver);
- }
- g_free(tmp);
+ if (devname) {
+ tmp = g_path_get_basename(devname);
+ g_free(devname);
+ return tmp;
}
- return driver;
+ return g_strdup("unknown");
}
struct HwmonSensor {
const char *friendly_name;
- const char *path_format;
+ const char *value_file_regex;
+ const char *value_path_format;
+ const char *label_path_format;
const char *key_format;
const char *unit;
const float adjust_ratio;
- const int begin_at;
+ const char *icon;
};
static const struct HwmonSensor hwmon_sensors[] = {
{
- "Fan",
+ "Fan Speed",
+ "^fan([0-9]+)_input$",
"%s/fan%d_input",
+ "%s/fan%d_label",
"fan%d",
- "RPM",
+ " RPM",
1.0,
- 1
+ "fan"
},
{
"Temperature",
+ "^temp([0-9]+)_input$",
"%s/temp%d_input",
+ "%s/temp%d_label",
"temp%d",
"\302\260C",
1000.0,
- 1
+ "therm"
},
{
"Voltage",
+ "^in([0-9]+)_input$",
"%s/in%d_input",
+ "%s/in%d_label",
"in%d",
"V",
1000.0,
- 0
+ "bolt"
+ },
+ {
+ "Current",
+ "^curr([0-9]+)_input$",
+ "%s/curr%d_input",
+ "%s/curr%d_label",
+ "curr%d",
+ " A",
+ 1000.0,
+ "bolt"
+ },
+ {
+ "Power",
+ "^power([0-9]+)_input$",
+ "%s/power%d_input",
+ "%s/power%d_label",
+ "power%d",
+ " W",
+ 1000000.0,
+ "bolt"
+ },
+ {
+ "CPU Voltage",
+ "^cpu([0-9]+)_vid$",
+ "%s/cpu%d_vid",
+ NULL,
+ "cpu%d_vid",
+ " V",
+ 1000.0,
+ "bolt"
},
{ }
};
static const char *hwmon_prefix[] = {"device", "", NULL};
+static gboolean read_raw_hwmon_value(gchar *path_hwmon, const gchar *item_path_format, int item_id, gchar **result){
+ gchar *full_path;
+ gboolean file_result;
+
+ if (item_path_format == NULL)
+ return FALSE;
+
+ full_path = g_strdup_printf(item_path_format, path_hwmon, item_id);
+ file_result = g_file_get_contents(full_path, result, NULL, NULL);
+
+ g_free(full_path);
+
+ return file_result;
+}
+
static void read_sensors_hwmon(void) {
- int hwmon, count;
- gchar *path_hwmon, *path_sensor, *tmp, *driver, *name, *mon;
- const char **prefix;
+ int hwmon, count, min, max;
+ gchar *path_hwmon, *tmp, *devname, *name, *mon, *key;
+ const char **prefix, *entry;
+ GDir *dir;
+ GRegex *regex;
+ GMatchInfo *match_info;
+ GError *err = NULL;
for (prefix = hwmon_prefix; *prefix; prefix++) {
hwmon = 0;
@@ -248,56 +337,92 @@ static void read_sensors_hwmon(void) {
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);
+ devname = determine_devname_for_hwmon_path(path_hwmon);
+ DEBUG("hwmon%d has device=%s", hwmon, devname);
+ if (hwmon_first_run) {
+ read_sensor_labels(devname);
}
+ dir = g_dir_open(path_hwmon, 0, NULL);
+ if (!dir)
+ continue;
+
for (sensor = hwmon_sensors; sensor->friendly_name; sensor++) {
DEBUG("current sensor type=%s", sensor->friendly_name);
+ regex = g_regex_new (sensor->value_file_regex, 0, 0, &err);
+ if (err != NULL){
+ g_free(err);
+ err = NULL;
+ continue;
+ }
- 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;
+ g_dir_rewind(dir);
+ min = 999;
+ max = -1;
+
+ while ((entry = g_dir_read_name(dir))) {
+ g_regex_match(regex, entry, 0, &match_info);
+ if (g_match_info_matches(match_info)) {
+ tmp = g_match_info_fetch(match_info, 1);
+ count = atoi(tmp);
+ g_free (tmp);
+
+ if (count < min){
+ min = count;
+ }
+ if (count > max){
+ max = count;
+ }
+ }
+ g_match_info_free(match_info);
+ }
+ g_regex_unref(regex);
+
+ for (count = min; count <= max; count++) {
+ if (!read_raw_hwmon_value(path_hwmon, sensor->value_path_format, count, &tmp)) {
+ continue;
}
mon = g_strdup_printf(sensor->key_format, count);
- name = get_sensor_label(mon);
+ key = g_strdup_printf("%s/%s", devname, mon);
+ name = get_sensor_label_from_conf(key);
+ if (name == NULL){
+ if (read_raw_hwmon_value(path_hwmon, sensor->label_path_format, count, &name)){
+ name = g_strchomp(name);
+ }
+ else{
+ name = g_strdup(mon);
+ }
+ }
+
if (!g_str_equal(name, "ignore")) {
- float adjusted = adjust_sensor(mon,
+ float adjusted = adjust_sensor(key,
atof(tmp) / sensor->adjust_ratio);
add_sensor(sensor->friendly_name,
name,
- driver,
+ devname,
adjusted,
- sensor->unit);
+ sensor->unit,
+ sensor->icon);
}
g_free(tmp);
g_free(mon);
+ g_free(key);
g_free(name);
- g_free(path_sensor);
}
}
+ g_dir_close(dir);
g_free(path_hwmon);
- g_free(driver);
+ g_free(devname);
path_hwmon = get_sensor_path(++hwmon, *prefix);
}
-
g_free(path_hwmon);
}
+ hwmon_first_run = FALSE;
}
static void read_sensors_acpi(void) {
@@ -323,7 +448,8 @@ static void read_sensors_acpi(void) {
entry,
"ACPI Thermal Zone",
temperature,
- "\302\260C");
+ "\302\260C",
+ "therm");
}
}
@@ -332,6 +458,78 @@ static void read_sensors_acpi(void) {
}
}
+// Sensors for Apple PowerPC devices using Windfarm driver.
+struct WindfarmSensorType {
+ const char *type;
+ const char *icon;
+ const char *file_regex;
+ const char *unit;
+ gboolean with_decimal_p;
+};
+static const struct WindfarmSensorType windfarm_sensor_types[] = {
+ {"Fan", "fan", "^[a-z-]+-fan(-[0-9]+)?$", " RPM", FALSE},
+ {"Temperature", "therm", "^[a-z-]+-temp(-[0-9]+)?$", "\302\260C", TRUE},
+ {"Power", "bolt", "^[a-z-]+-power(-[0-9]+)?$", " W", TRUE},
+ {"Current", "bolt", "^[a-z-]+-current(-[0-9]+)?$", " A", TRUE},
+ {"Voltage", "bolt", "^[a-z-]+-voltage(-[0-9]+)?$", " V", TRUE},
+ { }
+};
+static void read_sensors_windfarm(void)
+{
+ const gchar *path_wf = "/sys/devices/platform/windfarm.0";
+ GDir *wf;
+ gchar *tmp = NULL;
+ gint v1, v2;
+ double value;
+
+ wf = g_dir_open(path_wf, 0, NULL);
+ if (wf) {
+ GRegex *regex;
+ GError *err = NULL;
+ const gchar *entry;
+ const struct WindfarmSensorType *sensor;
+
+ for (sensor = windfarm_sensor_types; sensor->type; sensor++) {
+ DEBUG("current windfarm sensor type=%s", sensor->type);
+ regex = g_regex_new(sensor->file_regex, 0, 0, &err);
+ if (err != NULL) {
+ g_free(err);
+ err = NULL;
+ continue;
+ }
+
+ g_dir_rewind(wf);
+
+ while ((entry = g_dir_read_name(wf))) {
+ if (g_regex_match(regex, entry, 0, NULL)) {
+ gchar *path = g_strdup_printf("%s/%s", path_wf, entry);
+ if (g_file_get_contents(path, &tmp, NULL, NULL)) {
+
+ if (sensor->with_decimal_p) {
+ // format source
+ // https://elixir.free-electrons.com/linux/v5.14/source/drivers/macintosh/windfarm_core.c#L301
+ sscanf(tmp, "%d.%03d", &v1, &v2);
+ value = v1 + (v2 / 1000.0);
+ } else {
+ value = (double)atoi(tmp);
+ }
+ g_free(tmp);
+
+ tmp = g_strdup(entry);
+ add_sensor(sensor->type, g_strdelimit(tmp, "-", ' '),
+ "windfarm", value, sensor->unit,
+ sensor->icon);
+ g_free(tmp);
+ }
+ g_free(path);
+ }
+ }
+ g_regex_unref(regex);
+ }
+ g_dir_close(wf);
+ }
+}
+
static void read_sensors_sys_thermal(void) {
const gchar *path_tz = "/sys/class/thermal";
@@ -355,7 +553,8 @@ static void read_sensors_sys_thermal(void) {
entry,
"thermal",
temperature / 1000.0,
- "\302\260C");
+ "\302\260C",
+ "therm");
g_free(contents);
}
@@ -379,7 +578,8 @@ static void read_sensors_omnibook(void) {
"CPU",
"omnibook",
temperature,
- "\302\260C\n");
+ "\302\260C",
+ "therm");
g_free(contents);
}
@@ -401,7 +601,7 @@ static void read_sensors_hddtemp(void) {
gchar **disks;
int i;
- disks = g_strsplit(buffer, "\n", 0);
+ disks = g_strsplit(buffer, "||", 0);
for (i = 0; disks[i]; i++) {
gchar **fields = g_strsplit(disks[i] + 1, "|", 5);
@@ -412,12 +612,13 @@ static void read_sensors_hddtemp(void) {
* 3 -> C
*/
const gchar *unit = strcmp(fields[3], "C")
- ? "\302\260C" : "\302\260F";
- add_sensor("Hard Drive",
+ ? "\302\260F" : "\302\260C";
+ add_sensor("Drive Temperature",
fields[1],
"hddtemp",
atoi(fields[2]),
- unit);
+ unit,
+ "therm");
g_strfreev(fields);
}
@@ -426,28 +627,144 @@ static void read_sensors_hddtemp(void) {
}
}
+static void read_sensors_udisks2(void) {
+ GSList *node;
+ GSList *temps;
+ udiskt *disk;
+
+ temps = get_udisks2_temps();
+ if (temps == NULL)
+ return;
+
+ for (node = temps; node != NULL; node = node->next) {
+ disk = (udiskt *)node->data;
+ add_sensor("Drive Temperature",
+ disk->drive,
+ "udisks2",
+ disk->temperature,
+ "\302\260C",
+ "therm");
+ udiskt_free(disk);
+ }
+ g_slist_free(temps);
+}
+
+#if HAS_LIBSENSORS
+static const struct libsensors_feature_type {
+ const char *type_name;
+ const char *icon;
+ const char *unit;
+ sensors_subfeature_type input;
+} libsensors_feature_types[SENSORS_FEATURE_MAX] = {
+ [SENSORS_FEATURE_FAN] = {"Fan", "fan", "RPM",
+ SENSORS_SUBFEATURE_FAN_INPUT},
+ [SENSORS_FEATURE_TEMP] = {"Temperature", "therm", "\302\260C",
+ SENSORS_SUBFEATURE_TEMP_INPUT},
+ [SENSORS_FEATURE_POWER] = {"Power", "bolt", "W",
+ SENSORS_SUBFEATURE_POWER_INPUT},
+ [SENSORS_FEATURE_CURR] = {"Current", "bolt", "A",
+ SENSORS_SUBFEATURE_CURR_INPUT},
+ [SENSORS_FEATURE_IN] = {"Voltage", "bolt", "V",
+ SENSORS_SUBFEATURE_IN_INPUT},
+ [SENSORS_FEATURE_VID] = {"CPU Voltage", "bolt", "V",
+ SENSORS_SUBFEATURE_VID},
+};
+static gboolean libsensors_initialized;
+
+static int read_sensors_libsensors(void) {
+ char chip_name_buf[512];
+ const sensors_chip_name *name;
+ int chip_nr = 0;
+ int added_sensors = 0;
+
+ if (!libsensors_initialized)
+ return 0;
+
+ while ((name = sensors_get_detected_chips(NULL, &chip_nr))) {
+ const struct sensors_feature *feat;
+ int feat_nr = 0;
+
+ sensors_snprintf_chip_name(chip_name_buf, 512, name);
+
+ while ((feat = sensors_get_features(name, &feat_nr))) {
+ const struct libsensors_feature_type *feat_descr;
+ const struct sensors_subfeature *subfeat;
+ double value;
+
+ feat_descr = &libsensors_feature_types[feat->type];
+ if (!feat_descr->type_name)
+ continue;
+
+ subfeat = sensors_get_subfeature(name, feat, feat_descr->input);
+ if (!subfeat)
+ continue;
+
+ if (!sensors_get_value(name, subfeat->number, &value)) {
+ char *label = sensors_get_label(name, feat);
+ gchar *label_with_chip = g_strdup_printf("%s (%s)", label, chip_name_buf);
+
+ add_sensor(feat_descr->type_name,
+ label_with_chip,
+ "libsensors",
+ value,
+ feat_descr->unit,
+ feat_descr->icon);
+
+ free(label_with_chip);
+ free(label);
+
+ added_sensors++;
+ }
+ }
+ }
+
+ return added_sensors;
+}
+#else
+static int read_sensors_libsensors(void)
+{
+ return 0;
+}
+#endif
+
void scan_sensors_do(void) {
g_free(sensors);
+ g_free(sensor_icons);
+ g_free(last_group);
+ last_group = NULL;
sensors = g_strdup("");
+ sensor_icons = g_strdup("");
g_free(lginterval);
lginterval = g_strdup("");
- read_sensors_hwmon();
- read_sensors_acpi();
- read_sensors_sys_thermal();
- read_sensors_omnibook();
+ if (read_sensors_libsensors() == 0) {
+ read_sensors_hwmon();
+ read_sensors_acpi();
+ read_sensors_sys_thermal();
+ read_sensors_omnibook();
+ }
+
+ read_sensors_windfarm();
read_sensors_hddtemp();
- /* FIXME: Add support for ibm acpi and more sensors */
+ read_sensors_udisks2();
}
-void sensors_init(void) {
+void sensor_init(void) {
+#if HAS_LIBSENSORS
+ libsensors_initialized = sensors_init(NULL) == 0;
+#endif
+
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 sensor_shutdown(void) {
+#if HAS_LIBSENSORS
+ sensors_cleanup();
+#endif
+
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 9da2f9b0..a5ce3e0a 100644
--- a/modules/devices/sh/processor.c
+++ b/modules/devices/sh/processor.c
@@ -1,10 +1,10 @@
/*
* HardInfo - Displays System Information
- * Copyright (C) 2003-2006 Leandro A. F. Pereira <leandro@hardinfo.org>
+ * Copyright (C) 2003-2006 L. A. F. Pereira <l@tia.mat.br>
*
* 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.
+ * the Free Software Foundation, version 2 or later.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/modules/devices/sparc/processor.c b/modules/devices/sparc/processor.c
index 32c7aa94..76f4b0e0 100644
--- a/modules/devices/sparc/processor.c
+++ b/modules/devices/sparc/processor.c
@@ -1,10 +1,10 @@
/*
* HardInfo - Displays System Information
- * Copyright (C) 2003-2006 Leandro A. F. Pereira <leandro@hardinfo.org>
+ * Copyright (C) 2003-2006 L. A. F. Pereira <l@tia.mat.br>
*
* 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.
+ * the Free Software Foundation, version 2 or later.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
diff --git a/modules/devices/spd-decode.c b/modules/devices/spd-decode.c
index 2db4895b..511504b2 100644
--- a/modules/devices/spd-decode.c
+++ b/modules/devices/spd-decode.c
@@ -1,6 +1,8 @@
/*
- * spd-decode.c
- * Copyright (c) 2010 Leandro A. F. Pereira
+ * spd-decode.c, spd-vendors.c
+ * Copyright (c) 2010 L. A. F. Pereira
+ * modified by Ondrej ÄŒerman (2019)
+ * modified by Burt P. (2019)
*
* Based on decode-dimms.pl
* Copyright 1998, 1999 Philip Edelbrock <phil@netroedge.com>
@@ -27,602 +29,91 @@
#include <stdio.h>
#include <sys/stat.h>
-#include "hardinfo.h"
#include "devices.h"
+#include "hardinfo.h"
+
+gboolean spd_no_driver = FALSE;
+gboolean spd_no_support = FALSE;
+gboolean spd_ddr4_partial_data = FALSE;
+int spd_ram_types = 0; /* bits using enum RamType */
typedef enum {
- UNKNOWN,
- DIRECT_RAMBUS,
- RAMBUS,
- FPM_DRAM,
- EDO,
- PIPELINED_NIBBLE,
- SDR_SDRAM,
- MULTIPLEXED_ROM,
- DDR_SGRAM,
- DDR_SDRAM,
- DDR2_SDRAM,
- DDR3_SDRAM
+ UNKNOWN = 0,
+ DIRECT_RAMBUS = 1,
+ RAMBUS = 2,
+ FPM_DRAM = 3,
+ EDO = 4,
+ PIPELINED_NIBBLE = 5,
+ SDR_SDRAM = 6,
+ MULTIPLEXED_ROM = 7,
+ DDR_SGRAM = 8,
+ DDR_SDRAM = 9,
+ DDR2_SDRAM = 10,
+ DDR3_SDRAM = 11,
+ DDR4_SDRAM = 12,
+ N_RAM_TYPES = 13
} RamType;
-char *spd_info = NULL;
-
-static const char *ram_types[] = {
- "Unknown",
- "Direct Rambus",
- "Rambus",
- "FPM DRAM",
- "EDO",
- "Pipelined Nibble",
- "SDR SDRAM",
- "Multiplexed ROM",
- "DDR SGRAM",
- "DDR SDRAM",
- "DDR2 SDRAM",
- "DDR3 SDRAM"
-};
+static const char *ram_types[] = {"Unknown", "Direct Rambus", "Rambus", "FPM DRAM",
+ "EDO", "Pipelined Nibble", "SDR SDRAM", "Multiplexed ROM",
+ "DDR SGRAM", "DDR SDRAM", "DDR2 SDRAM", "DDR3 SDRAM",
+ "DDR4 SDRAM"};
+#define GET_RAM_TYPE_STR(rt) (ram_types[(rt < N_RAM_TYPES) ? rt : 0])
-static const char *vendors1[] = { "AMD", "AMI", "Fairchild", "Fujitsu",
- "GTE", "Harris", "Hitachi", "Inmos",
- "Intel", "I.T.T.", "Intersil",
- "Monolithic Memories",
- "Mostek",
- "Freescale (former Motorola)",
- "National", "NEC",
- "RCA", "Raytheon",
- "Conexant (Rockwell)", "Seeq",
- "NXP (former Signetics, Philips Semi.)",
- "Synertek",
- "Texas Instruments", "Toshiba",
- "Xicor", "Zilog", "Eurotechnique",
- "Mitsubishi",
- "Lucent (AT&T)", "Exel", "Atmel",
- "SGS/Thomson",
- "Lattice Semi.", "NCR",
- "Wafer Scale Integration", "IBM",
- "Tristar", "Visic",
- "Intl. CMOS Technology", "SSSI",
- "MicrochipTechnology", "Ricoh Ltd.",
- "VLSI", "Micron Technology",
- "Hyundai Electronics",
- "OKI Semiconductor", "ACTEL",
- "Sharp",
- "Catalyst", "Panasonic", "IDT",
- "Cypress",
- "DEC", "LSI Logic",
- "Zarlink (former Plessey)", "UTMC",
- "Thinking Machine", "Thomson CSF",
- "Integrated CMOS (Vertex)",
- "Honeywell",
- "Tektronix", "Sun Microsystems",
- "SST", "ProMos/Mosel Vitelic",
- "Infineon (former Siemens)",
- "Macronix", "Xerox", "Plus Logic",
- "SunDisk", "Elan Circuit Tech.",
- "European Silicon Str.",
- "Apple Computer",
- "Xilinx", "Compaq",
- "Protocol Engines", "SCI",
- "Seiko Instruments", "Samsung",
- "I3 Design System", "Klic",
- "Crosspoint Solutions",
- "Alliance Semiconductor", "Tandem",
- "Hewlett-Packard",
- "Intg. Silicon Solutions",
- "Brooktree", "New Media",
- "MHS Electronic",
- "Performance Semi.",
- "Winbond Electronic",
- "Kawasaki Steel",
- "Bright Micro",
- "TECMAR", "Exar", "PCMCIA",
- "LG Semi (former Goldstar)",
- "Northern Telecom", "Sanyo",
- "Array Microsystems",
- "Crystal Semiconductor",
- "Analog Devices", "PMC-Sierra",
- "Asparix", "Convex Computer",
- "Quality Semiconductor",
- "Nimbus Technology", "Transwitch",
- "Micronas (ITT Intermetall)",
- "Cannon", "Altera", "NEXCOM",
- "QUALCOMM",
- "Sony", "Cray Research",
- "AMS(Austria Micro)", "Vitesse",
- "Aster Electronics",
- "Bay Networks (Synoptic)",
- "Zentrum or ZMD",
- "TRW",
- "Thesys", "Solbourne Computer",
- "Allied-Signal", "Dialog",
- "Media Vision",
- "Level One Communication"
-};
+#include "spd-vendors.c"
-static const char *vendors2[] = { "Cirrus Logic",
- "National Instruments",
- "ILC Data Device",
- "Alcatel Mietec",
- "Micro Linear",
- "Univ. of NC",
- "JTAG Technologies",
- "BAE Systems",
- "Nchip",
- "Galileo Tech",
- "Bestlink Systems",
- "Graychip",
- "GENNUM",
- "VideoLogic",
- "Robert Bosch",
- "Chip Express",
- "DATARAM",
- "United Microelec Corp.",
- "TCSI",
- "Smart Modular",
- "Hughes Aircraft",
- "Lanstar Semiconductor",
- "Qlogic", "Kingston",
- "Music Semi",
- "Ericsson Components",
- "SpaSE",
- "Eon Silicon Devices",
- "Programmable Micro Corp",
- "DoD",
- "Integ. Memories Tech.",
- "Corollary Inc.",
- "Dallas Semiconductor",
- "Omnivision",
- "EIV(Switzerland)",
- "Novatel Wireless",
- "Zarlink (former Mitel)",
- "Clearpoint",
- "Cabletron",
- "STEC (former Silicon Technology)",
- "Vanguard",
- "Hagiwara Sys-Com",
- "Vantis", "Celestica",
- "Century",
- "Hal Computers",
- "Rohm Company Ltd.",
- "Juniper Networks",
- "Libit Signal Processing",
- "Mushkin Enhanced Memory",
- "Tundra Semiconductor",
- "Adaptec Inc.",
- "LightSpeed Semi.",
- "ZSP Corp.",
- "AMIC Technology",
- "Adobe Systems",
- "Dynachip",
- "PNY Electronics",
- "Newport Digital",
- "MMC Networks",
- "T Square",
- "Seiko Epson",
- "Broadcom",
- "Viking Components",
- "V3 Semiconductor",
- "Flextronics (former Orbit)",
- "Suwa Electronics",
- "Transmeta",
- "Micron CMS",
- "American Computer & Digital Components Inc",
- "Enhance 3000 Inc",
- "Tower Semiconductor",
- "CPU Design",
- "Price Point",
- "Maxim Integrated Product",
- "Tellabs",
- "Centaur Technology",
- "Unigen Corporation",
- "Transcend Information",
- "Memory Card Technology",
- "CKD Corporation Ltd.",
- "Capital Instruments, Inc.",
- "Aica Kogyo, Ltd.",
- "Linvex Technology",
- "MSC Vertriebs GmbH",
- "AKM Company, Ltd.",
- "Dynamem, Inc.",
- "NERA ASA",
- "GSI Technology",
- "Dane-Elec (C Memory)",
- "Acorn Computers",
- "Lara Technology",
- "Oak Technology, Inc.",
- "Itec Memory",
- "Tanisys Technology",
- "Truevision",
- "Wintec Industries",
- "Super PC Memory",
- "MGV Memory",
- "Galvantech",
- "Gadzoox Nteworks",
- "Multi Dimensional Cons.",
- "GateField",
- "Integrated Memory System",
- "Triscend", "XaQti",
- "Goldenram",
- "Clear Logic",
- "Cimaron Communications",
- "Nippon Steel Semi. Corp.",
- "Advantage Memory",
- "AMCC",
- "LeCroy",
- "Yamaha Corporation",
- "Digital Microwave",
- "NetLogic Microsystems",
- "MIMOS Semiconductor",
- "Advanced Fibre",
- "BF Goodrich Data.",
- "Epigram",
- "Acbel Polytech Inc.",
- "Apacer Technology",
- "Admor Memory",
- "FOXCONN",
- "Quadratics Superconductor",
- "3COM",
-};
+struct dmi_mem_socket;
+typedef struct {
+ unsigned char bytes[512];
+ char dev[32]; /* %1d-%04d\0 */
+ const char *spd_driver;
+ int spd_size;
-static const char *vendors3[] = { "Camintonn Corporation", "ISOA Incorporated",
- "Agate Semiconductor", "ADMtek Incorporated",
- "HYPERTEC", "Adhoc Technologies", "MOSAID Technologies",
- "Ardent Technologies",
- "Switchcore", "Cisco Systems, Inc.", "Allayer Technologies",
- "WorkX AG",
- "Oasis Semiconductor", "Novanet Semiconductor", "E-M Solutions",
- "Power General",
- "Advanced Hardware Arch.", "Inova Semiconductors GmbH", "Telocity",
- "Delkin Devices",
- "Symagery Microsystems", "C-Port Corporation",
- "SiberCore Technologies", "Southland Microsystems",
- "Malleable Technologies", "Kendin Communications",
- "Great Technology Microcomputer", "Sanmina Corporation",
- "HADCO Corporation", "Corsair", "Actrans System Inc.",
- "ALPHA Technologies",
- "Silicon Laboratories, Inc. (Cygnal)", "Artesyn Technologies",
- "Align Manufacturing", "Peregrine Semiconductor",
- "Chameleon Systems", "Aplus Flash Technology", "MIPS Technologies",
- "Chrysalis ITS",
- "ADTEC Corporation", "Kentron Technologies", "Win Technologies",
- "Tachyon Semiconductor (former ASIC Designs Inc.)",
- "Extreme Packet Devices", "RF Micro Devices", "Siemens AG",
- "Sarnoff Corporation",
- "Itautec Philco SA", "Radiata Inc.", "Benchmark Elect. (AVEX)",
- "Legend",
- "SpecTek Incorporated", "Hi/fn", "Enikia Incorporated",
- "SwitchOn Networks",
- "AANetcom Incorporated", "Micro Memory Bank", "ESS Technology",
- "Virata Corporation",
- "Excess Bandwidth", "West Bay Semiconductor", "DSP Group",
- "Newport Communications",
- "Chip2Chip Incorporated", "Phobos Corporation",
- "Intellitech Corporation", "Nordic VLSI ASA",
- "Ishoni Networks", "Silicon Spice", "Alchemy Semiconductor",
- "Agilent Technologies",
- "Centillium Communications", "W.L. Gore", "HanBit Electronics",
- "GlobeSpan",
- "Element 14", "Pycon", "Saifun Semiconductors", "Sibyte, Incorporated",
- "MetaLink Technologies", "Feiya Technology", "I & C Technology",
- "Shikatronics",
- "Elektrobit", "Megic", "Com-Tier", "Malaysia Micro Solutions",
- "Hyperchip", "Gemstone Communications", "Anadigm (former Anadyne)",
- "3ParData",
- "Mellanox Technologies", "Tenx Technologies", "Helix AG", "Domosys",
- "Skyup Technology", "HiNT Corporation", "Chiaro",
- "MDT Technologies GmbH (former MCI Computer GMBH)",
- "Exbit Technology A/S", "Integrated Technology Express", "AVED Memory",
- "Legerity",
- "Jasmine Networks", "Caspian Networks", "nCUBE",
- "Silicon Access Networks",
- "FDK Corporation", "High Bandwidth Access", "MultiLink Technology",
- "BRECIS",
- "World Wide Packets", "APW", "Chicory Systems", "Xstream Logic",
- "Fast-Chip", "Zucotto Wireless", "Realchip", "Galaxy Power",
- "eSilicon", "Morphics Technology", "Accelerant Networks",
- "Silicon Wave",
- "SandCraft", "Elpida"
-};
+ RamType type;
-static const char *vendors4[] = { "Solectron", "Optosys Technologies",
- "Buffalo (former Melco)",
- "TriMedia Technologies",
- "Cyan Technologies", "Global Locate",
- "Optillion",
- "Terago Communications",
- "Ikanos Communications",
- "Princeton Technology",
- "Nanya Technology",
- "Elite Flash Storage",
- "Mysticom", "LightSand Communications",
- "ATI Technologies",
- "Agere Systems",
- "NeoMagic", "AuroraNetics", "Golden Empire",
- "Mushkin",
- "Tioga Technologies", "Netlist", "TeraLogic",
- "Cicada Semiconductor",
- "Centon Electronics", "Tyco Electronics",
- "Magis Works", "Zettacom",
- "Cogency Semiconductor", "Chipcon AS",
- "Aspex Technology",
- "F5 Networks",
- "Programmable Silicon Solutions",
- "ChipWrights",
- "Acorn Networks",
- "Quicklogic",
- "Kingmax Semiconductor", "BOPS", "Flasys",
- "BitBlitz Communications",
- "eMemory Technology", "Procket Networks",
- "Purple Ray",
- "Trebia Networks",
- "Delta Electronics", "Onex Communications",
- "Ample Communications",
- "Memory Experts Intl",
- "Astute Networks", "Azanda Network Devices",
- "Dibcom", "Tekmos",
- "API NetWorks", "Bay Microsystems",
- "Firecron Ltd",
- "Resonext Communications",
- "Tachys Technologies", "Equator Technology",
- "Concept Computer",
- "SILCOM",
- "3Dlabs", "c't Magazine", "Sanera Systems",
- "Silicon Packets",
- "Viasystems Group", "Simtek",
- "Semicon Devices Singapore",
- "Satron Handelsges",
- "Improv Systems", "INDUSYS GmbH", "Corrent",
- "Infrant Technologies",
- "Ritek Corp", "empowerTel Networks",
- "Hypertec",
- "Cavium Networks",
- "PLX Technology", "Massana Design",
- "Intrinsity",
- "Valence Semiconductor",
- "Terawave Communications",
- "IceFyre Semiconductor", "Primarion",
- "Picochip Designs Ltd",
- "Silverback Systems",
- "Jade Star Technologies",
- "Pijnenburg Securealink",
- "TakeMS International AG",
- "Cambridge Silicon Radio",
- "Swissbit", "Nazomi Communications",
- "eWave System",
- "Rockwell Collins", "Picocel Co., Ltd.",
- "Alphamosaic Ltd",
- "Sandburst",
- "SiCon Video", "NanoAmp Solutions",
- "Ericsson Technology",
- "PrairieComm",
- "Mitac International", "Layer N Networks",
- "MtekVision",
- "Allegro Networks",
- "Marvell Semiconductors",
- "Netergy Microelectronic", "NVIDIA",
- "Internet Machines",
- "Peak Electronics",
- "Litchfield Communication",
- "Accton Technology",
- "Teradiant Networks",
- "Europe Technologies", "Cortina Systems",
- "RAM Components",
- "Raqia Networks",
- "ClearSpeed", "Matsushita Battery",
- "Xelerated",
- "SimpleTech",
- "Utron Technology", "Astec International",
- "AVM gmbH",
- "Redux Communications",
- "Dot Hill Systems", "TeraChip"
-};
+ int vendor_bank;
+ int vendor_index;
+ const char *vendor_str;
+ const Vendor *vendor;
-static const char *vendors5[] = { "T-RAM Incorporated",
- "Innovics Wireless", "Teknovus", "KeyEye Communications",
- "Runcom Technologies", "RedSwitch", "Dotcast",
- "Silicon Mountain Memory",
- "Signia Technologies", "Pixim", "Galazar Networks",
- "White Electronic Designs",
- "Patriot Scientific", "Neoaxiom Corporation", "3Y Power Technology",
- "Europe Technologies",
- "Potentia Power Systems", "C-guys Incorporated",
- "Digital Communications Technology Incorporated",
- "Silicon-Based Technology",
- "Fulcrum Microsystems", "Positivo Informatica Ltd",
- "XIOtech Corporation", "PortalPlayer",
- "Zhiying Software", "Direct2Data", "Phonex Broadband",
- "Skyworks Solutions",
- "Entropic Communications", "Pacific Force Technology", "Zensys A/S",
- "Legend Silicon Corp.",
- "sci-worx GmbH", "SMSC (former Oasis Silicon Systems)",
- "Renesas Technology", "Raza Microelectronics",
- "Phyworks", "MediaTek", "Non-cents Productions", "US Modular",
- "Wintegra Ltd", "Mathstar", "StarCore", "Oplus Technologies",
- "Mindspeed", "Just Young Computer", "Radia Communications", "OCZ",
- "Emuzed", "LOGIC Devices", "Inphi Corporation", "Quake Technologies",
- "Vixel", "SolusTek", "Kongsberg Maritime", "Faraday Technology",
- "Altium Ltd.", "Insyte", "ARM Ltd.", "DigiVision",
- "Vativ Technologies", "Endicott Interconnect Technologies", "Pericom",
- "Bandspeed",
- "LeWiz Communications", "CPU Technology", "Ramaxel Technology",
- "DSP Group",
- "Axis Communications", "Legacy Electronics", "Chrontel",
- "Powerchip Semiconductor",
- "MobilEye Technologies", "Excel Semiconductor", "A-DATA Technology",
- "VirtualDigm",
- "G Skill Intl", "Quanta Computer", "Yield Microelectronics",
- "Afa Technologies",
- "KINGBOX Technology Co. Ltd.", "Ceva", "iStor Networks",
- "Advance Modules",
- "Microsoft", "Open-Silicon", "Goal Semiconductor",
- "ARC International",
- "Simmtec", "Metanoia", "Key Stream", "Lowrance Electronics",
- "Adimos", "SiGe Semiconductor", "Fodus Communications",
- "Credence Systems Corp.",
- "Genesis Microchip Inc.", "Vihana, Inc.", "WIS Technologies",
- "GateChange Technologies",
- "High Density Devices AS", "Synopsys", "Gigaram",
- "Enigma Semiconductor Inc.",
- "Century Micro Inc.", "Icera Semiconductor",
- "Mediaworks Integrated Systems", "O'Neil Product Development",
- "Supreme Top Technology Ltd.", "MicroDisplay Corporation",
- "Team Group Inc.", "Sinett Corporation",
- "Toshiba Corporation", "Tensilica", "SiRF Technology", "Bacoc Inc.",
- "SMaL Camera Technologies", "Thomson SC", "Airgo Networks",
- "Wisair Ltd.",
- "SigmaTel", "Arkados", "Compete IT gmbH Co. KG",
- "Eudar Technology Inc.",
- "Focus Enhancements", "Xyratex"
-};
+ int dram_vendor_bank;
+ int dram_vendor_index;
+ const char *dram_vendor_str;
+ const Vendor *dram_vendor;
-static const char *vendors6[] = { "Specular Networks",
- "Patriot Memory",
- "U-Chip Technology Corp.",
- "Silicon Optix",
- "Greenfield Networks",
- "CompuRAM GmbH", "Stargen, Inc.",
- "NetCell Corporation",
- "Excalibrus Technologies Ltd",
- "SCM Microsystems",
- "Xsigo Systems, Inc.",
- "CHIPS & Systems Inc",
- "Tier 1 Multichip Solutions",
- "CWRL Labs", "Teradici",
- "Gigaram, Inc.",
- "g2 Microsystems",
- "PowerFlash Semiconductor",
- "P.A. Semi, Inc.",
- "NovaTech Solutions, S.A.",
- "c2 Microsystems, Inc.",
- "Level5 Networks",
- "COS Memory AG",
- "Innovasic Semiconductor",
- "02IC Co. Ltd", "Tabula, Inc.",
- "Crucial Technology",
- "Chelsio Communications",
- "Solarflare Communications",
- "Xambala Inc.", "EADS Astrium",
- "ATO Semicon Co. Ltd.",
- "Imaging Works, Inc.",
- "Astute Networks, Inc.", "Tzero",
- "Emulex",
- "Power-One", "Pulse~LINK Inc.",
- "Hon Hai Precision Industry",
- "White Rock Networks Inc.",
- "Telegent Systems USA, Inc.",
- "Atrua Technologies, Inc.",
- "Acbel Polytech Inc.",
- "eRide Inc.",
- "ULi Electronics Inc.",
- "Magnum Semiconductor Inc.",
- "neoOne Technology, Inc.",
- "Connex Technology, Inc.",
- "Stream Processors, Inc.",
- "Focus Enhancements",
- "Telecis Wireless, Inc.",
- "uNav Microelectronics",
- "Tarari, Inc.", "Ambric, Inc.",
- "Newport Media, Inc.", "VMTS",
- "Enuclia Semiconductor, Inc.",
- "Virtium Technology Inc.",
- "Solid State System Co., Ltd.",
- "Kian Tech LLC",
- "Artimi",
- "Power Quotient International",
- "Avago Technologies",
- "ADTechnology", "Sigma Designs",
- "SiCortex, Inc.",
- "Ventura Technology Group",
- "eASIC", "M.H.S. SAS",
- "Micro Star International",
- "Rapport Inc.",
- "Makway International",
- "Broad Reach Engineering Co.",
- "Semiconductor Mfg Intl Corp",
- "SiConnect", "FCI USA Inc.",
- "Validity Sensors",
- "Coney Technology Co. Ltd.",
- "Spans Logic", "Neterion Inc.",
- "Qimonda",
- "New Japan Radio Co. Ltd.",
- "Velogix", "Montalvo Systems",
- "iVivity Inc.",
- "Walton Chaintech",
- "AENEON",
- "Lorom Industrial Co. Ltd.",
- "Radiospire Networks",
- "Sensio Technologies, Inc.",
- "Nethra Imaging",
- "Hexon Technology Pte Ltd",
- "CompuStocx (CSX)",
- "Methode Electronics, Inc.",
- "Connect One Ltd.",
- "Opulan Technologies",
- "Septentrio NV",
- "Goldenmars Technology Inc.",
- "Kreton Corporation",
- "Cochlear Ltd.",
- "Altair Semiconductor",
- "NetEffect, Inc.",
- "Spansion, Inc.",
- "Taiwan Semiconductor Mfg",
- "Emphany Systems Inc.",
- "ApaceWave Technologies",
- "Mobilygen Corporation", "Tego",
- "Cswitch Corporation",
- "Haier (Beijing) IC Design Co.",
- "MetaRAM",
- "Axel Electronics Co. Ltd.",
- "Tilera Corporation",
- "Aquantia",
- "Vivace Semiconductor",
- "Redpine Signals", "Octalica",
- "InterDigital Communications",
- "Avant Technology",
- "Asrock, Inc.", "Availink",
- "Quartics, Inc.",
- "Element CXI",
- "Innovaciones Microelectronicas",
- "VeriSilicon Microelectronics",
- "W5 Networks"
-};
+ char partno[32];
+ const char *form_factor;
+ char type_detail[256];
-static const char *vendors7[] = { "MOVEKING", "Mavrix Technology, Inc.",
- "CellGuide Ltd.", "Faraday Technology",
- "Diablo Technologies, Inc.", "Jennic", "Octasic",
- "Molex Incorporated",
- "3Leaf Networks",
- "Bright Micron Technology", "Netxen", "NextWave Broadband Inc.",
- "DisplayLink", "ZMOS Technology",
- "Tec-Hill", "Multigig, Inc.", "Amimon", "Euphonic Technologies, Inc.",
- "BRN Phoenix",
- "InSilica", "Ember Corporation", "Avexir Technologies Corporation",
- "Echelon Corporation",
- "Edgewater Computer Systems", "XMOS Semiconductor Ltd.",
- "GENUSION, Inc.", "Memory Corp NV",
- "SiliconBlue Technologies", "Rambus Inc."
-};
+ dmi_mem_size size_MiB;
-static const char **vendors[7] = { vendors1, vendors2, vendors3, vendors4, vendors5, vendors6,
- vendors7
-};
+ int spd_rev_major; // bytes[1] >> 4
+ int spd_rev_minor; // bytes[1] & 0xf
+
+ int week, year;
+
+ gboolean ddr4_no_ee1004;
+
+ struct dmi_mem_socket *dmi_socket;
+ int match_score;
+} spd_data;
+
+#define spd_data_new() g_new0(spd_data, 1)
+void spd_data_free(spd_data *s) { g_free(s); }
/*
* We consider that no data was written to this area of the SPD EEPROM if
* all bytes read 0x00 or all bytes read 0xff
*/
-static int spd_written(unsigned char *bytes, int len)
-{
+static int spd_written(unsigned char *bytes, int len) {
do {
- if (*bytes == 0x00 || *bytes == 0xFF)
- return 1;
+ if (*bytes == 0x00 || *bytes == 0xFF) return 1;
} while (--len && bytes++);
return 0;
}
-static int parity(int value)
-{
+static int parity(int value) {
value ^= value >> 16;
value ^= value >> 8;
value ^= value >> 4;
@@ -631,235 +122,152 @@ static int parity(int value)
return (0x6996 >> value) & 1;
}
-static void decode_sdr_module_size(unsigned char *bytes, int *size)
-{
- int i, k = 0;
+static void decode_sdr_module_size(unsigned char *bytes, dmi_mem_size *size) {
+ unsigned short i, k = 0;
i = (bytes[3] & 0x0f) + (bytes[4] & 0x0f) - 17;
- if (bytes[5] <= 8 && bytes[17] <= 8) {
- k = bytes[5] * bytes[17];
- }
+ if (bytes[5] <= 8 && bytes[17] <= 8) { k = bytes[5] * bytes[17]; }
if (i > 0 && i <= 12 && k > 0) {
- if (size) {
- *size = (1 << i) * k;
- }
+ if (size) { *size = (dmi_mem_size)k * (unsigned short)(1 << i); }
} else {
- if (size) {
- *size = -1;
- }
+ if (size) { *size = -1; }
}
}
-static void decode_sdr_module_timings(unsigned char *bytes, float *tcl, float *trcd, float *trp, float *tras)
-{
+static void decode_sdr_module_timings(unsigned char *bytes, float *tcl, float *trcd, float *trp,
+ float *tras) {
float cas[3], ctime;
int i, j;
for (i = 0, j = 0; j < 7; j++) {
- if (bytes[18] & 1 << j) {
- cas[i++] = j + 1;
- }
+ if (bytes[18] & 1 << j) { cas[i++] = j + 1; }
}
- ctime = (bytes[9] >> 4 + bytes[9] & 0xf) * 0.1;
+ ctime = ((bytes[9] >> 4) + (bytes[9] & 0xf)) * 0.1;
- if (trcd) {
- *trcd = ceil(bytes[29] / ctime);
- }
- if (trp) {
- *trp = ceil(bytes[27] / ctime);
- }
- if (tras) {
- *tras = ceil(bytes[30] / ctime);
- }
- if (tcl) {
- *tcl = cas[i];
- }
+ if (trcd) { *trcd = ceil(bytes[29] / ctime); }
+ if (trp) { *trp = ceil(bytes[27] / ctime); }
+ if (tras) { *tras = ceil(bytes[30] / ctime); }
+ if (tcl) { *tcl = cas[i]; }
}
-static void decode_sdr_module_row_address_bits(unsigned char *bytes, char **bits)
-{
+static void decode_sdr_module_row_address_bits(unsigned char *bytes, char **bits) {
char *temp;
switch (bytes[3]) {
- case 0:
- temp = "Undefined";
- break;
- case 1:
- temp = "1/16";
- break;
- case 2:
- temp = "2/27";
- break;
- case 3:
- temp = "3/18";
- break;
+ case 0: temp = "Undefined"; break;
+ case 1: temp = "1/16"; break;
+ case 2: temp = "2/27"; break;
+ case 3: temp = "3/18"; break;
default:
- /* printf("%d\n", bytes[3]); */
- temp = "Unknown";
+ /* printf("%d\n", bytes[3]); */
+ temp = NULL;
}
- if (bits) {
- *bits = temp;
- }
+ if (bits) { *bits = temp; }
}
-static void decode_sdr_module_col_address_bits(unsigned char *bytes, char **bits)
-{
+static void decode_sdr_module_col_address_bits(unsigned char *bytes, char **bits) {
char *temp;
switch (bytes[4]) {
- case 0:
- temp = "Undefined";
- break;
- case 1:
- temp = "1/16";
- break;
- case 2:
- temp = "2/17";
- break;
- case 3:
- temp = "3/18";
- break;
+ case 0: temp = "Undefined"; break;
+ case 1: temp = "1/16"; break;
+ case 2: temp = "2/17"; break;
+ case 3: temp = "3/18"; break;
default:
- /*printf("%d\n", bytes[4]); */
- temp = "Unknown";
+ /*printf("%d\n", bytes[4]); */
+ temp = NULL;
}
- if (bits) {
- *bits = temp;
- }
+ if (bits) { *bits = temp; }
}
-static void decode_sdr_module_number_of_rows(unsigned char *bytes, int *rows)
-{
- if (rows) {
- *rows = bytes[5];
- }
+static void decode_sdr_module_number_of_rows(unsigned char *bytes, int *rows) {
+ if (rows) { *rows = bytes[5]; }
}
-static void decode_sdr_module_data_with(unsigned char *bytes, int *width)
-{
+static void decode_sdr_module_data_with(unsigned char *bytes, int *width) {
if (width) {
- if (bytes[7] > 1) {
- *width = 0;
- } else {
- *width = (bytes[7] * 0xff) + bytes[6];
- }
+ if (bytes[7] > 1) {
+ *width = 0;
+ } else {
+ *width = (bytes[7] * 0xff) + bytes[6];
+ }
}
}
-static void decode_sdr_module_interface_signal_levels(unsigned char *bytes, char **signal_levels)
-{
+static void decode_sdr_module_interface_signal_levels(unsigned char *bytes, char **signal_levels) {
char *temp;
switch (bytes[8]) {
- case 0:
- temp = "5.0 Volt/TTL";
- break;
- case 1:
- temp = "LVTTL";
- break;
- case 2:
- temp = "HSTL 1.5";
- break;
- case 3:
- temp = "SSTL 3.3";
- break;
- case 4:
- temp = "SSTL 2.5";
- break;
- case 255:
- temp = "New Table";
- break;
- default:
- temp = "Undefined";
+ case 0: temp = "5.0 Volt/TTL"; break;
+ case 1: temp = "LVTTL"; break;
+ case 2: temp = "HSTL 1.5"; break;
+ case 3: temp = "SSTL 3.3"; break;
+ case 4: temp = "SSTL 2.5"; break;
+ case 255: temp = "New Table"; break;
+ default: temp = NULL;
}
- if (signal_levels) {
- *signal_levels = temp;
- }
+ if (signal_levels) { *signal_levels = temp; }
}
-static void decode_sdr_module_configuration_type(unsigned char *bytes, char **module_config_type)
-{
+static void decode_sdr_module_configuration_type(unsigned char *bytes, char **module_config_type) {
char *temp;
switch (bytes[11]) {
- case 0:
- temp = "No parity";
- break;
- case 1:
- temp = "Parity";
- break;
- case 2:
- temp = "ECC";
- break;
- default:
- temp = "Undefined";
+ case 0: temp = "No parity"; break;
+ case 1: temp = "Parity"; break;
+ case 2: temp = "ECC"; break;
+ default: temp = NULL;
}
- if (module_config_type) {
- *module_config_type = temp;
- }
+ if (module_config_type) { *module_config_type = temp; }
}
-static void decode_sdr_module_refresh_type(unsigned char *bytes, char **refresh_type)
-{
+static void decode_sdr_module_refresh_type(unsigned char *bytes, char **refresh_type) {
char *temp;
if (bytes[12] & 0x80) {
- temp = "Self refreshing";
+ temp = "Self refreshing";
} else {
- temp = "Not self refreshing";
+ temp = "Not self refreshing";
}
- if (refresh_type) {
- *refresh_type = temp;
- }
+ if (refresh_type) { *refresh_type = temp; }
}
-static void decode_sdr_module_refresh_rate(unsigned char *bytes, char **refresh_rate)
-{
+static void decode_sdr_module_refresh_rate(unsigned char *bytes, char **refresh_rate) {
char *temp;
switch (bytes[12] & 0x7f) {
- case 0:
- temp = "Normal (15.625us)";
- break;
- case 1:
- temp = "Reduced (3.9us)";
- break;
- case 2:
- temp = "Reduced (7.8us)";
- break;
- case 3:
- temp = "Extended (31.3us)";
- break;
- case 4:
- temp = "Extended (62.5us)";
- break;
- case 5:
- temp = "Extended (125us)";
- break;
- default:
- temp = "Undefined";
+ case 0: temp = "Normal (15.625us)"; break;
+ case 1: temp = "Reduced (3.9us)"; break;
+ case 2: temp = "Reduced (7.8us)"; break;
+ case 3: temp = "Extended (31.3us)"; break;
+ case 4: temp = "Extended (62.5us)"; break;
+ case 5: temp = "Extended (125us)"; break;
+ default: temp = NULL;
}
- if (refresh_rate) {
- *refresh_rate = temp;
+ if (refresh_rate) { *refresh_rate = temp; }
+}
+
+static void decode_sdr_module_detail(unsigned char *bytes, char *type_detail) {
+ bytes = bytes; /* silence unused warning */
+ if (type_detail) {
+ snprintf(type_detail, 255, "SDR");
}
}
-static gchar *decode_sdr_sdram(unsigned char *bytes, int *size)
-{
+static gchar *decode_sdr_sdram_extra(unsigned char *bytes) {
int rows, data_width;
float tcl, trcd, trp, tras;
char *row_address_bits, *col_address_bits, *signal_level;
char *module_config_type, *refresh_type, *refresh_rate;
- decode_sdr_module_size(bytes, size);
decode_sdr_module_timings(bytes, &tcl, &trcd, &trp, &tras);
decode_sdr_module_row_address_bits(bytes, &row_address_bits);
decode_sdr_module_col_address_bits(bytes, &col_address_bits);
@@ -882,29 +290,30 @@ static gchar *decode_sdr_sdram(unsigned char *bytes, int *size)
- Other misc stuff
*/
- return g_strdup_printf("[Module Information]\n"
- "Module type=SDR\n"
- "SPD revision=%d\n"
- "Row address bits=%s\n"
- "Column address bits=%s\n"
- "Number of rows=%d\n"
- "Data width=%d bits\n"
- "Interface signal levels=%s\n"
- "Configuration type=%s\n"
- "Refresh=%s (%s)\n"
- "[Timings]\n"
- "tCL=%.2f\n"
- "tRCD=%.2f\n"
- "tRP=%.2f\n"
- "tRAS=%.2f\n",
- bytes[62],
- row_address_bits, col_address_bits, rows,
- data_width, signal_level, module_config_type,
- refresh_type, refresh_rate, tcl, trcd, trp, tras);
+ /* expected to continue an [SPD] section */
+ return g_strdup_printf("%s=%s\n"
+ "%s=%s\n"
+ "%s=%d\n"
+ "%s=%d bits\n"
+ "%s=%s\n"
+ "%s=%s\n"
+ "%s=%s (%s)\n"
+ "[%s]\n"
+ "tCL=%.2f\n"
+ "tRCD=%.2f\n"
+ "tRP=%.2f\n"
+ "tRAS=%.2f\n",
+ _("Row address bits"), row_address_bits ? row_address_bits : _("(Unknown)"),
+ _("Column address bits"), col_address_bits ? col_address_bits : _("(Unknown)"),
+ _("Number of rows"), rows,
+ _("Data width"), data_width,
+ _("Interface signal levels"), signal_level ? signal_level : _("(Unknown)"),
+ _("Configuration type"), module_config_type ? module_config_type : _("(Unknown)"),
+ _("Refresh"), refresh_type, refresh_rate ? refresh_rate : _("Unknown"),
+ _("Timings"), tcl, trcd, trp, tras);
}
-static void decode_ddr_module_speed(unsigned char *bytes, float *ddrclk, int *pcclk)
-{
+static void decode_ddr_module_speed(unsigned char *bytes, float *ddrclk, int *pcclk) {
float temp, clk;
int tbits, pc;
@@ -912,601 +321,952 @@ static void decode_ddr_module_speed(unsigned char *bytes, float *ddrclk, int *pc
clk = 2 * (1000 / temp);
tbits = (bytes[7] * 256) + bytes[6];
- if (bytes[11] == 2 || bytes[11] == 1) {
- tbits -= 8;
- }
+ if (bytes[11] == 2 || bytes[11] == 1) { tbits -= 8; }
pc = clk * tbits / 8;
- if (pc % 100 > 50) {
- pc += 100;
- }
+ if (pc % 100 > 50) { pc += 100; }
pc -= pc % 100;
- if (ddrclk)
- *ddrclk = (int) clk;
+ if (ddrclk) *ddrclk = (int)clk;
- if (pcclk)
- *pcclk = pc;
+ if (pcclk) *pcclk = pc;
}
-static void decode_ddr_module_size(unsigned char *bytes, int *size)
-{
- int i, k;
+static void decode_ddr_module_size(unsigned char *bytes, dmi_mem_size *size) {
+ unsigned short i, k;
i = (bytes[3] & 0x0f) + (bytes[4] & 0x0f) - 17;
k = (bytes[5] <= 8 && bytes[17] <= 8) ? bytes[5] * bytes[17] : 0;
if (i > 0 && i <= 12 && k > 0) {
- if (size) {
- *size = (1 << i) * k;
- }
+ if (size) { *size = (dmi_mem_size)k * (unsigned short)(1 << i); }
} else {
- if (size) {
- *size = -1;
- }
+ if (size) { *size = -1; }
}
}
-static void *decode_ddr_module_timings(unsigned char *bytes, float *tcl, float *trcd, float *trp, float *tras)
-{
+static void decode_ddr_module_timings(unsigned char *bytes, float *tcl, float *trcd, float *trp,
+ float *tras) {
float ctime;
float highest_cas = 0;
int i;
for (i = 0; i < 7; i++) {
- if (bytes[18] & (1 << i)) {
- highest_cas = 1 + i * 0.5f;
- }
+ if (bytes[18] & (1 << i)) { highest_cas = 1 + i * 0.5f; }
}
ctime = (bytes[9] >> 4) + (bytes[9] & 0xf) * 0.1;
if (trcd) {
- *trcd = (bytes[29] >> 2) + ((bytes[29] & 3) * 0.25);
- *trcd = ceil(*trcd / ctime);
+ *trcd = (bytes[29] >> 2) + ((bytes[29] & 3) * 0.25);
+ *trcd = ceil(*trcd / ctime);
}
if (trp) {
- *trp = (bytes[27] >> 2) + ((bytes[27] & 3) * 0.25);
- *trp = ceil(*trp / ctime);
+ *trp = (bytes[27] >> 2) + ((bytes[27] & 3) * 0.25);
+ *trp = ceil(*trp / ctime);
}
if (tras) {
- *tras = bytes[30];
- *tras = ceil(*tras / ctime);
+ *tras = bytes[30];
+ *tras = ceil(*tras / ctime);
}
- if (tcl) {
- *tcl = highest_cas;
- }
+ if (tcl) { *tcl = highest_cas; }
}
-static gchar *decode_ddr_sdram(unsigned char *bytes, int *size)
-{
+static void decode_ddr_module_detail(unsigned char *bytes, char *type_detail) {
float ddr_clock;
- float tcl, trcd, trp, tras;
int pc_speed;
+ if (type_detail) {
+ decode_ddr_module_speed(bytes, &ddr_clock, &pc_speed);
+ snprintf(type_detail, 255, "DDR-%.0f (PC-%d)", ddr_clock, pc_speed);
+ }
+}
+
+static gchar *decode_ddr_sdram_extra(unsigned char *bytes) {
+ float tcl, trcd, trp, tras;
- decode_ddr_module_speed(bytes, &ddr_clock, &pc_speed);
- decode_ddr_module_size(bytes, size);
decode_ddr_module_timings(bytes, &tcl, &trcd, &trp, &tras);
- return g_strdup_printf("[Module Information]\n"
- "Module type=DDR %.2fMHz (PC%d)\n"
- "SPD revision=%d.%d\n"
- "[Timings]\n"
- "tCL=%.2f\n"
- "tRCD=%.2f\n"
- "tRP=%.2f\n"
- "tRAS=%.2f\n", ddr_clock, pc_speed, bytes[62] >> 4, bytes[62] & 0xf, tcl, trcd, trp, tras);
+ return g_strdup_printf("[%s]\n"
+ "tCL=%.2f\n"
+ "tRCD=%.2f\n"
+ "tRP=%.2f\n"
+ "tRAS=%.2f\n",
+ _("Timings"), tcl, trcd, trp, tras);
}
-static float decode_ddr2_module_ctime(unsigned char byte)
-{
+static float decode_ddr2_module_ctime(unsigned char byte) {
float ctime;
ctime = (byte >> 4);
byte &= 0xf;
if (byte <= 9) {
- ctime += byte * 0.1;
+ ctime += byte * 0.1;
} else if (byte == 10) {
- ctime += 0.25;
+ ctime += 0.25;
} else if (byte == 11) {
- ctime += 0.33;
+ ctime += 0.33;
} else if (byte == 12) {
- ctime += 0.66;
+ ctime += 0.66;
} else if (byte == 13) {
- ctime += 0.75;
+ ctime += 0.75;
}
return ctime;
}
-static void decode_ddr2_module_speed(unsigned char *bytes, float *ddr_clock, int *pc2_speed)
-{
+static void decode_ddr2_module_speed(unsigned char *bytes, float *ddr_clock, int *pc2_speed) {
float ctime;
float ddrclk;
int tbits, pcclk;
-
ctime = decode_ddr2_module_ctime(bytes[9]);
ddrclk = 2 * (1000 / ctime);
tbits = (bytes[7] * 256) + bytes[6];
- if (bytes[11] & 0x03) {
- tbits -= 8;
- }
+ if (bytes[11] & 0x03) { tbits -= 8; }
pcclk = ddrclk * tbits / 8;
pcclk -= pcclk % 100;
- if (ddr_clock) {
- *ddr_clock = (int) ddrclk;
- }
- if (pc2_speed) {
- *pc2_speed = pcclk;
- }
+ if (ddr_clock) { *ddr_clock = (int)ddrclk; }
+ if (pc2_speed) { *pc2_speed = pcclk; }
}
-static void decode_ddr2_module_size(unsigned char *bytes, int *size)
-{
- int i, k;
+static void decode_ddr2_module_size(unsigned char *bytes, dmi_mem_size *size) {
+ unsigned short i, k;
i = (bytes[3] & 0x0f) + (bytes[4] & 0x0f) - 17;
k = ((bytes[5] & 0x7) + 1) * bytes[17];
if (i > 0 && i <= 12 && k > 0) {
- if (*size) {
- *size = ((1 << i) * k);
- }
+ if (size) { *size = (dmi_mem_size)k * (unsigned short)(1 << i); }
} else {
- if (*size) {
- *size = 0;
- }
+ if (size) { *size = 0; }
}
}
-static void decode_ddr2_module_timings(unsigned char *bytes, float *trcd, float *trp, float *tras, float *tcl)
-{
- float ctime;
- float highest_cas = 0;
- int i;
-
- for (i = 0; i < 7; i++) {
- if (bytes[18] & (1 << i)) {
- highest_cas = i;
- }
+static void decode_ddr2_module_type(unsigned char *bytes, const char **type) {
+ switch (bytes[20]) {
+ case 0x01: *type = "RDIMM (Registered DIMM)"; break;
+ case 0x02: *type = "UDIMM (Unbuffered DIMM)"; break;
+ case 0x04: *type = "SO-DIMM (Small Outline DIMM)"; break;
+ case 0x06: *type = "72b-SO-CDIMM (Small Outline Clocked DIMM, 72-bit data bus)"; break;
+ case 0x07: *type = "72b-SO-RDIMM (Small Outline Registered DIMM, 72-bit data bus)"; break;
+ case 0x08: *type = "Micro-DIMM"; break;
+ case 0x10: *type = "Mini-RDIMM (Mini Registered DIMM)"; break;
+ case 0x20: *type = "Mini-UDIMM (Mini Unbuffered DIMM)"; break;
+ default: *type = NULL;
}
+}
- ctime = decode_ddr2_module_ctime(bytes[9]);
+static void decode_ddr2_module_timings(float ctime, unsigned char *bytes, float *trcd, float *trp, float *tras) {
- if (trcd) {
- *trcd = ceil(((bytes[29] >> 2) + ((bytes[29] & 3) * 0.25)) / ctime);
- }
+ if (trcd) { *trcd = ceil(((bytes[29] >> 2) + ((bytes[29] & 3) * 0.25)) / ctime); }
- if (trp) {
- *trp = ceil(((bytes[27] >> 2) + ((bytes[27] & 3) * 0.25)) / ctime);
- }
+ if (trp) { *trp = ceil(((bytes[27] >> 2) + ((bytes[27] & 3) * 0.25)) / ctime); }
- if (tras) {
- *tras = ceil(bytes[30] / ctime);
+ if (tras) { *tras = ceil(bytes[30] / ctime); }
+}
+
+static gboolean decode_ddr2_module_ctime_for_casx(int casx_minus, unsigned char *bytes, float *ctime, float *tcl){
+ int highest_cas, i, bytei;
+ float ctimev = 0;
+
+ switch (casx_minus){
+ case 0:
+ bytei = 9;
+ break;
+ case 1:
+ bytei = 23;
+ break;
+ case 2:
+ bytei = 25;
+ break;
+ default:
+ return FALSE;
}
- if (tcl) {
- *tcl = highest_cas;
+ for (i = 0; i < 7; i++) {
+ if (bytes[18] & (1 << i)) { highest_cas = i; }
}
+
+ if ((bytes[18] & (1 << (highest_cas-casx_minus))) == 0)
+ return FALSE;
+
+ ctimev = decode_ddr2_module_ctime(bytes[bytei]);
+ if (ctimev == 0)
+ return FALSE;
+
+ if (tcl) { *tcl = highest_cas-casx_minus; }
+ if (ctime) { *ctime = ctimev; }
+
+ return TRUE;
}
-static gchar *decode_ddr2_sdram(unsigned char *bytes, int *size)
-{
+static void decode_ddr2_module_detail(unsigned char *bytes, char *type_detail) {
float ddr_clock;
- float trcd, trp, tras, tcl;
int pc2_speed;
+ if (type_detail) {
+ decode_ddr2_module_speed(bytes, &ddr_clock, &pc2_speed);
+ snprintf(type_detail, 255, "DDR2-%.0f (PC2-%d)", ddr_clock, pc2_speed);
+ }
+}
- decode_ddr2_module_speed(bytes, &ddr_clock, &pc2_speed);
- decode_ddr2_module_size(bytes, size);
- decode_ddr2_module_timings(bytes, &trcd, &trp, &tras, &tcl);
-
- return g_strdup_printf("[Module Information]\n"
- "Module type=DDR2 %.2f MHz (PC2-%d)\n"
- "SPD revision=%d.%d\n"
- "[Timings]\n"
- "tCL=%.2f\n"
- "tRCD=%.2f\n"
- "tRP=%.2f\n"
- "tRAS=%.2f\n", ddr_clock, pc2_speed, bytes[62] >> 4, bytes[62] & 0xf, tcl, trcd, trp, tras);
+static gchar *decode_ddr2_sdram_extra(unsigned char *bytes) {
+ float trcd, trp, tras, ctime, tcl;
+ const char* voltage;
+ gchar *out;
+ int i;
+
+ switch(bytes[8]){
+ case 0x0:
+ voltage = "TTL/5 V tolerant";
+ break;
+ case 0x1:
+ voltage = "LVTTL";
+ break;
+ case 0x2:
+ voltage = "HSTL 1.5 V";
+ break;
+ case 0x3:
+ voltage = "SSTL 3.3 V";
+ break;
+ case 0x4:
+ voltage = "SSTL 2.5 V";
+ break;
+ case 0x5:
+ voltage = "SSTL 1.8 V";
+ break;
+ default:
+ voltage = _("(Unknown)");
+ }
+
+ /* expected to continue an [SPD] section */
+ out = g_strdup_printf("%s=%s\n"
+ "[%s]\n",
+ _("Voltage"), voltage,
+ _("JEDEC Timings"));
+
+ for (i = 0; i <= 2; i++) {
+ if (!decode_ddr2_module_ctime_for_casx(i, bytes, &ctime, &tcl))
+ break;
+ decode_ddr2_module_timings(ctime, bytes, &trcd, &trp, &tras);
+ out = h_strdup_cprintf("DDR2-%d=%.0f-%.0f-%.0f-%.0f\n",
+ out,
+ (int)(2 * (1000 / ctime)), tcl, trcd, trp, tras);
+ }
+
+ return out;
}
-static void decode_ddr3_module_speed(unsigned char *bytes, float *ddr_clock, int *pc3_speed)
-{
+static void decode_ddr3_module_speed(unsigned char *bytes, float *ddr_clock, int *pc3_speed) {
float ctime;
float ddrclk;
int tbits, pcclk;
float mtb = 0.125;
- if (bytes[10] == 1 && bytes[11] == 8)
- mtb = 0.125;
- if (bytes[10] == 1 && bytes[11] == 15)
- mtb = 0.0625;
+ if (bytes[10] == 1 && bytes[11] == 8) mtb = 0.125;
+ if (bytes[10] == 1 && bytes[11] == 15) mtb = 0.0625;
ctime = mtb * bytes[12];
ddrclk = 2 * (1000 / ctime);
tbits = 64;
switch (bytes[8]) {
- case 1:
- tbits = 16;
- break;
- case 4:
- tbits = 32;
- break;
+ case 1: tbits = 16; break;
+ case 4: tbits = 32; break;
case 3:
- case 0xb:
- tbits = 64;
- break;
+ case 0xb: tbits = 64; break;
}
pcclk = ddrclk * tbits / 8;
pcclk -= pcclk % 100;
- if (ddr_clock) {
- *ddr_clock = (int) ddrclk;
- }
- if (pc3_speed) {
- *pc3_speed = pcclk;
- }
+ if (ddr_clock) { *ddr_clock = (int)ddrclk; }
+ if (pc3_speed) { *pc3_speed = pcclk; }
}
-static void decode_ddr3_module_size(unsigned char *bytes, int *size)
-{
- *size = 512 << bytes[4];
+static void decode_ddr3_module_size(unsigned char *bytes, dmi_mem_size *size) {
+ unsigned int sdr_capacity = 256 << (bytes[4] & 0xF);
+ unsigned int sdr_width = 4 << (bytes[7] & 0x7);
+ unsigned int bus_width = 8 << (bytes[8] & 0x7);
+ unsigned int ranks = 1 + ((bytes[7] >> 3) & 0x7);
+
+ *size = (dmi_mem_size)sdr_capacity / 8 * bus_width / sdr_width * ranks;
}
-static void decode_ddr3_module_timings(unsigned char *bytes, float *trcd, float *trp, float *tras, float *tcl)
-{
+static void decode_ddr3_module_timings(unsigned char *bytes, float *trcd, float *trp, float *tras,
+ float *tcl) {
float ctime;
- float highest_cas = 0;
- int i;
float mtb = 0.125;
+ float taa;
- if (bytes[10] == 1 && bytes[11] == 8)
- mtb = 0.125;
- if (bytes[10] == 1 && bytes[11] == 15)
- mtb = 0.0625;
+ if (bytes[10] == 1 && bytes[11] == 8) mtb = 0.125;
+ if (bytes[10] == 1 && bytes[11] == 15) mtb = 0.0625;
ctime = mtb * bytes[12];
+ taa = bytes[16] * mtb;
- switch (bytes[14]) {
- case 6:
- highest_cas = 5;
- break;
- case 4:
- highest_cas = 6;
- break;
- case 0xc:
- highest_cas = 7;
- break;
- case 0x1e:
- highest_cas = 8;
- break;
- }
- if (trcd) {
- *trcd = bytes[18] * mtb;
- }
+ if (trcd) { *trcd = bytes[18] * mtb; }
- if (trp) {
- *trp = bytes[20] * mtb;
- }
+ if (trp) { *trp = bytes[20] * mtb; }
- if (tras) {
- *tras = (bytes[22] + bytes[21] & 0xf) * mtb;
- }
+ if (tras) { *tras = (bytes[22] + (bytes[21] & 0xf)) * mtb; }
- if (tcl) {
- *tcl = highest_cas;
- }
+ if (tcl) { *tcl = ceil(taa/ctime); }
}
-static void decode_ddr3_module_type(unsigned char *bytes, const char **type)
-{
+static void decode_ddr3_module_type(unsigned char *bytes, const char **type) {
switch (bytes[3]) {
- case 0x00:
- *type = "Undefined";
- break;
- case 0x01:
- *type = "RDIMM (Registered Long DIMM)";
- break;
- case 0x02:
- *type = "UDIMM (Unbuffered Long DIMM)";
- break;
- case 0x03:
- *type = "SODIMM (Small Outline DIMM)";
- break;
- default:
- *type = "Unknown";
+ case 0x01: *type = "RDIMM (Registered Long DIMM)"; break;
+ case 0x02: *type = "UDIMM (Unbuffered Long DIMM)"; break;
+ case 0x03: *type = "SODIMM (Small Outline DIMM)"; break;
+ default: *type = NULL;
}
}
-static gchar *decode_ddr3_sdram(unsigned char *bytes, int *size)
-{
+static void decode_ddr3_module_detail(unsigned char *bytes, char *type_detail) {
float ddr_clock;
- float trcd, trp, tras, tcl;
int pc3_speed;
- const char *type;
+ if (type_detail) {
+ decode_ddr3_module_speed(bytes, &ddr_clock, &pc3_speed);
+ snprintf(type_detail, 255, "DDR3-%.0f (PC3-%d)", ddr_clock, pc3_speed);
+ }
+}
+
+static gchar *decode_ddr3_sdram_extra(unsigned char *bytes) {
+ float trcd, trp, tras, tcl;
- decode_ddr3_module_speed(bytes, &ddr_clock, &pc3_speed);
- decode_ddr3_module_size(bytes, size);
decode_ddr3_module_timings(bytes, &trcd, &trp, &tras, &tcl);
- decode_ddr3_module_type(bytes, &type);
-
- return g_strdup_printf("[Module Information]\n"
- "Module type=DDR3 %.2f MHz (PC3-%d)\n"
- "SPD revision=%d.%d\n"
- "Type=%s\n"
- "[Timings]\n"
- "tCL=%.2f\n"
- "tRCD=%.3fns\n"
- "tRP=%.3fns\n"
- "tRAS=%.3fns\n",
- ddr_clock, pc3_speed,
- bytes[1] >> 4, bytes[1] & 0xf,
- type,
- tcl,
- trcd,
- trp,
- tras);
+
+ int ranks = 1 + ((bytes[7] >> 3) & 0x7);
+ int pins = 4 << (bytes[7] & 0x7);
+ int die_count = (bytes[33] >> 4) & 0x7;
+ int ts = !!(bytes[32] & 0x80);
+
+ /* expected to continue an [SPD] section */
+ return g_strdup_printf("%s=%d\n"
+ "%s=%d\n"
+ "%s=%d %s\n"
+ "%s=[%02x] %s\n"
+ "%s=%s%s%s\n"
+ "%s="
+ "%s%s%s%s%s%s%s%s"
+ "%s%s%s%s%s%s%s\n"
+ "[%s]\n"
+ "tCL=%.0f\n"
+ "tRCD=%.3fns\n"
+ "tRP=%.3fns\n"
+ "tRAS=%.3fns\n",
+ _("Ranks"), ranks,
+ _("IO Pins per Chip"), pins,
+ _("Die count"), die_count, die_count ? "" : _("(Unspecified)"),
+ _("Thermal Sensor"), bytes[32], ts ? _("Present") : _("Not present"),
+ _("Supported Voltages"),
+ (bytes[6] & 4) ? "1.25V " : "",
+ (bytes[6] & 2) ? "1.35V " : "",
+ (bytes[6] & 1) ? "" : "1.5V",
+ _("Supported CAS Latencies"),
+ (bytes[15] & 0x40) ? "18 " : "",
+ (bytes[15] & 0x20) ? "17 " : "",
+ (bytes[15] & 0x10) ? "16 " : "",
+ (bytes[15] & 0x08) ? "15 " : "",
+ (bytes[15] & 0x04) ? "14 " : "",
+ (bytes[15] & 0x02) ? "13 " : "",
+ (bytes[15] & 0x01) ? "12 " : "",
+ (bytes[14] & 0x80) ? "11 " : "",
+ (bytes[14] & 0x40) ? "10 " : "",
+ (bytes[14] & 0x20) ? "9 " : "",
+ (bytes[14] & 0x10) ? "8 " : "",
+ (bytes[14] & 0x08) ? "7 " : "",
+ (bytes[14] & 0x04) ? "6 " : "",
+ (bytes[14] & 0x02) ? "5 " : "",
+ (bytes[14] & 0x01) ? "4" : "",
+ _("Timings"), tcl, trcd, trp, tras
+ );
}
-static void decode_ddr3_part_number(unsigned char *bytes, char *part_number)
-{
+static void decode_ddr3_part_number(unsigned char *bytes, char *part_number) {
int i;
if (part_number) {
- for (i = 128; i <= 145; i++)
- *part_number++ = bytes[i];
- *part_number = '\0';
+ for (i = 128; i <= 145; i++) *part_number++ = bytes[i];
+ *part_number = '\0';
}
}
-static void decode_ddr3_manufacturer(unsigned char *bytes, char **manufacturer)
-{
- char *out = "Unknown";
+static void decode_ddr34_manufacturer(unsigned char count, unsigned char code, char **manufacturer, int *bank, int *index) {
+ if (!manufacturer) return;
+
+ if (code == 0x00 || code == 0xFF) {
+ *manufacturer = NULL;
+ return;
+ }
+
+ if (parity(count) != 1 || parity(code) != 1) {
+ *manufacturer = _("Invalid");
+ return;
+ }
- end:
- if (manufacturer) {
- *manufacturer = out;
+ *bank = count & 0x7f;
+ *index = code & 0x7f;
+ if (*bank >= VENDORS_BANKS) {
+ *manufacturer = NULL;
+ return;
}
+
+ *manufacturer = (char *)JEDEC_MFG_STR(*bank, *index - 1);
+}
+
+static void decode_ddr3_manufacturer(unsigned char *bytes, char **manufacturer, int *bank, int *index) {
+ decode_ddr34_manufacturer(bytes[117], bytes[118], (char **) manufacturer, bank, index);
}
-static void decode_module_manufacturer(unsigned char *bytes, char **manufacturer)
-{
+static void decode_module_manufacturer(unsigned char *bytes, char **manufacturer) {
char *out = "Unknown";
unsigned char first;
int ai = 0;
int len = 8;
- unsigned char *initial = bytes;
if (!spd_written(bytes, 8)) {
- out = "Undefined";
- goto end;
+ out = "Undefined";
+ goto end;
}
- do {
- ai++;
- } while ((--len && (*bytes++ == 0x7f)));
+ do { ai++; } while ((--len && (*bytes++ == 0x7f)));
first = *--bytes;
if (ai == 0) {
- out = "Invalid";
- goto end;
+ out = "Invalid";
+ goto end;
}
if (parity(first) != 1) {
- out = "Invalid";
- goto end;
+ out = "Invalid";
+ goto end;
}
- out = (char *) vendors[ai - 1][(first & 0x7f) - 1];
+ out = (char*)JEDEC_MFG_STR(ai - 1, (first & 0x7f) - 1);
- end:
- if (manufacturer) {
- *manufacturer = out;
- }
+end:
+ if (manufacturer) { *manufacturer = out; }
}
-static void decode_module_part_number(unsigned char *bytes, char *part_number)
-{
+static void decode_module_part_number(unsigned char *bytes, char *part_number) {
if (part_number) {
- bytes += 8 + 64;
+ bytes += 8 + 64;
+
+ while (*++bytes && *bytes >= 32 && *bytes < 127) { *part_number++ = *bytes; }
+ *part_number = '\0';
+ }
+}
+
+static char *print_spd_timings(int speed, float cas, float trcd, float trp, float tras,
+ float ctime) {
+ return g_strdup_printf("DDR4-%d=%.0f-%.0f-%.0f-%.0f\n", speed, cas, ceil(trcd / ctime - 0.025),
+ ceil(trp / ctime - 0.025), ceil(tras / ctime - 0.025));
+}
+
+static void decode_ddr4_module_type(unsigned char *bytes, const char **type) {
+ switch (bytes[3]) {
+ case 0x01: *type = "RDIMM (Registered DIMM)"; break;
+ case 0x02: *type = "UDIMM (Unbuffered DIMM)"; break;
+ case 0x03: *type = "SODIMM (Small Outline Unbuffered DIMM)"; break;
+ case 0x04: *type = "LRDIMM (Load-Reduced DIMM)"; break;
+ case 0x05: *type = "Mini-RDIMM (Mini Registered DIMM)"; break;
+ case 0x06: *type = "Mini-UDIMM (Mini Unbuffered DIMM)"; break;
+ case 0x08: *type = "72b-SO-RDIMM (Small Outline Registered DIMM, 72-bit data bus)"; break;
+ case 0x09: *type = "72b-SO-UDIMM (Small Outline Unbuffered DIMM, 72-bit data bus)"; break;
+ case 0x0c: *type = "16b-SO-UDIMM (Small Outline Unbuffered DIMM, 16-bit data bus)"; break;
+ case 0x0d: *type = "32b-SO-UDIMM (Small Outline Unbuffered DIMM, 32-bit data bus)"; break;
+ default: *type = NULL;
+ }
+}
+
+static float ddr4_mtb_ftb_calc(unsigned char b1, signed char b2) {
+ float mtb = 0.125;
+ float ftb = 0.001;
+ return b1 * mtb + b2 * ftb;
+}
+
+static void decode_ddr4_module_speed(unsigned char *bytes, float *ddr_clock, int *pc4_speed) {
+ float ctime;
+ float ddrclk;
+ int tbits, pcclk;
+
+ ctime = ddr4_mtb_ftb_calc(bytes[18], bytes[125]);
+ ddrclk = 2 * (1000 / ctime);
+ tbits = 8 << (bytes[13] & 7);
+
+ pcclk = ddrclk * tbits / 8;
+ pcclk -= pcclk % 100;
+
+ if (ddr_clock) { *ddr_clock = (int)ddrclk; }
+ if (pc4_speed) { *pc4_speed = pcclk; }
+}
+
+static void decode_ddr4_module_spd_timings(unsigned char *bytes, float speed, char **str) {
+ float ctime, ctime_max, pctime, taa, trcd, trp, tras;
+ int pcas, best_cas, base_cas, ci, i, j;
+ unsigned char cas_support[] = {bytes[20], bytes[21], bytes[22], bytes[23] & 0x1f};
+ float possible_ctimes[] = {15 / 24.0, 15 / 22.0, 15 / 20.0, 15 / 18.0,
+ 15 / 16.0, 15 / 14.0, 15 / 12.0};
+
+ base_cas = bytes[23] & 0x80 ? 23 : 7;
+
+ ctime = ddr4_mtb_ftb_calc(bytes[18], bytes[125]);
+ ctime_max = ddr4_mtb_ftb_calc(bytes[19], bytes[124]);
+
+ taa = ddr4_mtb_ftb_calc(bytes[24], bytes[123]);
+ trcd = ddr4_mtb_ftb_calc(bytes[25], bytes[122]);
+ trp = ddr4_mtb_ftb_calc(bytes[26], bytes[121]);
+ tras = (((bytes[27] & 0x0f) << 8) + bytes[28]) * 0.125;
+
+ *str = print_spd_timings((int)speed, ceil(taa / ctime - 0.025), trcd, trp, tras, ctime);
+
+ for (ci = 0; ci < 7; ci++) {
+ best_cas = 0;
+ pctime = possible_ctimes[ci];
+
+ for (i = 3; i >= 0; i--) {
+ for (j = 7; j >= 0; j--) {
+ if ((cas_support[i] & (1 << j)) != 0) {
+ pcas = base_cas + 8 * i + j;
+ if (ceil(taa / pctime) - 0.025 <= pcas) { best_cas = pcas; }
+ }
+ }
+ }
+
+ if (best_cas > 0 && pctime <= ctime_max && pctime >= ctime) {
+ *str = h_strdup_cprintf(
+ "%s\n", *str,
+ print_spd_timings((int)(2000.0 / pctime), best_cas, trcd, trp, tras, pctime));
+ }
+ }
+}
+
+static void decode_ddr4_module_size(unsigned char *bytes, dmi_mem_size *size) {
+ int sdrcap = 256 << (bytes[4] & 15);
+ int buswidth = 8 << (bytes[13] & 7);
+ int sdrwidth = 4 << (bytes[12] & 7);
+ int signal_loading = bytes[6] & 3;
+ int lranks_per_dimm = ((bytes[12] >> 3) & 7) + 1;
+
+ if (signal_loading == 2) lranks_per_dimm *= ((bytes[6] >> 4) & 7) + 1;
+
+ *size = (dmi_mem_size)sdrcap / 8 * buswidth / sdrwidth * lranks_per_dimm;
+}
+
+
+static void decode_ddr234_module_date(unsigned char weekb, unsigned char yearb, int *week, int *year) {
+ if (yearb == 0x0 || yearb == 0xff ||
+ weekb == 0x0 || weekb == 0xff) {
+ return;
+ }
+ *week = (weekb>>4) & 0xf;
+ *week *= 10;
+ *week += weekb & 0xf;
+ *year = (yearb>>4) & 0xf;
+ *year *= 10;
+ *year += yearb & 0xf;
+ *year += 2000;
+}
+
+static void decode_ddr2_module_date(unsigned char *bytes, int *week, int *year) {
+ decode_ddr234_module_date(bytes[94], bytes[93], week, year);
+}
- while (*bytes++ && *bytes >= 32 && *bytes < 127) {
- *part_number++ = *bytes;
- }
- *part_number = '\0';
+static void decode_ddr3_module_date(unsigned char *bytes, int *week, int *year) {
+ decode_ddr234_module_date(bytes[121], bytes[120], week, year);
+}
+
+static void decode_ddr4_module_date(unsigned char *bytes, int spd_size, int *week, int *year) {
+ if (spd_size < 324)
+ return;
+ decode_ddr234_module_date(bytes[324], bytes[323], week, year);
+}
+
+static void decode_ddr3_dram_manufacturer(unsigned char *bytes,
+ char **manufacturer, int *bank, int *index) {
+ decode_ddr34_manufacturer(bytes[94], bytes[95], (char **) manufacturer, bank, index);
+}
+
+static void decode_ddr4_dram_manufacturer(unsigned char *bytes, int spd_size,
+ char **manufacturer, int *bank, int *index) {
+ if (spd_size < 351) {
+ *manufacturer = NULL;
+ return;
+ }
+
+ decode_ddr34_manufacturer(bytes[350], bytes[351], (char **) manufacturer, bank, index);
+}
+
+static void detect_ddr4_xmp(unsigned char *bytes, int spd_size, int *majv, int *minv) {
+ if (spd_size < 387)
+ return;
+
+ *majv = 0; *minv = 0;
+
+ if (bytes[384] != 0x0c || bytes[385] != 0x4a) // XMP magic number
+ return;
+
+ if (majv)
+ *majv = bytes[387] >> 4;
+ if (minv)
+ *minv = bytes[387] & 0xf;
+}
+
+static void decode_ddr4_xmp(unsigned char *bytes, int spd_size, char **str) {
+ float ctime;
+ float ddrclk, taa, trcd, trp, tras;
+
+ if (spd_size < 405)
+ return;
+
+ ctime = ddr4_mtb_ftb_calc(bytes[396], bytes[431]);
+ ddrclk = 2 * (1000 / ctime);
+ taa = ddr4_mtb_ftb_calc(bytes[401], bytes[430]);
+ trcd = ddr4_mtb_ftb_calc(bytes[402], bytes[429]);
+ trp = ddr4_mtb_ftb_calc(bytes[403], bytes[428]);
+ tras = (((bytes[404] & 0x0f) << 8) + bytes[405]) * 0.125;
+
+ *str = g_strdup_printf("[%s]\n"
+ "%s=DDR4 %d MHz\n"
+ "%s=%d.%d V\n"
+ "[%s]\n"
+ "%s",
+ _("XMP Profile"),
+ _("Speed"), (int) ddrclk,
+ _("Voltage"), bytes[393] >> 7, bytes[393] & 0x7f,
+ _("XMP Timings"),
+ print_spd_timings((int) ddrclk, ceil(taa/ctime - 0.025), trcd, trp, tras, ctime));
+}
+
+static void decode_ddr4_module_detail(unsigned char *bytes, char *type_detail) {
+ float ddr_clock;
+ int pc4_speed;
+ if (type_detail) {
+ decode_ddr4_module_speed(bytes, &ddr_clock, &pc4_speed);
+ snprintf(type_detail, 255, "DDR4-%.0f (PC4-%d)", ddr_clock, pc4_speed);
+ }
+}
+
+static gchar *decode_ddr4_sdram_extra(unsigned char *bytes, int spd_size) {
+ float ddr_clock;
+ int pc4_speed, xmp_majv = -1, xmp_minv = -1;
+ char *speed_timings = NULL, *xmp_profile = NULL, *xmp = NULL, *manf_date = NULL;
+ static gchar *out;
+
+ decode_ddr4_module_speed(bytes, &ddr_clock, &pc4_speed);
+ decode_ddr4_module_spd_timings(bytes, ddr_clock, &speed_timings);
+ detect_ddr4_xmp(bytes, spd_size, &xmp_majv, &xmp_minv);
+
+ if (xmp_majv == -1 && xmp_minv == -1) {
+ xmp = NULL;
+ }
+ else if (xmp_majv <= 0 && xmp_minv <= 0) {
+ xmp = g_strdup(_("No"));
+ }
+ else {
+ xmp = g_strdup_printf("%s (revision %d.%d)", _("Yes"), xmp_majv, xmp_minv);
+ if (xmp_majv == 2 && xmp_minv == 0)
+ decode_ddr4_xmp(bytes, spd_size, &xmp_profile);
+ }
+
+ /* expected to continue an [SPD] section */
+ out = g_strdup_printf("%s=%s\n"
+ "%s=%s\n"
+ "[%s]\n"
+ "%s\n"
+ "%s",
+ _("Voltage"), bytes[11] & 0x01 ? "1.2 V": _("(Unknown)"),
+ _("XMP"), xmp ? xmp : _("(Unknown)"),
+ _("JEDEC Timings"), speed_timings,
+ xmp_profile ? xmp_profile: "");
+
+ g_free(speed_timings);
+ g_free(manf_date);
+ g_free(xmp);
+ g_free(xmp_profile);
+
+ return out;
+}
+
+static void decode_ddr4_part_number(unsigned char *bytes, int spd_size, char *part_number) {
+ int i;
+ if (!part_number) return;
+
+ if (spd_size < 348) {
+ *part_number++ = '\0';
+ return;
}
+
+ for (i = 329; i <= 348; i++)
+ *part_number++ = bytes[i];
+ *part_number = '\0';
+}
+
+static void decode_ddr4_module_manufacturer(unsigned char *bytes, int spd_size,
+ char **manufacturer, int *bank, int *index) {
+ if (spd_size < 321) {
+ *manufacturer = NULL;
+ return;
+ }
+
+ decode_ddr34_manufacturer(bytes[320], bytes[321], manufacturer, bank, index);
}
-static int decode_ram_type(unsigned char *bytes)
-{
+static int decode_ram_type(unsigned char *bytes) {
if (bytes[0] < 4) {
- switch (bytes[2]) {
- case 1:
- return DIRECT_RAMBUS;
- case 17:
- return RAMBUS;
- }
+ switch (bytes[2]) {
+ case 1: return DIRECT_RAMBUS;
+ case 17: return RAMBUS;
+ }
} else {
- switch (bytes[2]) {
- case 1:
- return FPM_DRAM;
- case 2:
- return EDO;
- case 3:
- return PIPELINED_NIBBLE;
- case 4:
- return SDR_SDRAM;
- case 5:
- return MULTIPLEXED_ROM;
- case 6:
- return DDR_SGRAM;
- case 7:
- return DDR_SDRAM;
- case 8:
- return DDR2_SDRAM;
- case 11:
- return DDR3_SDRAM;
- }
+ switch (bytes[2]) {
+ case 1: return FPM_DRAM;
+ case 2: return EDO;
+ case 3: return PIPELINED_NIBBLE;
+ case 4: return SDR_SDRAM;
+ case 5: return MULTIPLEXED_ROM;
+ case 6: return DDR_SGRAM;
+ case 7: return DDR_SDRAM;
+ case 8: return DDR2_SDRAM;
+ case 11: return DDR3_SDRAM;
+ case 12: return DDR4_SDRAM;
+ }
}
return UNKNOWN;
}
-static void read_spd(char *spd_path, int offset, size_t size, int use_sysfs, unsigned char *bytes_out)
-{
+static int read_spd(char *spd_path, int offset, size_t size, int use_sysfs,
+ unsigned char *bytes_out) {
+ int data_size = 0;
if (use_sysfs) {
- FILE *spd;
- gchar *temp_path;
+ FILE *spd;
+ gchar *temp_path;
- temp_path = g_strdup_printf("%s/eeprom", spd_path);
- if ((spd = fopen(temp_path, "rb"))) {
- fseek(spd, offset, SEEK_SET);
- fread(bytes_out, 1, size, spd);
- fclose(spd);
- }
+ temp_path = g_strdup_printf("%s/eeprom", spd_path);
+ if ((spd = fopen(temp_path, "rb"))) {
+ fseek(spd, offset, SEEK_SET);
+ data_size = fread(bytes_out, 1, size, spd);
+ fclose(spd);
+ }
- g_free(temp_path);
+ g_free(temp_path);
} else {
- int i;
+ int i;
- for (i = 0; i <= 3; i++) {
- FILE *spd;
- char *temp_path;
+ for (i = 0; i <= 3; i++) {
+ FILE *spd;
+ char *temp_path;
- temp_path = g_strdup_printf("%s/%02x", spd_path, offset + i * 16);
- if ((spd = fopen(temp_path, "rb"))) {
- fread(bytes_out + i * 16, 1, 16, spd);
- fclose(spd);
- }
+ temp_path = g_strdup_printf("%s/%02x", spd_path, offset + i * 16);
+ if ((spd = fopen(temp_path, "rb"))) {
+ data_size += fread(bytes_out + i * 16, 1, 16, spd);
+ fclose(spd);
+ }
- g_free(temp_path);
- }
+ g_free(temp_path);
+ }
}
+
+ return data_size;
}
-static gchar *decode_dimms(GSList * dimm_list, gboolean use_sysfs)
-{
- GSList *dimm;
- GString *output;
- gint count = 0;
-
- output = g_string_new("");
-
- for (dimm = dimm_list; dimm; dimm = dimm->next, count++) {
- gchar *spd_path = (gchar *) dimm->data;
- gchar *manufacturer;
- gchar *detailed_info;
- gchar *moreinfo_key;
- gchar part_number[32];
- unsigned char bytes[256];
- int module_size;
- RamType ram_type;
-
- shell_status_pulse();
-
- read_spd(spd_path, 0, 256, use_sysfs, bytes);
- ram_type = decode_ram_type(bytes);
-
- switch (ram_type) {
- case DDR2_SDRAM:
- detailed_info = decode_ddr2_sdram(bytes, &module_size);
- decode_module_part_number(bytes, part_number);
- decode_module_manufacturer(bytes + 64, &manufacturer);
- break;
- case DDR3_SDRAM:
- detailed_info = decode_ddr3_sdram(bytes, &module_size);
- decode_ddr3_part_number(bytes, part_number);
- decode_ddr3_manufacturer(bytes, &manufacturer);
- break;
- case DDR_SDRAM:
- detailed_info = decode_ddr_sdram(bytes, &module_size);
- decode_module_part_number(bytes, part_number);
- decode_module_manufacturer(bytes + 64, &manufacturer);
- break;
- case SDR_SDRAM:
- detailed_info = decode_sdr_sdram(bytes, &module_size);
- decode_module_part_number(bytes, part_number);
- decode_module_manufacturer(bytes + 64, &manufacturer);
- break;
- default:
- DEBUG("Unsupported EEPROM type: %s\n", ram_types[ram_type]);
- continue;
- }
-
-
-
- gchar *key = g_strdup_printf("MEM%d", count);
- moreinfo_add_with_prefix("DEV", key, g_strdup(detailed_info));
- g_free(key);
- g_string_append_printf(output, "$MEM%d$%d=%s|%d MB|%s\n", count, count, part_number, module_size, manufacturer);
-
- g_free(spd_path);
- g_free(detailed_info);
+static GSList *decode_dimms2(GSList *eeprom_list, const gchar *driver, gboolean use_sysfs, int max_size) {
+ GSList *eeprom, *dimm_list = NULL;
+ int count = 0;
+ int spd_size = 0;
+ unsigned char bytes[512] = {0};
+ spd_data *s = NULL;
+
+ for (eeprom = eeprom_list; eeprom; eeprom = eeprom->next, count++) {
+ gchar *spd_path = (gchar*)eeprom->data;
+ s = NULL;
+
+ RamType ram_type;
+
+ memset(bytes, 0, 512); /* clear */
+ spd_size = read_spd(spd_path, 0, max_size, use_sysfs, bytes);
+ ram_type = decode_ram_type(bytes);
+
+ switch (ram_type) {
+ case SDR_SDRAM:
+ s = spd_data_new();
+ memcpy(s->bytes, bytes, 512);
+ decode_module_part_number(bytes, s->partno);
+ decode_module_manufacturer(bytes + 64, (char**)&s->vendor_str);
+ decode_sdr_module_size(bytes, &s->size_MiB);
+ decode_sdr_module_detail(bytes, s->type_detail);
+ break;
+ case DDR_SDRAM:
+ s = spd_data_new();
+ memcpy(s->bytes, bytes, 512);
+ decode_module_part_number(bytes, s->partno);
+ decode_module_manufacturer(bytes + 64, (char**)&s->vendor_str);
+ decode_ddr_module_size(bytes, &s->size_MiB);
+ decode_ddr_module_detail(bytes, s->type_detail);
+ break;
+ case DDR2_SDRAM:
+ s = spd_data_new();
+ memcpy(s->bytes, bytes, 512);
+ decode_module_part_number(bytes, s->partno);
+ decode_module_manufacturer(bytes + 64, (char**)&s->vendor_str);
+ decode_ddr2_module_size(bytes, &s->size_MiB);
+ decode_ddr2_module_detail(bytes, s->type_detail);
+ decode_ddr2_module_type(bytes, &s->form_factor);
+ decode_ddr2_module_date(bytes, &s->week, &s->year);
+ break;
+ case DDR3_SDRAM:
+ s = spd_data_new();
+ memcpy(s->bytes, bytes, 512);
+ decode_ddr3_part_number(bytes, s->partno);
+ decode_ddr3_manufacturer(bytes, (char**)&s->vendor_str,
+ &s->vendor_bank, &s->vendor_index);
+ decode_ddr3_dram_manufacturer(bytes, (char**)&s->dram_vendor_str,
+ &s->dram_vendor_bank, &s->dram_vendor_index);
+ decode_ddr3_module_size(bytes, &s->size_MiB);
+ decode_ddr3_module_type(bytes, &s->form_factor);
+ decode_ddr3_module_detail(bytes, s->type_detail);
+ decode_ddr3_module_date(bytes, &s->week, &s->year);
+ break;
+ case DDR4_SDRAM:
+ s = spd_data_new();
+ memcpy(s->bytes, bytes, 512);
+ decode_ddr4_part_number(bytes, spd_size, s->partno);
+ decode_ddr4_module_manufacturer(bytes, spd_size, (char**)&s->vendor_str,
+ &s->vendor_bank, &s->vendor_index);
+ decode_ddr4_dram_manufacturer(bytes, spd_size, (char**)&s->dram_vendor_str,
+ &s->dram_vendor_bank, &s->dram_vendor_index);
+ decode_ddr4_module_size(bytes, &s->size_MiB);
+ decode_ddr4_module_type(bytes, &s->form_factor);
+ decode_ddr4_module_detail(bytes, s->type_detail);
+ decode_ddr4_module_date(bytes, spd_size, &s->week, &s->year);
+ s->ddr4_no_ee1004 = s->ddr4_no_ee1004 || (spd_size < 512);
+ spd_ddr4_partial_data = spd_ddr4_partial_data || s->ddr4_no_ee1004;
+ break;
+ case UNKNOWN:
+ break;
+ default:
+ DEBUG("Unsupported EEPROM type: %s for %s\n", GET_RAM_TYPE_STR(ram_type), spd_path); continue;
+ if (ram_type) {
+ /* some kind of RAM that we can't decode, but exists */
+ s = spd_data_new();
+ memcpy(s->bytes, bytes, 512);
+ }
+ }
+
+ if (s) {
+ strncpy(s->dev, g_basename(spd_path), 31);
+ s->spd_driver = driver;
+ s->spd_size = spd_size;
+ s->type = ram_type;
+ spd_ram_types |= (1 << (ram_type-1));
+ switch (ram_type) {
+ case SDR_SDRAM:
+ case DDR_SDRAM:
+ case DDR2_SDRAM:
+ s->spd_rev_major = bytes[62] >> 4;
+ s->spd_rev_minor = bytes[62] & 0xf;
+ break;
+ case DDR3_SDRAM:
+ case DDR4_SDRAM:
+ s->spd_rev_major = bytes[1] >> 4;
+ s->spd_rev_minor = bytes[1] & 0xf;
+ break;
+ }
+ s->vendor = vendor_match(s->vendor_str, NULL);
+ s->dram_vendor = vendor_match(s->dram_vendor_str, NULL);
+ dimm_list = g_slist_append(dimm_list, s);
+ }
}
- return g_string_free(output, FALSE);
+ return dimm_list;
}
-void scan_spd_do(void)
-{
- GDir *dir = NULL;
- GSList *dimm_list = NULL;
- gboolean use_sysfs = FALSE;
- gchar *dir_entry;
- gchar *list;
-
- if (g_file_test("/sys/bus/i2c/drivers/eeprom", G_FILE_TEST_EXISTS)) {
- dir = g_dir_open("/sys/bus/i2c/drivers/eeprom", 0, NULL);
- use_sysfs = TRUE;
- } else if (g_file_test("/proc/sys/dev/sensors", G_FILE_TEST_EXISTS)) {
- dir = g_dir_open("/proc/sys/dev/sensors", 0, NULL);
- }
+struct SpdDriver {
+ const char *driver;
+ const char *dir_path;
+ const gint max_size;
+ const gboolean use_sysfs;
+ const char *spd_name;
+};
- if (!dir) {
- g_free(spd_info);
- if (!g_file_test("/sys/module/eeprom", G_FILE_TEST_EXISTS)) {
- spd_info = g_strdup(_("[SPD]\n"
- "Please load the eeprom module to obtain information about memory SPD=\n"
- "[$ShellParam$]\n"
- "ReloadInterval=500\n"));
- } else {
- spd_info = g_strdup(_("[SPD]\n" "Reading memory SPD not supported on this system=\n"));
- }
-
- return;
+static const struct SpdDriver spd_drivers[] = {
+ { "ee1004", "/sys/bus/i2c/drivers/ee1004", 512, TRUE, "ee1004"},
+ { "at24", "/sys/bus/i2c/drivers/at24" , 256, TRUE, "spd"},
+ { "eeprom", "/sys/bus/i2c/drivers/eeprom", 256, TRUE, "eeprom"},
+ { "eeprom-proc", "/proc/sys/dev/sensors" , 256, FALSE, NULL},
+ { NULL }
+};
+
+GSList *spd_scan() {
+ GDir *dir = NULL;
+ GSList *eeprom_list = NULL, *dimm_list = NULL;
+ gchar *dimm_list_entry, *dir_entry, *name_file, *name;
+ const struct SpdDriver *driver;
+ gboolean driver_found = FALSE;
+ gboolean is_spd = FALSE;
+
+ spd_ddr4_partial_data = FALSE;
+ spd_no_driver = FALSE;
+ spd_no_support = FALSE;
+
+ for (driver = spd_drivers; driver->dir_path; driver++) {
+ if (g_file_test(driver->dir_path, G_FILE_TEST_EXISTS)) {
+ dir = g_dir_open(driver->dir_path, 0, NULL);
+ if (!dir) continue;
+
+ driver_found = TRUE;
+ while ((dir_entry = (char *)g_dir_read_name(dir))) {
+ is_spd = FALSE;
+
+ if (driver->use_sysfs) {
+ name_file = NULL;
+ name = NULL;
+
+ if (isdigit(dir_entry[0])) {
+ name_file = g_build_filename(driver->dir_path, dir_entry, "name", NULL);
+ g_file_get_contents(name_file, &name, NULL, NULL);
+
+ is_spd = g_strcmp0(name, driver->spd_name);
+
+ g_free(name_file);
+ g_free(name);
+ }
+ }
+ else {
+ is_spd = g_str_has_prefix(dir_entry, "eeprom-");
+ }
+
+ if (is_spd){
+ dimm_list_entry = g_strdup_printf("%s/%s", driver->dir_path, dir_entry);
+ eeprom_list = g_slist_prepend(eeprom_list, dimm_list_entry);
+ }
+ }
+
+ g_dir_close(dir);
+
+ if (eeprom_list) {
+ dimm_list = decode_dimms2(eeprom_list, driver->driver, driver->use_sysfs, driver->max_size);
+ g_slist_free(eeprom_list);
+ eeprom_list = NULL;
+ }
+ if (dimm_list) break;
+ }
}
- while ((dir_entry = (char *) g_dir_read_name(dir))) {
- if (use_sysfs && isdigit(dir_entry[0])) {
- dimm_list = g_slist_prepend(dimm_list, g_strdup_printf("/sys/bus/i2c/drivers/eeprom/%s", dir_entry));
- } else if (g_str_has_prefix(dir_entry, "eeprom-")) {
- dimm_list = g_slist_prepend(dimm_list, g_strdup_printf("/proc/sys/dev/sensors/%s", dir_entry));
- }
+ if (!driver_found) {
+ if (!g_file_test("/sys/module/eeprom", G_FILE_TEST_EXISTS) &&
+ !g_file_test("/sys/module/at24", G_FILE_TEST_EXISTS)) {
+ spd_no_driver = TRUE; /* trigger hinote for no eeprom driver */
+ } else {
+ spd_no_support = TRUE; /* trigger hinote for unsupported system */
+ }
}
- g_dir_close(dir);
-
- list = decode_dimms(dimm_list, use_sysfs);
- g_slist_free(dimm_list);
-
- g_free(spd_info);
- 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);
+ return dimm_list;
}
diff --git a/modules/devices/spd-vendors.c b/modules/devices/spd-vendors.c
new file mode 100644
index 00000000..80b2a6a4
--- /dev/null
+++ b/modules/devices/spd-vendors.c
@@ -0,0 +1,292 @@
+/*
+ * spd-decode.c, spd-vendors.c
+ * Copyright (c) 2010 L. A. F. Pereira
+ * modified by Ondrej ÄŒerman (2019)
+ * modified by Burt P. (2019)
+ *
+ * Based on decode-dimms.pl
+ * Copyright 1998, 1999 Philip Edelbrock <phil@netroedge.com>
+ * modified by Christian Zuckschwerdt <zany@triq.net>
+ * modified by Burkart Lingner <burkart@bollchen.de>
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* from decode-dimms, in the i2c-tools package:
+ * https://github.com/angeloc/i2c-tools/blob/master/eeprom/decode-dimms
+ *
+ * STANDARD MANUFACTURERS IDENTIFICATION CODEs
+ * as defined in JEP106
+ *
+ * As of: 28 June 2019
+ *
+ */
+
+#define VENDORS_BANKS 8
+#define VENDORS_ITEMS 128
+#define JEDEC_MFG_STR(b,i) ( (b >= 0 && b < VENDORS_BANKS && i < VENDORS_ITEMS) ? vendors[(b)][(i)] : NULL )
+static const char* vendors[VENDORS_BANKS][VENDORS_ITEMS] =
+{
+{"AMD", "AMI", "Fairchild", "Fujitsu",
+ "GTE", "Harris", "Hitachi", "Inmos",
+ "Intel", "I.T.T.", "Intersil", "Monolithic Memories",
+ "Mostek", "Freescale (former Motorola)", "National", "NEC",
+ "RCA", "Raytheon", "Conexant (Rockwell)", "Seeq",
+ "NXP (former Signetics, Philips Semi.)", "Synertek", "Texas Instruments", "Toshiba",
+ "Xicor", "Zilog", "Eurotechnique", "Mitsubishi",
+ "Lucent (AT&T)", "Exel", "Atmel", "SGS/Thomson",
+ "Lattice Semi.", "NCR", "Wafer Scale Integration", "IBM",
+ "Tristar", "Visic", "Intl. CMOS Technology", "SSSI",
+ "MicrochipTechnology", "Ricoh Ltd.", "VLSI", "Micron Technology",
+ "SK Hynix (former Hyundai Electronics)", "OKI Semiconductor", "ACTEL", "Sharp",
+ "Catalyst", "Panasonic", "IDT", "Cypress",
+ "DEC", "LSI Logic", "Zarlink (former Plessey)", "UTMC",
+ "Thinking Machine", "Thomson CSF", "Integrated CMOS (Vertex)", "Honeywell",
+ "Tektronix", "Oracle Corporation (former Sun Microsystems)", "Silicon Storage Technology", "ProMos/Mosel Vitelic",
+ "Infineon (former Siemens)", "Macronix", "Xerox", "Plus Logic",
+ "SunDisk", "Elan Circuit Tech.", "European Silicon Str.", "Apple Computer",
+ "Xilinx", "Compaq", "Protocol Engines", "SCI",
+ "Seiko Instruments", "Samsung", "I3 Design System", "Klic",
+ "Crosspoint Solutions", "Alliance Semiconductor", "Tandem", "Hewlett-Packard",
+ "Integrated Silicon Solutions", "Brooktree", "New Media", "MHS Electronic",
+ "Performance Semi.", "Winbond Electronic", "Kawasaki Steel", "Bright Micro",
+ "TECMAR", "Exar", "PCMCIA", "LG Semi (former Goldstar)",
+ "Northern Telecom", "Sanyo", "Array Microsystems", "Crystal Semiconductor",
+ "Analog Devices", "PMC-Sierra", "Asparix", "Convex Computer",
+ "Quality Semiconductor", "Nimbus Technology", "Transwitch", "Micronas (ITT Intermetall)",
+ "Cannon", "Altera", "NEXCOM", "QUALCOMM",
+ "Sony", "Cray Research", "AMS(Austria Micro)", "Vitesse",
+ "Aster Electronics", "Bay Networks (Synoptic)", "Zentrum or ZMD", "TRW",
+ "Thesys", "Solbourne Computer", "Allied-Signal", "Dialog",
+ "Media Vision", "Numonyx Corporation (former Level One Communication)"},
+{"Cirrus Logic", "National Instruments", "ILC Data Device", "Alcatel Mietec",
+ "Micro Linear", "Univ. of NC", "JTAG Technologies", "BAE Systems",
+ "Nchip", "Galileo Tech", "Bestlink Systems", "Graychip",
+ "GENNUM", "VideoLogic", "Robert Bosch", "Chip Express",
+ "DATARAM", "United Microelec Corp.", "TCSI", "Smart Modular",
+ "Hughes Aircraft", "Lanstar Semiconductor", "Qlogic", "Kingston",
+ "Music Semi", "Ericsson Components", "SpaSE", "Eon Silicon Devices",
+ "Programmable Micro Corp", "DoD", "Integ. Memories Tech.", "Corollary Inc.",
+ "Dallas Semiconductor", "Omnivision", "EIV(Switzerland)", "Novatel Wireless",
+ "Zarlink (former Mitel)", "Clearpoint", "Cabletron", "STEC (former Silicon Technology)",
+ "Vanguard", "Hagiwara Sys-Com", "Vantis", "Celestica",
+ "Century", "Hal Computers", "Rohm Company Ltd.", "Juniper Networks",
+ "Libit Signal Processing", "Mushkin Enhanced Memory", "Tundra Semiconductor", "Adaptec Inc.",
+ "LightSpeed Semi.", "ZSP Corp.", "AMIC Technology", "Adobe Systems",
+ "Dynachip", "PNY Electronics", "Newport Digital", "MMC Networks",
+ "T Square", "Seiko Epson", "Broadcom", "Viking Components",
+ "V3 Semiconductor", "Flextronics (former Orbit)", "Suwa Electronics", "Transmeta",
+ "Micron CMS", "American Computer & Digital Components Inc", "Enhance 3000 Inc", "Tower Semiconductor",
+ "CPU Design", "Price Point", "Maxim Integrated Product", "Tellabs",
+ "Centaur Technology", "Unigen Corporation", "Transcend Information", "Memory Card Technology",
+ "CKD Corporation Ltd.", "Capital Instruments, Inc.", "Aica Kogyo, Ltd.", "Linvex Technology",
+ "MSC Vertriebs GmbH", "AKM Company, Ltd.", "Dynamem, Inc.", "NERA ASA",
+ "GSI Technology", "Dane-Elec (C Memory)", "Acorn Computers", "Lara Technology",
+ "Oak Technology, Inc.", "Itec Memory", "Tanisys Technology", "Truevision",
+ "Wintec Industries", "Super PC Memory", "MGV Memory", "Galvantech",
+ "Gadzoox Nteworks", "Multi Dimensional Cons.", "GateField", "Integrated Memory System",
+ "Triscend", "XaQti", "Goldenram", "Clear Logic",
+ "Cimaron Communications", "Nippon Steel Semi. Corp.", "Advantage Memory", "AMCC",
+ "LeCroy", "Yamaha Corporation", "Digital Microwave", "NetLogic Microsystems",
+ "MIMOS Semiconductor", "Advanced Fibre", "BF Goodrich Data.", "Epigram",
+ "Acbel Polytech Inc.", "Apacer Technology", "Admor Memory", "FOXCONN",
+ "Quadratics Superconductor", "3COM"},
+{"Camintonn Corporation", "ISOA Incorporated", "Agate Semiconductor", "ADMtek Incorporated",
+ "HYPERTEC", "Adhoc Technologies", "MOSAID Technologies", "Ardent Technologies",
+ "Switchcore", "Cisco Systems, Inc.", "Allayer Technologies", "WorkX AG (Wichman)",
+ "Oasis Semiconductor", "Novanet Semiconductor", "E-M Solutions", "Power General",
+ "Advanced Hardware Arch.", "Inova Semiconductors GmbH", "Telocity", "Delkin Devices",
+ "Symagery Microsystems", "C-Port Corporation", "SiberCore Technologies", "Southland Microsystems",
+ "Malleable Technologies", "Kendin Communications", "Great Technology Microcomputer", "Sanmina Corporation",
+ "HADCO Corporation", "Corsair", "Actrans System Inc.", "ALPHA Technologies",
+ "Silicon Laboratories, Inc. (Cygnal)", "Artesyn Technologies", "Align Manufacturing", "Peregrine Semiconductor",
+ "Chameleon Systems", "Aplus Flash Technology", "MIPS Technologies", "Chrysalis ITS",
+ "ADTEC Corporation", "Kentron Technologies", "Win Technologies", "Tachyon Semiconductor (former ASIC Designs Inc.)",
+ "Extreme Packet Devices", "RF Micro Devices", "Siemens AG", "Sarnoff Corporation",
+ "Itautec SA (former Itautec Philco SA)", "Radiata Inc.", "Benchmark Elect. (AVEX)", "Legend",
+ "SpecTek Incorporated", "Hi/fn", "Enikia Incorporated", "SwitchOn Networks",
+ "AANetcom Incorporated", "Micro Memory Bank", "ESS Technology", "Virata Corporation",
+ "Excess Bandwidth", "West Bay Semiconductor", "DSP Group", "Newport Communications",
+ "Chip2Chip Incorporated", "Phobos Corporation", "Intellitech Corporation", "Nordic VLSI ASA",
+ "Ishoni Networks", "Silicon Spice", "Alchemy Semiconductor", "Agilent Technologies",
+ "Centillium Communications", "W.L. Gore", "HanBit Electronics", "GlobeSpan",
+ "Element 14", "Pycon", "Saifun Semiconductors", "Sibyte, Incorporated",
+ "MetaLink Technologies", "Feiya Technology", "I & C Technology", "Shikatronics",
+ "Elektrobit", "Megic", "Com-Tier", "Malaysia Micro Solutions",
+ "Hyperchip", "Gemstone Communications", "Anadigm (former Anadyne)", "3ParData",
+ "Mellanox Technologies", "Tenx Technologies", "Helix AG", "Domosys",
+ "Skyup Technology", "HiNT Corporation", "Chiaro", "MDT Technologies GmbH (former MCI Computer GMBH)",
+ "Exbit Technology A/S", "Integrated Technology Express", "AVED Memory", "Legerity",
+ "Jasmine Networks", "Caspian Networks", "nCUBE", "Silicon Access Networks",
+ "FDK Corporation", "High Bandwidth Access", "MultiLink Technology", "BRECIS",
+ "World Wide Packets", "APW", "Chicory Systems", "Xstream Logic",
+ "Fast-Chip", "Zucotto Wireless", "Realchip", "Galaxy Power",
+ "eSilicon", "Morphics Technology", "Accelerant Networks", "Silicon Wave",
+ "SandCraft", "Elpida"},
+{"Solectron", "Optosys Technologies", "Buffalo (former Melco)", "TriMedia Technologies",
+ "Cyan Technologies", "Global Locate", "Optillion", "Terago Communications",
+ "Ikanos Communications", "Princeton Technology", "Nanya Technology", "Elite Flash Storage",
+ "Mysticom", "LightSand Communications", "ATI Technologies", "Agere Systems",
+ "NeoMagic", "AuroraNetics", "Golden Empire", "Mushkin",
+ "Tioga Technologies", "Netlist", "TeraLogic", "Cicada Semiconductor",
+ "Centon Electronics", "Tyco Electronics", "Magis Works", "Zettacom",
+ "Cogency Semiconductor", "Chipcon AS", "Aspex Technology", "F5 Networks",
+ "Programmable Silicon Solutions", "ChipWrights", "Acorn Networks", "Quicklogic",
+ "Kingmax Semiconductor", "BOPS", "Flasys", "BitBlitz Communications",
+ "eMemory Technology", "Procket Networks", "Purple Ray", "Trebia Networks",
+ "Delta Electronics", "Onex Communications", "Ample Communications", "Memory Experts Intl",
+ "Astute Networks", "Azanda Network Devices", "Dibcom", "Tekmos",
+ "API NetWorks", "Bay Microsystems", "Firecron Ltd", "Resonext Communications",
+ "Tachys Technologies", "Equator Technology", "Concept Computer", "SILCOM",
+ "3Dlabs", "c't Magazine", "Sanera Systems", "Silicon Packets",
+ "Viasystems Group", "Simtek", "Semicon Devices Singapore", "Satron Handelsges",
+ "Improv Systems", "INDUSYS GmbH", "Corrent", "Infrant Technologies",
+ "Ritek Corp", "empowerTel Networks", "Hypertec", "Cavium Networks",
+ "PLX Technology", "Massana Design", "Intrinsity", "Valence Semiconductor",
+ "Terawave Communications", "IceFyre Semiconductor", "Primarion", "Picochip Designs Ltd",
+ "Silverback Systems", "Jade Star Technologies", "Pijnenburg Securealink",
+ "takeMS - Ultron AG (former Memorysolution GmbH)", "Cambridge Silicon Radio",
+ "Swissbit", "Nazomi Communications", "eWave System",
+ "Rockwell Collins", "Picocel Co., Ltd.", "Alphamosaic Ltd", "Sandburst",
+ "SiCon Video", "NanoAmp Solutions", "Ericsson Technology", "PrairieComm",
+ "Mitac International", "Layer N Networks", "MtekVision", "Allegro Networks",
+ "Marvell Semiconductors", "Netergy Microelectronic", "NVIDIA", "Internet Machines",
+ "Peak Electronics", "Litchfield Communication", "Accton Technology", "Teradiant Networks",
+ "Scaleo Chip (former Europe Technologies)", "Cortina Systems", "RAM Components", "Raqia Networks",
+ "ClearSpeed", "Matsushita Battery", "Xelerated", "SimpleTech",
+ "Utron Technology", "Astec International", "AVM gmbH", "Redux Communications",
+ "Dot Hill Systems", "TeraChip"},
+{"T-RAM Incorporated", "Innovics Wireless", "Teknovus", "KeyEye Communications",
+ "Runcom Technologies", "RedSwitch", "Dotcast", "Silicon Mountain Memory",
+ "Signia Technologies", "Pixim", "Galazar Networks", "White Electronic Designs",
+ "Patriot Scientific", "Neoaxiom Corporation", "3Y Power Technology", "Scaleo Chip (former Europe Technologies)",
+ "Potentia Power Systems", "C-guys Incorporated", "Digital Communications Technology Incorporated", "Silicon-Based Technology",
+ "Fulcrum Microsystems", "Positivo Informatica Ltd", "XIOtech Corporation", "PortalPlayer",
+ "Zhiying Software", "Parker Vision, Inc. (former Direct2Data)", "Phonex Broadband", "Skyworks Solutions",
+ "Entropic Communications", "Pacific Force Technology", "Zensys A/S", "Legend Silicon Corp.",
+ "sci-worx GmbH", "SMSC (former Oasis Silicon Systems)", "Renesas Electronics (former Renesas Technology)", "Raza Microelectronics",
+ "Phyworks", "MediaTek", "Non-cents Productions", "US Modular",
+ "Wintegra Ltd", "Mathstar", "StarCore", "Oplus Technologies",
+ "Mindspeed", "Just Young Computer", "Radia Communications", "OCZ",
+ "Emuzed", "LOGIC Devices", "Inphi Corporation", "Quake Technologies",
+ "Vixel", "SolusTek", "Kongsberg Maritime", "Faraday Technology",
+ "Altium Ltd.", "Insyte", "ARM Ltd.", "DigiVision",
+ "Vativ Technologies", "Endicott Interconnect Technologies", "Pericom", "Bandspeed",
+ "LeWiz Communications", "CPU Technology", "Ramaxel Technology", "DSP Group",
+ "Axis Communications", "Legacy Electronics", "Chrontel", "Powerchip Semiconductor",
+ "MobilEye Technologies", "Excel Semiconductor", "A-DATA Technology", "VirtualDigm",
+ "G.Skill Intl", "Quanta Computer", "Yield Microelectronics", "Afa Technologies",
+ "KINGBOX Technology Co. Ltd.", "Ceva", "iStor Networks", "Advance Modules",
+ "Microsoft", "Open-Silicon", "Goal Semiconductor", "ARC International",
+ "Simmtec", "Metanoia", "Key Stream", "Lowrance Electronics",
+ "Adimos", "SiGe Semiconductor", "Fodus Communications", "Credence Systems Corp.",
+ "Genesis Microchip Inc.", "Vihana, Inc.", "WIS Technologies", "GateChange Technologies",
+ "High Density Devices AS", "Synopsys", "Gigaram", "Enigma Semiconductor Inc.",
+ "Century Micro Inc.", "Icera Semiconductor", "Mediaworks Integrated Systems", "O'Neil Product Development",
+ "Supreme Top Technology Ltd.", "MicroDisplay Corporation", "Team Group Inc.", "Sinett Corporation",
+ "Toshiba Corporation", "Tensilica", "SiRF Technology", "Bacoc Inc.",
+ "SMaL Camera Technologies", "Thomson SC", "Airgo Networks", "Wisair Ltd.",
+ "SigmaTel", "Arkados", "Compete IT gmbH Co. KG", "Eudar Technology Inc.",
+ "Focus Enhancements", "Xyratex"},
+{"Specular Networks", "Patriot Memory", "U-Chip Technology Corp.", "Silicon Optix",
+ "Greenfield Networks", "CompuRAM GmbH", "Stargen, Inc.", "NetCell Corporation",
+ "Excalibrus Technologies Ltd", "SCM Microsystems", "Xsigo Systems, Inc.", "CHIPS & Systems Inc",
+ "Tier 1 Multichip Solutions", "CWRL Labs", "Teradici", "Gigaram, Inc.",
+ "g2 Microsystems", "PowerFlash Semiconductor", "P.A. Semi, Inc.", "NovaTech Solutions, S.A.",
+ "c2 Microsystems, Inc.", "Level5 Networks", "COS Memory AG", "Innovasic Semiconductor",
+ "02IC Co. Ltd", "Tabula, Inc.", "Crucial Technology", "Chelsio Communications",
+ "Solarflare Communications", "Xambala Inc.", "EADS Astrium", "Terra Semiconductor Inc. (former ATO Semicon Co. Ltd.)",
+ "Imaging Works, Inc.", "Astute Networks, Inc.", "Tzero", "Emulex",
+ "Power-One", "Pulse~LINK Inc.", "Hon Hai Precision Industry", "White Rock Networks Inc.",
+ "Telegent Systems USA, Inc.", "Atrua Technologies, Inc.", "Acbel Polytech Inc.",
+ "eRide Inc.","ULi Electronics Inc.", "Magnum Semiconductor Inc.", "neoOne Technology, Inc.",
+ "Connex Technology, Inc.", "Stream Processors, Inc.", "Focus Enhancements", "Telecis Wireless, Inc.",
+ "uNav Microelectronics", "Tarari, Inc.", "Ambric, Inc.", "Newport Media, Inc.", "VMTS",
+ "Enuclia Semiconductor, Inc.", "Virtium Technology Inc.", "Solid State System Co., Ltd.", "Kian Tech LLC",
+ "Artimi", "Power Quotient International", "Avago Technologies", "ADTechnology", "Sigma Designs",
+ "SiCortex, Inc.", "Ventura Technology Group", "eASIC", "M.H.S. SAS", "Micro Star International",
+ "Rapport Inc.", "Makway International", "Broad Reach Engineering Co.",
+ "Semiconductor Mfg Intl Corp", "SiConnect", "FCI USA Inc.", "Validity Sensors",
+ "Coney Technology Co. Ltd.", "Spans Logic", "Neterion Inc.", "Qimonda",
+ "New Japan Radio Co. Ltd.", "Velogix", "Montalvo Systems", "iVivity Inc.", "Walton Chaintech",
+ "AENEON", "Lorom Industrial Co. Ltd.", "Radiospire Networks", "Sensio Technologies, Inc.",
+ "Nethra Imaging", "Hexon Technology Pte Ltd", "CompuStocx (CSX)", "Methode Electronics, Inc.",
+ "Connect One Ltd.", "Opulan Technologies", "Septentrio NV", "Goldenmars Technology Inc.",
+ "Kreton Corporation", "Cochlear Ltd.", "Altair Semiconductor", "NetEffect, Inc.",
+ "Spansion, Inc.", "Taiwan Semiconductor Mfg", "Emphany Systems Inc.",
+ "ApaceWave Technologies", "Mobilygen Corporation", "Tego", "Cswitch Corporation",
+ "Haier (Beijing) IC Design Co.", "MetaRAM", "Axel Electronics Co. Ltd.", "Tilera Corporation",
+ "Aquantia", "Vivace Semiconductor", "Redpine Signals", "Octalica", "InterDigital Communications",
+ "Avant Technology", "Asrock, Inc.", "Availink", "Quartics, Inc.", "Element CXI",
+ "Innovaciones Microelectronicas", "VeriSilicon Microelectronics", "W5 Networks"},
+{"MOVEKING", "Mavrix Technology, Inc.", "CellGuide Ltd.", "Faraday Technology",
+ "Diablo Technologies, Inc.", "Jennic", "Octasic", "Molex Incorporated", "3Leaf Networks",
+ "Bright Micron Technology", "Netxen", "NextWave Broadband Inc.", "DisplayLink", "ZMOS Technology",
+ "Tec-Hill", "Multigig, Inc.", "Amimon", "Euphonic Technologies, Inc.", "BRN Phoenix",
+ "InSilica", "Ember Corporation", "Avexir Technologies Corporation", "Echelon Corporation",
+ "Edgewater Computer Systems", "XMOS Semiconductor Ltd.", "GENUSION, Inc.", "Memory Corp NV",
+ "SiliconBlue Technologies", "Rambus Inc.", "Andes Technology Corporation", "Coronis Systems",
+ "Achronix Semiconductor", "Siano Mobile Silicon Ltd.", "Semtech Corporation", "Pixelworks Inc.",
+ "Gaisler Research AB", "Teranetics", "Toppan Printing Co. Ltd.", "Kingxcon",
+ "Silicon Integrated Systems", "I-O Data Device, Inc.", "NDS Americas Inc.", "Solomon Systech Limited",
+ "On Demand Microelectronics", "Amicus Wireless Inc.", "SMARDTV SNC", "Comsys Communication Ltd.",
+ "Movidia Ltd.", "Javad GNSS, Inc.", "Montage Technology Group", "Trident Microsystems", "Super Talent",
+ "Optichron, Inc.", "Future Waves UK Ltd.", "SiBEAM, Inc.", "Inicore, Inc.", "Virident Systems",
+ "M2000, Inc.", "ZeroG Wireless, Inc.", "Gingle Technology Co. Ltd.", "Space Micro Inc.", "Wilocity",
+ "Novafora, Inc.", "iKoa Corporation", "ASint Technology", "Ramtron", "Plato Networks Inc.",
+ "IPtronics AS", "Infinite-Memories", "Parade Technologies Inc.", "Dune Networks",
+ "GigaDevice Semiconductor", "Modu Ltd.", "CEITEC", "Northrop Grumman", "XRONET Corporation",
+ "Sicon Semiconductor AB", "Atla Electronics Co. Ltd.", "TOPRAM Technology", "Silego Technology Inc.",
+ "Kinglife", "Ability Industries Ltd.", "Silicon Power Computer & Communications",
+ "Augusta Technology, Inc.", "Nantronics Semiconductors", "Hilscher Gesellschaft", "Quixant Ltd.",
+ "Percello Ltd.", "NextIO Inc.", "Scanimetrics Inc.", "FS-Semi Company Ltd.", "Infinera Corporation",
+ "SandForce Inc.", "Lexar Media", "Teradyne Inc.", "Memory Exchange Corp.", "Suzhou Smartek Electronics",
+ "Avantium Corporation", "ATP Electronics Inc.", "Valens Semiconductor Ltd", "Agate Logic, Inc.",
+ "Netronome", "Zenverge, Inc.", "N-trig Ltd", "SanMax Technologies Inc.", "Contour Semiconductor Inc.",
+ "TwinMOS", "Silicon Systems, Inc.", "V-Color Technology Inc.", "Certicom Corporation", "JSC ICC Milandr",
+ "PhotoFast Global Inc.", "InnoDisk Corporation", "Muscle Power", "Energy Micro", "Innofidei",
+ "CopperGate Communications", "Holtek Semiconductor Inc.", "Myson Century, Inc.", "FIDELIX",
+ "Red Digital Cinema", "Densbits Technology", "Zempro", "MoSys", "Provigent", "Triad Semiconductor, Inc."},
+{"Siklu Communication Ltd.", "A Force Manufacturing Ltd.", "Strontium", "Abilis Systems", "Siglead, Inc.",
+ "Ubicom, Inc.", "Unifosa Corporation", "Stretch, Inc.", "Lantiq Deutschland GmbH", "Visipro",
+ "EKMemory", "Microelectronics Institute ZTE", "Cognovo Ltd.", "Carry Technology Co. Ltd.", "Nokia",
+ "King Tiger Technology", "Sierra Wireless", "HT Micron", "Albatron Technology Co. Ltd.",
+ "Leica Geosystems AG", "BroadLight", "AEXEA", "ClariPhy Communications, Inc.", "Green Plug",
+ "Design Art Networks", "Mach Xtreme Technology Ltd.", "ATO Solutions Co. Ltd.", "Ramsta",
+ "Greenliant Systems, Ltd.", "Teikon", "Antec Hadron", "NavCom Technology, Inc.",
+ "Shanghai Fudan Microelectronics", "Calxeda, Inc.", "JSC EDC Electronics", "Kandit Technology Co. Ltd.",
+ "Ramos Technology", "Goldenmars Technology", "XeL Technology Inc.", "Newzone Corporation",
+ "ShenZhen MercyPower Tech", "Nanjing Yihuo Technology", "Nethra Imaging Inc.", "SiTel Semiconductor BV",
+ "SolidGear Corporation", "Topower Computer Ind Co Ltd.", "Wilocity", "Profichip GmbH",
+ "Gerad Technologies", "Ritek Corporation", "Gomos Technology Limited", "Memoright Corporation",
+ "D-Broad, Inc.", "HiSilicon Technologies", "Syndiant Inc.", "Enverv Inc.", "Cognex",
+ "Xinnova Technology Inc.", "Ultron AG", "Concord Idea Corporation", "AIM Corporation",
+ "Lifetime Memory Products", "Ramsway", "Recore Systems BV", "Haotian Jinshibo Science Tech",
+ "Being Advanced Memory", "Adesto Technologies", "Giantec Semiconductor, Inc.", "HMD Electronics AG",
+ "Gloway International (HK)", "Kingcore", "Anucell Technology Holding",
+ "Accord Software & Systems Pvt. Ltd.", "Active-Semi Inc.", "Denso Corporation", "TLSI Inc.",
+ "Shenzhen Daling Electronic Co. Ltd.", "Mustang", "Orca Systems", "Passif Semiconductor",
+ "GigaDevice Semiconductor (Beijing) Inc.", "Memphis Electronic", "Beckhoff Automation GmbH",
+ "Harmony Semiconductor Corp (former ProPlus Design Solutions)", "Air Computers SRL", "TMT Memory",
+ "Eorex Corporation", "Xingtera", "Netsol", "Bestdon Technology Co. Ltd.", "Baysand Inc.",
+ "Uroad Technology Co. Ltd. (former Triple Grow Industrial Ltd.)", "Wilk Elektronik S.A.",
+ "AAI", "Harman", "Berg Microelectronics Inc.", "ASSIA, Inc.", "Visiontek Products LLC",
+ "OCMEMORY", "Welink Solution Inc.", "Shark Gaming", "Avalanche Technology",
+ "R&D Center ELVEES OJSC", "KingboMars Technology Co. Ltd.",
+ "High Bridge Solutions Industria Eletronica", "Transcend Technology Co. Ltd.",
+ "Everspin Technologies", "Hon-Hai Precision", "Smart Storage Systems", "Toumaz Group",
+ "Zentel Electronics Corporation", "Panram International Corporation",
+ "Silicon Space Technology"}
+};
diff --git a/modules/devices/storage.c b/modules/devices/storage.c
index 0c393682..bbf9b195 100644
--- a/modules/devices/storage.c
+++ b/modules/devices/storage.c
@@ -1,10 +1,11 @@
/*
* HardInfo - Displays System Information
- * Copyright (C) 2003-2006 Leandro A. F. Pereira <leandro@hardinfo.org>
+ * Copyright (C) 2003-2006 L. A. F. Pereira <l@tia.mat.br>
+ * modified by Ondrej ÄŒerman (2019-2021)
*
* 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.
+ * the Free Software Foundation, version 2 or later.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -20,12 +21,464 @@
#include "hardinfo.h"
#include "devices.h"
+#include "udisks2_util.h"
+#include "storage_util.h"
+
+#define UNKIFNULL_AC(f) (f != NULL) ? f : _("(Unknown)");
gchar *storage_icons = NULL;
+gchar *nvme_pci_sections(pcid *p) {
+ const gchar *vendor, *svendor, *product, *sproduct;
+
+ if (!p) return NULL;
+
+ vendor = UNKIFNULL_AC(p->vendor_id_str);
+ svendor = UNKIFNULL_AC(p->sub_vendor_id_str);
+ product = UNKIFNULL_AC(p->device_id_str);
+ sproduct = UNKIFNULL_AC(p->sub_device_id_str);
+
+ gchar *vendor_device_str;
+ if (p->vendor_id == p->sub_vendor_id && p->device_id == p->sub_device_id) {
+ vendor_device_str = g_strdup_printf("[%s]\n"
+ /* Vendor */ "$^$%s=[%04x] %s\n"
+ /* Device */ "%s=[%04x] %s\n",
+ _("NVMe Controller"),
+ _("Vendor"), p->vendor_id, vendor,
+ _("Device"), p->device_id, product);
+ } else {
+ vendor_device_str = g_strdup_printf("[%s]\n"
+ /* Vendor */ "$^$%s=[%04x] %s\n"
+ /* Device */ "%s=[%04x] %s\n"
+ /* Sub-device vendor */ "$^$%s=[%04x] %s\n"
+ /* Sub-device */ "%s=[%04x] %s\n",
+ _("NVMe Controller"),
+ _("Vendor"), p->vendor_id, vendor,
+ _("Device"), p->device_id, product,
+ _("SVendor"), p->sub_vendor_id, svendor,
+ _("SDevice"), p->sub_device_id, sproduct);
+ }
+
+ gchar *pcie_str;
+ if (p->pcie_width_curr) {
+ pcie_str = g_strdup_printf("[%s]\n"
+ /* Addy */ "%s=PCI/%s\n"
+ /* Width (max) */ "%s=x%u\n"
+ /* Speed (max) */ "%s=%0.1f %s\n",
+ _("PCI Express"),
+ _("Location"), p->slot_str,
+ _("Maximum Link Width"), p->pcie_width_max,
+ _("Maximum Link Speed"), p->pcie_speed_max, _("GT/s") );
+ } else
+ pcie_str = strdup("");
+
+ gchar *ret = g_strdup_printf("%s%s", vendor_device_str, pcie_str);
+ g_free(vendor_device_str);
+ g_free(pcie_str);
+ return ret;
+}
+
+gboolean __scan_udisks2_devices(void) {
+ GSList *node, *drives;
+ u2driveext *ext;
+ udiskd *disk;
+ udiskp *part;
+ udisksa *attrib;
+ gchar *udisks2_storage_list = NULL, *features = NULL, *moreinfo = NULL;
+ gchar *devid, *size, *tmp = NULL, *media_comp = NULL, *ven_tag = NULL;
+ const gchar *url, *media_label, *alabel, *icon, *media_curr = NULL;
+ int n = 0, i, j, m;
+
+ // http://storaged.org/doc/udisks2-api/latest/gdbus-org.freedesktop.UDisks2.Drive.html#gdbus-property-org-freedesktop-UDisks2-Drive.MediaCompatibility
+ static struct {
+ char *media;
+ char *label;
+ char *icon;
+ } media_info[] = {
+ { "thumb", "Thumb-drive", "usbfldisk" },
+ { "flash", "Flash Card", "usbfldisk" },
+ { "flash_cf", "CompactFlash", "usbfldisk" },
+ { "flash_ms", "MemoryStick", "usbfldisk" },
+ { "flash_sm", "SmartMedia", "usbfldisk" },
+ { "flash_sd", "SD", "usbfldisk" },
+ { "flash_sdhc", "SDHC", "usbfldisk" },
+ { "flash_sdxc", "SDXC", "usbfldisk" },
+ { "flash_mmc", "MMC", "usbfldisk" },
+ { "floppy", "Floppy Disk", "media-floppy" },
+ { "floppy_zip", "Zip Disk", "media-floppy" },
+ { "floppy_jaz", "Jaz Disk", "media-floppy" },
+ { "optical", "Optical Disc", "cdrom" },
+ { "optical_cd", "CD-ROM", "cdrom" },
+ { "optical_cd_r", "CD-R", "cdrom" },
+ { "optical_cd_rw", "CD-RW", "cdrom" },
+ { "optical_dvd", "DVD-ROM", "cdrom" },
+ { "optical_dvd_r", "DVD-R", "cdrom" },
+ { "optical_dvd_rw", "DVD-RW", "cdrom" },
+ { "optical_dvd_ram", "DVD-RAM", "cdrom" },
+ { "optical_dvd_plus_r", "DVD+R" , "cdrom" },
+ { "optical_dvd_plus_rw", "DVD+RW" , "cdrom" },
+ { "optical_dvd_plus_r_dl", "DVD+R DL", "cdrom" },
+ { "optical_dvd_plus_rw_dl", "DVD+RW DL", "cdrom" },
+ { "optical_bd", "BD-ROM", "cdrom" },
+ { "optical_bd_r", "BD-R", "cdrom" },
+ { "optical_bd_re", "BD-RE", "cdrom" },
+ { "optical_hddvd", "HD DVD-ROM", "cdrom" },
+ { "optical_hddvd_r", "HD DVD-R", "cdrom" },
+ { "optical_hddvd_rw", "HD DVD-RW", "cdrom" },
+ { "optical_mo", "MO Disc", "cdrom" },
+ { "optical_mrw", "MRW Media", "cdrom" },
+ { "optical_mrw_w", "MRW Media (write)", "cdrom" },
+ { NULL, NULL }
+ };
+
+ struct {
+ char *identifier;
+ char *label;
+ } smart_attrib_info[] = {
+ { "raw-read-error-rate", _("Read Error Rate" ) },
+ { "throughput-performance", _("Throughput Performance") },
+ { "spin-up-time", _("Spin-Up Time") },
+ { "start-stop-count", _("Start/Stop Count") },
+ { "reallocated-sector-count", _("Reallocated Sector Count") },
+ { "read-channel-margin", _("Read Channel Margin") },
+ { "seek-error-rate", _("Seek Error Rate") },
+ { "seek-time-performance", _("Seek Timer Performance") },
+ { "power-on-hours", _("Power-On Hours") },
+ { "spin-retry-count", _("Spin Retry Count") },
+ { "calibration-retry-count", _("Calibration Retry Count") },
+ { "power-cycle-count", _("Power Cycle Count") },
+ { "read-soft-error-rate", _("Soft Read Error Rate") },
+ { "runtime-bad-block-total", _("Runtime Bad Block") },
+ { "end-to-end-error", _("End-to-End error") },
+ { "reported-uncorrect", _("Reported Uncorrectable Errors") },
+ { "command-timeout", _("Command Timeout") },
+ { "high-fly-writes", _("High Fly Writes") },
+ { "airflow-temperature-celsius", _("Airflow Temperature") },
+ { "g-sense-error-rate", _("G-sense Error Rate") },
+ { "power-off-retract-count", _("Power-off Retract Count") },
+ { "load-cycle-count", _("Load Cycle Count") },
+ { "temperature-celsius-2", _("Temperature") },
+ { "hardware-ecc-recovered", _("Hardware ECC Recovered") },
+ { "reallocated-event-count", _("Reallocation Event Count") },
+ { "current-pending-sector", _("Current Pending Sector Count") },
+ { "offline-uncorrectable", _("Uncorrectable Sector Count") },
+ { "udma-crc-error-count", _("UltraDMA CRC Error Count") },
+ { "multi-zone-error-rate", _("Multi-Zone Error Rate") },
+ { "soft-read-error-rate", _("Soft Read Error Rate") },
+ { "run-out-cancel", _("Run Out Cancel") },
+ { "flying-height", _("Flying Height") },
+ { "spin-high-current", _("Spin High Current") },
+ { "spin-buzz", _("Spin Buzz") },
+ { "offline-seek-performance", _("Offline Seek Performance") },
+ { "disk-shift", _("Disk Shift") },
+ { "g-sense-error-rate-2", _("G-Sense Error Rate") },
+ { "loaded-hours", _("Loaded Hours") },
+ { "load-retry-count", _("Load/Unload Retry Count") },
+ { "load-friction", _("Load Friction") },
+ { "load-cycle-count-2", _("Load/Unload Cycle Count") },
+ { "load-in-time", _("Load-in time") },
+ { "torq-amp-count", _("Torque Amplification Count") },
+ { "power-off-retract-count-2", _("Power-Off Retract Count") },
+ { "head-amplitude", _("GMR Head Amplitude") },
+ { "temperature-celsius", _("Temperature") },
+ { "endurance-remaining", _("Endurance Remaining") },
+ { "power-on-seconds-2", _("Power-On Hours") },
+ { "good-block-rate", _("Good Block Rate") },
+ { "head-flying-hours", _("Head Flying Hours") },
+ { "read-error-retry-rate", _("Read Error Retry Rate") },
+ { "total-lbas-written", _("Total LBAs Written") },
+ { "total-lbas-read", _("Total LBAs Read") },
+ { "wear-leveling-count", _("Wear leveling Count") },
+ { "used-reserved-blocks-total", _("Total Used Reserved Block Count") },
+ { "program-fail-count-total", _("Total Program Fail Count") },
+ { "erase-fail-count-total", _("Total Erase Fail Count") },
+ { "available-reserved-space", _("Available Reserved Space") },
+ { "program-fail-count", _("Program Fail Count") },
+ { "erase-fail-count", _("Erase Fail Count") },
+ { "ta-increase-count", _("TA Counter Increased") },
+ { "unused-reserved-blocks", _("Total Unused Reserved Block Count") },
+ { NULL, NULL }
+ };
+
+ moreinfo_del_with_prefix("DEV:UDISKS");
+ udisks2_storage_list = g_strdup(_("\n[UDisks2]\n"));
+
+ drives = get_udisks2_drives_ext();
+ for (node = drives; node != NULL; node = node->next) {
+ ext = (u2driveext *)node->data;
+ disk = ext->d;
+ devid = g_strdup_printf("UDISKS%d", n++);
+
+ icon = NULL;
+
+ media_curr = disk->media;
+ if (disk->media){
+ for (j = 0; media_info[j].media != NULL; j++) {
+ if (g_strcmp0(disk->media, media_info[j].media) == 0) {
+ media_curr = media_info[j].label;
+ break;
+ }
+ }
+ }
+
+ if (disk->media_compatibility){
+ for (i = 0; disk->media_compatibility[i] != NULL; i++){
+ media_label = disk->media_compatibility[i];
+
+ for (j = 0; media_info[j].media != NULL; j++) {
+ if (g_strcmp0(disk->media_compatibility[i], media_info[j].media) == 0) {
+ media_label = media_info[j].label;
+ if (icon == NULL)
+ icon = media_info[j].icon;
+ break;
+ }
+ }
+
+ if (media_comp == NULL){
+ media_comp = g_strdup(media_label);
+ }
+ else{
+ media_comp = h_strdup_cprintf(", %s", media_comp, media_label);
+ }
+ }
+ }
+ if (icon == NULL && disk->ejectable && g_strcmp0(disk->connection_bus, "usb") == 0) {
+ icon = "usbfldisk";
+ }
+ if (icon == NULL){
+ icon = "hdd";
+ }
+
+ size = size_human_readable((gfloat) disk->size);
+ ven_tag = vendor_list_ribbon(ext->vendors, params.fmt_opts);
+
+ udisks2_storage_list = h_strdup_cprintf("$%s$%s=%s|%s %s\n", udisks2_storage_list, devid, disk->block_dev, size, ven_tag ? ven_tag : "", disk->model);
+ storage_icons = h_strdup_cprintf("Icon$%s$%s=%s.png\n", storage_icons, devid, disk->model, icon);
+ features = h_strdup_cprintf("%s", features, disk->removable ? _("Removable"): _("Fixed"));
+
+ if (disk->ejectable) {
+ features = h_strdup_cprintf(", %s", features, _("Ejectable"));
+ }
+ if (disk->smart_supported) {
+ features = h_strdup_cprintf(", %s", features, _("Self-monitoring (S.M.A.R.T.)"));
+ }
+ if (disk->pm_supported) {
+ features = h_strdup_cprintf(", %s", features, _("Power Management"));
+ }
+ if (disk->apm_supported) {
+ features = h_strdup_cprintf(", %s", features, _("Advanced Power Management"));
+ }
+ if (disk->aam_supported) {
+ features = h_strdup_cprintf(", %s", features, _("Automatic Acoustic Management"));
+ }
+
+ moreinfo = g_strdup_printf(_("[Drive Information]\n"
+ "Model=%s\n"),
+ disk->model);
+
+ if (disk->vendor && *disk->vendor) {
+ moreinfo = h_strdup_cprintf("$^$%s=%s\n",
+ moreinfo,
+ _("Vendor"), disk->vendor);
+ }
+
+ moreinfo = h_strdup_cprintf(_("Revision=%s\n"
+ "Block Device=%s\n"
+ "Serial=%s\n"
+ "Size=%s\n"
+ "Features=%s\n"),
+ moreinfo,
+ disk->revision,
+ disk->block_dev,
+ disk->serial,
+ size,
+ features);
+ g_free(size);
+ g_free(ven_tag);
+
+ if (disk->rotation_rate > 0) {
+ moreinfo = h_strdup_cprintf(_("Rotation Rate=%d RPM\n"), moreinfo, disk->rotation_rate);
+ }
+ if (media_comp || media_curr) {
+ moreinfo = h_strdup_cprintf(_("Media=%s\n"
+ "Media compatibility=%s\n"),
+ moreinfo,
+ media_curr ? media_curr : _("(None)"),
+ media_comp ? media_comp : _("(Unknown)"));
+ }
+ if (disk->connection_bus && strlen(disk->connection_bus) > 0) {
+ moreinfo = h_strdup_cprintf(_("Connection bus=%s\n"), moreinfo, disk->connection_bus);
+ }
+
+ tmp = NULL;
+ if (disk->wwid) {
+ m = strlen(disk->wwid);
+ if (m > 2 && m % 2 == 0){
+ for (j = 4; j < m; j = j + 2) {
+ tmp = h_strdup_cprintf("%s%c%c", tmp, j > 4 ? "-": "", disk->wwid[j], disk->wwid[j+1]);
+ }
+ }
+ moreinfo = h_strdup_cprintf("%s=%s\n", moreinfo,
+ g_str_has_prefix(disk->wwid, "nna.") ? _("WWN"):
+ (g_str_has_prefix(disk->wwid, "eui.") ? _("EUI "): "Unknown ID"),
+ tmp);
+ g_free(tmp);
+ }
+ else{
+ moreinfo = h_strdup_cprintf("%s=%s\n", moreinfo, _("WWN / EUI"), _("(None)"));
+ }
+
+ if (ext->wwid_oui.oui) {
+ moreinfo = h_strdup_cprintf(_("$^$%s=[%s] %s\n"),
+ moreinfo,
+ _("IEEE OUI"), ext->wwid_oui.oui,
+ ext->wwid_oui.vendor ?
+ ext->wwid_oui.vendor : _("(Unknown)"));
+ }
+
+ if (ext->nvme_controller) {
+ gchar *nvme = nvme_pci_sections(ext->nvme_controller);
+ if (nvme)
+ moreinfo = h_strdup_cprintf("%s", moreinfo, nvme);
+ g_free(nvme);
+ }
+ if (disk->smart_enabled) {
+ moreinfo = h_strdup_cprintf(_("[Self-monitoring (S.M.A.R.T.)]\n"
+ "Status=%s\n"
+ "Bad Sectors=%" G_GINT64_FORMAT "\n"
+ "Power on time=%" G_GUINT64_FORMAT " days %" G_GUINT64_FORMAT " hours\n"
+ "Temperature=%d°C\n"),
+ moreinfo,
+ disk->smart_failing ? _("Failing"): _("OK"),
+ disk->smart_bad_sectors,
+ disk->smart_poweron/(60*60*24), (disk->smart_poweron/60/60) % 24,
+ disk->smart_temperature);
+
+ if (disk->smart_attributes != NULL) {
+ moreinfo = h_strdup_cprintf(_("[S.M.A.R.T. Attributes]\n"
+ "Attribute=<tt>Value / Normalized / Worst / Threshold</tt>\n"),
+ moreinfo);
+
+ attrib = disk->smart_attributes;
+
+ while (attrib != NULL){
+ tmp = g_strdup("");
+
+ switch (attrib->interpreted_unit){
+ case UDSK_INTPVAL_SKIP:
+ tmp = h_strdup_cprintf("-", tmp);
+ break;
+ case UDSK_INTPVAL_MILISECONDS:
+ tmp = h_strdup_cprintf("%" G_GINT64_FORMAT " ms", tmp, attrib->interpreted);
+ break;
+ case UDSK_INTPVAL_HOURS:
+ tmp = h_strdup_cprintf("%" G_GINT64_FORMAT " h", tmp, attrib->interpreted);
+ break;
+ case UDSK_INTPVAL_CELSIUS:
+ tmp = h_strdup_cprintf("%" G_GINT64_FORMAT "°C", tmp, attrib->interpreted);
+ break;
+ case UDSK_INTPVAL_SECTORS:
+ tmp = h_strdup_cprintf(ngettext("%" G_GINT64_FORMAT " sector",
+ "%" G_GINT64_FORMAT " sectors", attrib->interpreted),
+ tmp, attrib->interpreted);
+ break;
+ case UDSK_INTPVAL_DIMENSIONLESS:
+ default:
+ tmp = h_strdup_cprintf("%" G_GINT64_FORMAT, tmp, attrib->interpreted);
+ break;
+ }
+
+ // pad spaces to next col
+ j = g_utf8_strlen(tmp, -1);
+ if (j < 13) tmp = h_strdup_cprintf("%*c", tmp, 13 - j, ' ');
+
+ if (attrib->value != -1)
+ tmp = h_strdup_cprintf("%-13d", tmp, attrib->value);
+ else
+ tmp = h_strdup_cprintf("%-13s", tmp, "???");
+
+ if (attrib->worst != -1)
+ tmp = h_strdup_cprintf("%-8d", tmp, attrib->worst);
+ else
+ tmp = h_strdup_cprintf("%-8s", tmp, "???");
+
+ if (attrib->threshold != -1)
+ tmp = h_strdup_cprintf("%d", tmp, attrib->threshold);
+ else
+ tmp = h_strdup_cprintf("???", tmp);
+
+
+ alabel = attrib->identifier;
+ for (i = 0; smart_attrib_info[i].identifier != NULL; i++) {
+ if (g_strcmp0(attrib->identifier, smart_attrib_info[i].identifier) == 0) {
+ alabel = smart_attrib_info[i].label;
+ break;
+ }
+ }
+
+ moreinfo = h_strdup_cprintf(_("(%d) %s=<tt>%s</tt>\n"),
+ moreinfo,
+ attrib->id, alabel, tmp);
+ g_free(tmp);
+ attrib = attrib->next;
+ }
+ }
+ }
+ if (disk->partition_table || disk->partitions) {
+ moreinfo = h_strdup_cprintf(_("[Partition table]\n"
+ "Type=%s\n"),
+ moreinfo,
+ disk->partition_table ? disk->partition_table : _("(Unknown)"));
+
+ if (disk->partitions != NULL) {
+ part = disk->partitions;
+ while (part != NULL){
+
+ tmp = size_human_readable((gfloat) part->size);
+ if (part->label) {
+ tmp = h_strdup_cprintf(" - %s", tmp, part->label);
+ }
+ if (part->type && part->version) {
+ tmp = h_strdup_cprintf(" (%s %s)", tmp, part->type, part->version);
+ }
+ else if (part->type) {
+ tmp = h_strdup_cprintf(" (%s)", tmp, part->type);
+ }
+ moreinfo = h_strdup_cprintf(_("Partition %s=%s\n"),
+ moreinfo,
+ part->block, tmp);
+ g_free(tmp);
+ part = part->next;
+ }
+ }
+ }
+
+ moreinfo_add_with_prefix("DEV", devid, moreinfo);
+ g_free(devid);
+ g_free(features);
+ g_free(media_comp);
+ media_comp = NULL;
+
+ features = NULL;
+ moreinfo = NULL;
+ devid = NULL;
+
+ u2driveext_free(ext);
+ }
+ g_slist_free(drives);
+
+ if (n) {
+ storage_list = h_strconcat(storage_list, udisks2_storage_list, NULL);
+ g_free(udisks2_storage_list);
+ return TRUE;
+ }
+
+ g_free(udisks2_storage_list);
+ return FALSE;
+}
+
/* SCSI support by Pascal F.Martin <pascalmartin@earthlink.net> */
-void
-__scan_scsi_devices(void)
+void __scan_scsi_devices(void)
{
FILE *proc_scsi;
gchar buffer[256], *buf;
@@ -40,12 +493,16 @@ __scan_scsi_devices(void)
/* remove old devices from global device table */
moreinfo_del_with_prefix("DEV:SCSI");
- if (!g_file_test("/proc/scsi/scsi", G_FILE_TEST_EXISTS))
- return;
-
scsi_storage_list = g_strdup(_("\n[SCSI Disks]\n"));
- if ((proc_scsi = fopen("/proc/scsi/scsi", "r"))) {
+ int otype = 0;
+ if (proc_scsi = fopen("/proc/scsi/scsi", "r")) {
+ otype = 1;
+ } else if (proc_scsi = popen("lsscsi -c", "r")) {
+ otype = 2;
+ }
+
+ if (otype) {
while (fgets(buffer, 256, proc_scsi)) {
buf = g_strstrip(buffer);
if (!strncmp(buf, "Host: scsi", 10)) {
@@ -104,23 +561,15 @@ __scan_scsi_devices(void)
}
gchar *devid = g_strdup_printf("SCSI%d", n);
- scsi_storage_list = h_strdup_cprintf("$%s$%s=\n", scsi_storage_list, devid, model);
+ scsi_storage_list = h_strdup_cprintf("$%s$scsi%d=|%s\n", scsi_storage_list, devid, scsi_controller, model);
storage_icons = h_strdup_cprintf("Icon$%s$%s=%s.png\n", storage_icons, devid, model, icon);
gchar *strhash = g_strdup_printf(_("[Device Information]\n"
"Model=%s\n"), model);
- const gchar *url = vendor_get_url(model);
- if (url) {
- strhash = h_strdup_cprintf(_("Vendor=%s (%s)\n"),
- strhash,
- vendor_get_name(model),
- url);
- } else {
- strhash = h_strdup_cprintf(_("Vendor=%s\n"),
- strhash,
- vendor_get_name(model));
- }
+ strhash = h_strdup_cprintf("$^$%s=%s\n",
+ strhash,
+ _("Vendor"), model);
strhash = h_strdup_cprintf(_("Type=%s\n"
"Revision=%s\n"
@@ -135,6 +584,7 @@ __scan_scsi_devices(void)
scsi_channel,
scsi_id,
scsi_lun);
+
moreinfo_add_with_prefix("DEV", devid, strhash);
g_free(devid);
@@ -145,7 +595,10 @@ __scan_scsi_devices(void)
scsi_controller = scsi_channel = scsi_id = scsi_lun = 0;
}
}
- fclose(proc_scsi);
+ if (otype == 1)
+ fclose(proc_scsi);
+ else if (otype == 2)
+ pclose(proc_scsi);
}
if (n) {
@@ -157,7 +610,8 @@ __scan_scsi_devices(void)
void __scan_ide_devices(void)
{
FILE *proc_ide;
- gchar *device, iface, *model, *media, *pgeometry = NULL, *lgeometry = NULL;
+ gchar *device, *model, *media, *pgeometry = NULL, *lgeometry = NULL;
+ gchar iface;
gint n = 0, i = 0, cache, nn = 0;
gchar *capab = NULL, *speed = NULL, *driver = NULL, *ide_storage_list;
@@ -305,7 +759,7 @@ void __scan_ide_devices(void)
gchar *devid = g_strdup_printf("IDE%d", n);
- ide_storage_list = h_strdup_cprintf("$%s$%s=\n", ide_storage_list, devid, model);
+ ide_storage_list = h_strdup_cprintf("$%s$hd%c=|%s\n", ide_storage_list, devid, iface, model);
storage_icons =
h_strdup_cprintf("Icon$%s$%s=%s.png\n", storage_icons,
devid, model, g_str_equal(media, "cdrom") ? "cdrom" : "hdd");
@@ -313,13 +767,8 @@ void __scan_ide_devices(void)
gchar *strhash = g_strdup_printf(_("[Device Information]\n" "Model=%s\n"),
model);
- const gchar *url = vendor_get_url(model);
-
- if (url) {
- strhash = h_strdup_cprintf(_("Vendor=%s (%s)\n"), strhash, vendor_get_name(model), url);
- } else {
- strhash = h_strdup_cprintf(_("Vendor=%s\n"), strhash, vendor_get_name(model));
- }
+ strhash = h_strdup_cprintf("$^$%s=%s\n",
+ strhash, _("Vendor"), model);
strhash = h_strdup_cprintf(_("Device Name=hd%c\n"
"Media=%s\n" "Cache=%dkb\n"), strhash, iface, media, cache);
diff --git a/modules/devices/usb.c b/modules/devices/usb.c
index 9366c7ce..c6a5ab39 100644
--- a/modules/devices/usb.c
+++ b/modules/devices/usb.c
@@ -1,10 +1,10 @@
/*
* HardInfo - Displays System Information
- * Copyright (C) 2003-2008 Leandro A. F. Pereira <leandro@hardinfo.org>
+ * Copyright (C) 2003-2008 L. A. F. Pereira <l@tia.mat.br>
*
* 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.
+ * the Free Software Foundation, version 2 or later.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -15,422 +15,210 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
-/*
- * FIXME:
- * - listing with sysfs does not generate device hierarchy
- */
#include <string.h>
+#include "cpu_util.h"
#include "hardinfo.h"
#include "devices.h"
+#include "usb_util.h"
gchar *usb_list = NULL;
-
-void __scan_usb_sysfs_add_device(gchar * endpoint, int n)
-{
- gchar *manufacturer, *product, *mxpwr, *tmp, *strhash;
- gint bus, classid, vendor, prodid;
- gfloat version, speed;
-
- classid = h_sysfs_read_int(endpoint, "bDeviceClass");
- vendor = h_sysfs_read_int(endpoint, "idVendor");
- prodid = h_sysfs_read_int(endpoint, "idProduct");
- bus = h_sysfs_read_int(endpoint, "busnum");
- speed = h_sysfs_read_float(endpoint, "speed");
- version = h_sysfs_read_float(endpoint, "version");
-
- if (!(mxpwr = h_sysfs_read_string(endpoint, "bMaxPower"))) {
- mxpwr = g_strdup_printf("%d %s", 0 , _("mA") );
- }
-
- if (!(manufacturer = h_sysfs_read_string(endpoint, "manufacturer"))) {
- manufacturer = g_strdup(_("(Unknown)"));
- }
-
- if (!(product = h_sysfs_read_string(endpoint, "product"))) {
- 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);
+gchar *usb_icons = NULL;
+
+#define UNKIFNULL_AC(f) (f != NULL) ? f : _("(Unknown)")
+#define IARR_END -2
+#define IARR_ANY -1
+
+static struct {
+ int class;
+ char *icon;
+} usb_class_icons[] = {
+ { 0x1, "audio"}, /* Audio */
+ { 0x2, "modem"}, /* Communications and CDC Control */
+ { 0x3, "inputdevices"}, /* HID (Human Interface Device) */
+ { 0x6, "camera-photo"}, /* Still Imaging */
+ { 0x7, "printer"}, /* Printer */
+ { 0x8, "media-removable"}, /* Mass storage */
+ { 0x9, "usb"}, /* Hub */
+ { 0xe, "camera-web"}, /* Video */
+ {IARR_END, NULL}
+};
+
+static struct {
+ int class, subclass, protocol;
+ char *icon;
+} usb_type_icons[] = {
+ { 0x2, 0x6, IARR_ANY, "network-interface"}, /* Ethernet Networking Control Model */
+ { 0x3, 0x1, 0x1, "keyboard"}, /* Keyboard */
+ { 0x3, 0x1, 0x2, "mouse"}, /* Mouse */
+ {0xe0, 0x1, 0x1, "bluetooth"}, /* Bluetooth Programming Interface */
+ {IARR_END, IARR_END, IARR_END, NULL},
+};
+
+static const char* get_class_icon(int class){
+ int i = 0;
+ while (usb_class_icons[i].class != IARR_END) {
+ if (usb_class_icons[i].class == class) {
+ return usb_class_icons[i].icon;
}
+ i++;
}
-
- 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("[%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);
+ return NULL;
}
-gboolean __scan_usb_sysfs(void)
-{
- GDir *sysfs;
- gchar *filename;
- const gchar *sysfs_path = "/sys/class/usb_endpoint";
- gint usb_device_number = 0;
-
- if (!(sysfs = g_dir_open(sysfs_path, 0, NULL))) {
- return FALSE;
- }
-
- if (usb_list) {
- moreinfo_del_with_prefix("DEV:USB");
- g_free(usb_list);
- }
- usb_list = g_strdup_printf("[%s]\n", _("USB Devices"));
-
- while ((filename = (gchar *) g_dir_read_name(sysfs))) {
- gchar *endpoint =
- g_build_filename(sysfs_path, filename, "device", NULL);
- gchar *temp;
+static const char* get_usbif_icon(const usbi *usbif) {
+ int i = 0;
+ while (usb_type_icons[i].class != IARR_END) {
+ if (usb_type_icons[i].class == usbif->if_class && usb_type_icons[i].subclass == usbif->if_subclass &&
+ (usb_type_icons[i].protocol == IARR_ANY || usb_type_icons[i].protocol == usbif->if_protocol)) {
- temp = g_build_filename(endpoint, "idVendor", NULL);
- if (g_file_test(temp, G_FILE_TEST_EXISTS)) {
- __scan_usb_sysfs_add_device(endpoint, ++usb_device_number);
- }
-
- g_free(temp);
- g_free(endpoint);
+ return usb_type_icons[i].icon;
+ }
+ i++;
}
- g_dir_close(sysfs);
-
- return usb_device_number > 0;
+ return get_class_icon(usbif->if_class);
}
-gboolean __scan_usb_procfs(void)
-{
- FILE *dev;
- gchar buffer[128];
- gchar *tmp, *manuf = NULL, *product = NULL, *mxpwr = NULL;
- gint bus = 0, level = 0, port = 0, classid = 0, trash;
- gint vendor = 0, prodid = 0;
- gfloat ver = 0.0f, rev = 0.0f, speed = 0.0f;
- int n = 0;
-
- dev = fopen("/proc/bus/usb/devices", "r");
- if (!dev)
- return 0;
+static const char* get_usbdev_icon(const usbd *u) {
+ const char * icon = NULL;
+ usbi *curr_if;
- if (usb_list) {
- moreinfo_del_with_prefix("DEV:USB");
- g_free(usb_list);
+ curr_if = u->if_list;
+ while (icon == NULL && curr_if != NULL){
+ icon = get_usbif_icon(curr_if);
+ curr_if = curr_if->next;
}
- usb_list = g_strdup_printf("[%s]\n", _("USB Devices"));
-
- while (fgets(buffer, 128, dev)) {
- tmp = buffer;
- switch (*tmp) {
- case 'T':
- sscanf(tmp,
- "T: Bus=%d Lev=%d Prnt=%d Port=%d Cnt=%d Dev#=%d Spd=%f",
- &bus, &level, &trash, &port, &trash, &trash, &speed);
- break;
- case 'D':
- sscanf(tmp, "D: Ver=%f Cls=%x", &ver, &classid);
- break;
- case 'P':
- sscanf(tmp, "P: Vendor=%x ProdID=%x Rev=%f", &vendor, &prodid, &rev);
- break;
- case 'S':
- if (strstr(tmp, "Manufacturer=")) {
- manuf = g_strdup(strchr(tmp, '=') + 1);
- remove_linefeed(manuf);
- } else if (strstr(tmp, "Product=")) {
- product = g_strdup(strchr(tmp, '=') + 1);
- remove_linefeed(product);
- }
- break;
- case 'C':
- mxpwr = strstr(buffer, "MxPwr=") + 6;
-
- tmp = g_strdup_printf("USB%d", ++n);
-
- if (product && *product == '\0') {
- g_free(product);
- if (classid == 9) {
- product = g_strdup_printf(_("USB %.2f Hub"), ver);
- } else {
- 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);
-
- 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 = NULL;
- product = NULL;
- port = classid = 0;
- }
+ if (icon == NULL){
+ icon = get_class_icon(u->dev_class);
}
- fclose(dev);
-
- return n > 0;
+ return icon;
}
-
-void __scan_usb_lsusb_add_device(char *buffer, int bufsize, FILE * lsusb, int usb_device_number)
-{
- gint bus, device, vendor_id, product_id;
- gchar *version = NULL, *product = NULL, *vendor = NULL, *dev_class = NULL, *int_class = NULL;
- gchar *max_power = NULL, *name = NULL;
- gchar *tmp, *strhash;
- long position = 0;
-
- g_strstrip(buffer);
- sscanf(buffer, "Bus %d Device %d: ID %x:%x", &bus, &device, &vendor_id, &product_id);
- name = g_strdup(buffer + 33);
-
- for (fgets(buffer, bufsize, lsusb); position >= 0 && fgets(buffer, bufsize, lsusb); position = ftell(lsusb)) {
- g_strstrip(buffer);
-
- if (g_str_has_prefix(buffer, "idVendor")) {
- g_free(vendor);
- vendor = g_strdup(buffer + 26);
- } else if (g_str_has_prefix(buffer, "idProduct")) {
- g_free(product);
- product = g_strdup(buffer + 26);
- } else if (g_str_has_prefix(buffer, "MaxPower")) {
- g_free(max_power);
- max_power = g_strdup(buffer + 9);
- } else if (g_str_has_prefix(buffer, "bcdUSB")) {
- g_free(version);
- version = g_strdup(buffer + 7);
- } else if (g_str_has_prefix(buffer, "bDeviceClass")) {
- g_free(dev_class);
- dev_class = g_strdup(buffer + 14);
- } else if (g_str_has_prefix(buffer, "bInterfaceClass")) {
- g_free(int_class);
- int_class = g_strdup(buffer + 16);
- } else if (g_str_has_prefix(buffer, "Bus ")) {
- /* device separator */
- fseek(lsusb, position, SEEK_SET);
- break;
- }
- }
-
- 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)"));
- }
- } else
- 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);
-
- 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);
+static void _usb_dev(const usbd *u) {
+ gchar *name, *key, *label, *str, *speed;
+ gchar *product, *vendor, *manufacturer, *device; /* don't free */
+ gchar *interfaces = strdup("");
+ usbi *i;
+ const char* icon;
+
+ vendor = UNKIFNULL_AC(u->vendor);
+ product = UNKIFNULL_AC(u->product);
+ manufacturer = UNKIFNULL_AC(u->manufacturer);
+ device = UNKIFNULL_AC(u->device);
+
+ if (u->vendors) {
+ gchar *ribbon = vendor_list_ribbon(u->vendors, params.fmt_opts);
+ name = g_strdup_printf("%s %s", ribbon, u->product? product: device);
} else {
- v_str = g_strdup_printf("%s", g_strstrip(vendor) );
+ name = g_strdup_printf("%s %s", u->vendor? vendor: manufacturer, u->product? product: device);
+ }
+ key = g_strdup_printf("USB%03d:%03d:%03d", u->bus, u->dev, 0);
+ label = g_strdup_printf("%03d:%03d", u->bus, u->dev);
+ icon = get_usbdev_icon(u);
+
+ usb_list = h_strdup_cprintf("$%s$%s=%s\n", usb_list, key, label, name);
+ usb_icons = h_strdup_cprintf("Icon$%s$%s=%s.png\n", usb_icons, key, label, icon ? icon: "usb");
+
+ if (u->if_list != NULL) {
+ i = u->if_list;
+ while (i != NULL){
+ interfaces = h_strdup_cprintf("[%s %d %s]\n"
+ /* Class */ "%s=[%d] %s\n"
+ /* Sub-class */ "%s=[%d] %s\n"
+ /* Protocol */ "%s=[%d] %s\n"
+ /* Driver */ "%s=%s\n",
+ interfaces,
+ _("Interface"), i->if_number, i->if_label? i->if_label: "",
+ _("Class"), i->if_class, UNKIFNULL_AC(i->if_class_str),
+ _("Sub-class"), i->if_subclass, UNKIFNULL_AC(i->if_subclass_str),
+ _("Protocol"), i->if_protocol, UNKIFNULL_AC(i->if_protocol_str),
+ _("Driver"), UNKIFNULL_AC(i->driver)
+ );
+ i = i->next;
+ }
}
- 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;
+ if (u->speed_mbs > 0){
+ speed = g_strdup_printf("%d %s", u->speed_mbs, _("Mb/s"));
+ }
+ else{
+ speed = g_strdup(_("Unknown"));
}
- 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"
+ str = g_strdup_printf("[%s]\n"
+ /* Product */ "%s=[0x%04x] %s\n"
+ /* Vendor */ "$^$%s=[0x%04x] %s\n"
+ /* Device */ "%s=%s\n"
+ /* Manufacturer */ "$^$%s=%s\n"
+ /* Max Current */ "%s=%d %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",
+ /* Speed */ "%s=%s\n"
+ /* Class */ "%s=[%d] %s\n"
+ /* Sub-class */ "%s=[%d] %s\n"
+ /* Protocol */ "%s=[%d] %s\n"
+ /* Dev Version */ "%s=%s\n"
+ /* Serial */ "%s=%s\n"
+ "[%s]\n"
+ /* Bus */ "%s=%03d\n"
+ /* Device */ "%s=%03d\n"
+ /* Interfaces */ "%s",
_("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);
- g_free(dev_class);
- g_free(version);
- g_free(tmp);
+ _("Product"), u->product_id, product,
+ _("Vendor"), u->vendor_id, vendor,
+ _("Device"), device,
+ _("Manufacturer"), manufacturer,
+ _("Max Current"), u->max_curr_ma, _("mA"),
+ _("USB Version"), u->usb_version,
+ _("Speed"), speed,
+ _("Class"), u->dev_class, UNKIFNULL_AC(u->dev_class_str),
+ _("Sub-class"), u->dev_subclass, UNKIFNULL_AC(u->dev_subclass_str),
+ _("Protocol"), u->dev_protocol, UNKIFNULL_AC(u->dev_protocol_str),
+ _("Device Version"), UNKIFNULL_AC(u->device_version),
+ _("Serial Number"), UNKIFNULL_AC(u->serial),
+ _("Connection"),
+ _("Bus"), u->bus,
+ _("Device"), u->dev,
+ interfaces
+ );
+
+ moreinfo_add_with_prefix("DEV", key, str); /* str now owned by morinfo */
+
+ g_free(speed);
g_free(name);
+ g_free(key);
+ g_free(label);
+ g_free(interfaces);
}
-gboolean __scan_usb_lsusb(void)
-{
- static gchar *lsusb_path = NULL;
- int usb_device_number = 0;
- FILE *lsusb;
- FILE *temp_lsusb;
- char buffer[512], *temp;
+void __scan_usb(void) {
+ usbd *list = usb_get_device_list();
+ usbd *curr = list;
- if (!lsusb_path) {
- if (!(lsusb_path = find_program("lsusb"))) {
- DEBUG("lsusb not found");
-
- return FALSE;
- }
- }
-
- temp = g_strdup_printf("%s -v | tr '[]' '()'", lsusb_path);
- if (!(lsusb = popen(temp, "r"))) {
- DEBUG("cannot run %s", lsusb_path);
-
- g_free(temp);
- return FALSE;
- }
-
- temp_lsusb = tmpfile();
- if (!temp_lsusb) {
- DEBUG("cannot create temporary file for lsusb");
- pclose(lsusb);
- g_free(temp);
- return FALSE;
- }
-
- while (fgets(buffer, sizeof(buffer), lsusb)) {
- fputs(buffer, temp_lsusb);
- }
-
- pclose(lsusb);
-
- // rewind file so we can read from it
- fseek(temp_lsusb, 0, SEEK_SET);
-
- g_free(temp);
+ int c = usbd_list_count(list);
if (usb_list) {
- moreinfo_del_with_prefix("DEV:USB");
+ moreinfo_del_with_prefix("DEV:USB");
g_free(usb_list);
}
+ if (usb_icons){
+ g_free(usb_icons);
+ usb_icons = NULL;
+ }
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);
+ if (c > 0) {
+ while(curr) {
+ _usb_dev(curr);
+ curr=curr->next;
}
- }
-
- fclose(temp_lsusb);
- return usb_device_number > 0;
-}
-
-void __scan_usb(void)
-{
- if (!__scan_usb_procfs()) {
- if (!__scan_usb_sysfs()) {
- __scan_usb_lsusb();
- }
+ usbd_list_free(list);
+ } else {
+ /* No USB? */
+ usb_list = g_strconcat(usb_list, _("No USB devices found."), "=\n", NULL);
}
}
diff --git a/modules/devices/x86/processor.c b/modules/devices/x86/processor.c
index f1c2b6e9..4141f051 100644
--- a/modules/devices/x86/processor.c
+++ b/modules/devices/x86/processor.c
@@ -1,10 +1,10 @@
/*
* HardInfo - Displays System Information
- * Copyright (C) 2003-2006 Leandro A. F. Pereira <leandro@hardinfo.org>
+ * Copyright (C) 2003-2006 L. A. F. Pereira <l@tia.mat.br>
*
* 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.
+ * the Free Software Foundation, version 2 or later.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -19,7 +19,7 @@
#include "hardinfo.h"
#include "devices.h"
#include "cpu_util.h"
-
+#include "nice_name.h"
#include "x86_data.h"
#include "x86_data.c"
@@ -275,7 +275,7 @@ gchar *clocks_summary(GSList * processors)
/* create list of all clock references */
for (l = processors; l; l = l->next) {
p = (Processor*)l->data;
- if (p->cpufreq) {
+ if (p->cpufreq && p->cpufreq->cpukhz_max > 0) {
all_clocks = g_slist_prepend(all_clocks, p->cpufreq);
}
}
@@ -448,14 +448,15 @@ gchar *caches_summary(GSList * processors)
return ret;
}
-#define PROC_SCAN_READ_BUFFER_SIZE 896
+#define PROC_SCAN_READ_BUFFER_SIZE 1024
GSList *processor_scan(void)
{
GSList *procs = NULL, *l = NULL;
Processor *processor = NULL;
FILE *cpuinfo;
- gchar buffer[PROC_SCAN_READ_BUFFER_SIZE];
+ gchar *buffer;
+ buffer = g_malloc(PROC_SCAN_READ_BUFFER_SIZE);
cpuinfo = fopen(PROC_CPUINFO, "r");
if (!cpuinfo)
return NULL;
@@ -513,6 +514,7 @@ GSList *processor_scan(void)
}
fclose(cpuinfo);
+ g_free(buffer);
/* finish last */
if (processor)
@@ -567,6 +569,8 @@ GSList *processor_scan(void)
if (processor->cpufreq->cpukhz_max)
processor->cpu_mhz = processor->cpufreq->cpukhz_max / 1000;
+
+ nice_name_x86_cpuid_model_string(processor->model_name);
}
return procs;
@@ -584,7 +588,7 @@ gchar *processor_get_capabilities_from_flags(gchar *strflags, gchar *lookup_pref
old = flags;
while (flags[j]) {
- if ( sscanf(flags[j], "[%d]", &i) ) {
+ if ( sscanf(flags[j], "[%d]", &i)==1 ) {
/* Some flags are indexes, like [13], and that looks like
* a new section to hardinfo shell */
tmp = h_strdup_cprintf("(%s%d)=\n", tmp,
@@ -624,7 +628,7 @@ gchar *processor_get_detailed_info(Processor * processor)
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" /* vendor */
"%s=%s\n" /* microcode */
"[%s]\n" /* configuration */
"%s=%d %s\n" /* cache size (from cpuinfo) */
@@ -648,7 +652,7 @@ gchar *processor_get_detailed_info(Processor * processor)
processor->model,
processor->stepping,
processor->strmodel,
- _("Vendor"), vendor_get_name(processor->vendor_id),
+ _("Vendor"), processor->vendor_id,
_("Microcode Version"), processor->microcode,
_("Configuration"),
_("Cache Size"), processor->cache_size, _("kb"),
@@ -678,12 +682,62 @@ gchar *processor_describe(GSList * processors) {
return processor_describe_default(processors);
}
+gchar *dmi_socket_info() {
+ gchar *ret;
+ dmi_type dt = 4;
+ guint i;
+ dmi_handle_list *hl = dmidecode_handles(&dt);
+
+ if (!hl) {
+ ret = g_strdup_printf("[%s]\n%s=%s\n",
+ _("Socket Information"), _("Result"),
+ (getuid() == 0)
+ ? _("(Not available)")
+ : _("(Not available; Perhaps try running HardInfo as root.)") );
+ } else {
+ ret = g_strdup("");
+ for(i = 0; i < hl->count; i++) {
+ dmi_handle h = hl->handles[i];
+ gchar *upgrade = dmidecode_match("Upgrade", &dt, &h);
+ gchar *socket = dmidecode_match("Socket Designation", &dt, &h);
+ gchar *bus_clock_str = dmidecode_match("External Clock", &dt, &h);
+ gchar *voltage_str = dmidecode_match("Voltage", &dt, &h);
+ gchar *max_speed_str = dmidecode_match("Max Speed", &dt, &h);
+
+ ret = h_strdup_cprintf("[%s (%d) %s]\n"
+ "%s=0x%x\n"
+ "%s=%s\n"
+ "%s=%s\n"
+ "%s=%s\n"
+ "%s=%s\n",
+ ret,
+ _("CPU Socket"), i, socket,
+ _("DMI Handle"), h,
+ _("Type"), upgrade,
+ _("Voltage"), voltage_str,
+ _("External Clock"), bus_clock_str,
+ _("Max Frequency"), max_speed_str
+ );
+ g_free(upgrade);
+ g_free(socket);
+ g_free(bus_clock_str);
+ g_free(voltage_str);
+ g_free(max_speed_str);
+ }
+
+ dmi_handle_list_free(hl);
+ }
+
+ return ret;
+}
+
gchar *processor_meta(GSList * processors) {
gchar *meta_cpu_name = processor_name(processors);
gchar *meta_cpu_desc = processor_describe(processors);
gchar *meta_freq_desc = processor_frequency_desc(processors);
gchar *meta_clocks = clocks_summary(processors);
gchar *meta_caches = caches_summary(processors);
+ gchar *meta_dmi = dmi_socket_info();
gchar *ret = NULL;
UNKIFNULL(meta_cpu_desc);
ret = g_strdup_printf("[%s]\n"
@@ -691,13 +745,15 @@ gchar *processor_meta(GSList * processors) {
"%s=%s\n"
"%s=%s\n"
"%s"
+ "%s"
"%s",
_("Package Information"),
_("Name"), meta_cpu_name,
_("Topology"), meta_cpu_desc,
_("Logical CPU Config"), meta_freq_desc,
meta_clocks,
- meta_caches);
+ meta_caches,
+ meta_dmi);
g_free(meta_cpu_desc);
g_free(meta_freq_desc);
g_free(meta_clocks);
@@ -711,8 +767,9 @@ gchar *processor_get_info(GSList * processors)
gchar *ret, *tmp, *hashkey;
gchar *meta; /* becomes owned by more_info? no need to free? */
GSList *l;
+ gchar *icons=g_strdup("");
- tmp = g_strdup_printf("$CPU_META$%s=\n", _("Package Information") );
+ tmp = g_strdup_printf("$!CPU_META$%s=|Summary\n", "all");
meta = processor_meta(processors);
moreinfo_add_with_prefix("DEV", "CPU_META", meta);
@@ -720,27 +777,46 @@ gchar *processor_get_info(GSList * processors)
for (l = processors; l; l = l->next) {
processor = (Processor *) l->data;
- tmp = g_strdup_printf("%s$CPU%d$%s=%.2f %s|%d:%d|%d\n",
+ gchar *model_name = g_strdup(processor->model_name);
+ const Vendor *v = vendor_match(processor->vendor_id, NULL);
+ if (v)
+ tag_vendor(&model_name, 0, v->name_short ? v->name_short : v->name, v->ansi_color, params.fmt_opts);
+
+ // bp: not convinced it looks good, but here's how it would be done...
+ //icons = h_strdup_cprintf("Icon$CPU%d$cpu%d=processor.png\n", icons, processor->id, processor->id);
+
+ tmp = g_strdup_printf("%s$CPU%d$cpu%d=%.2f %s|%s|%d:%d\n",
tmp, processor->id,
- processor->model_name,
+ processor->id,
processor->cpu_mhz, _("MHz"),
+ model_name,
processor->cputopo->socket_id,
- processor->cputopo->core_id,
- processor->cputopo->id );
+ processor->cputopo->core_id);
hashkey = g_strdup_printf("CPU%d", processor->id);
moreinfo_add_with_prefix("DEV", hashkey,
processor_get_detailed_info(processor));
g_free(hashkey);
+ g_free(model_name);
}
ret = g_strdup_printf("[$ShellParam$]\n"
"ViewType=1\n"
+ "ColumnTitle$TextValue=%s\n"
+ "ColumnTitle$Value=%s\n"
"ColumnTitle$Extra1=%s\n"
"ColumnTitle$Extra2=%s\n"
+ "ShowColumnHeaders=true\n"
+ "%s"
"[Processors]\n"
- "%s", _("Socket:Core"), _("Thread" /*TODO: +s*/), tmp);
+ "%s", _("Device"), _("Frequency"), _("Model"), _("Socket:Core"), icons, tmp);
g_free(tmp);
+ g_free(icons);
+
+ // now here's something fun...
+ struct Info *i = info_unflatten(ret);
+ g_free(ret);
+ ret = info_flatten(i);
return ret;
}
diff --git a/modules/devices/x86/x86_data.c b/modules/devices/x86/x86_data.c
index c052f4e1..f56e8668 100644
--- a/modules/devices/x86/x86_data.c
+++ b/modules/devices/x86/x86_data.c
@@ -18,6 +18,7 @@
*
*/
+#include <json-glib/json-glib.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
@@ -35,9 +36,13 @@
* 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[] = {
+
+struct flag_to_meaning {
+ char *name;
+ char *meaning;
+};
+
+static const struct flag_to_meaning builtin_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)") },
@@ -282,6 +287,8 @@ static struct {
{ "bug:cpu_meltdown", NC_("x86-flag", /*/bug:cpu_insecure & bug:cpu_meltdown*/ "CPU is affected by meltdown attack and needs kernel page table isolation") },
{ "bug:spectre_v1", NC_("x86-flag", /*/bug:spectre_v1*/ "CPU is affected by Spectre variant 1 attack with conditional branches") },
{ "bug:spectre_v2", NC_("x86-flag", /*/bug:spectre_v2*/ "CPU is affected by Spectre variant 2 attack with indirect branches") },
+ { "bug:spec_store_bypass", NC_("x86-flag", /*/bug:spec_store_bypass*/ "CPU is affected by speculative store bypass attack") },
+ { "bug:l1tf", NC_("x86-flag", /*/bug:l1tf*/ "CPU is affected by L1 Terminal Fault") },
/* power management
* ... from arch/x86/kernel/cpu/powerflags.h */
{ "pm:ts", NC_("x86-flag", /*/flag:pm:ts*/ "temperature sensor") },
@@ -299,32 +306,77 @@ static struct {
{ NULL, NULL},
};
+static struct flag_to_meaning *tab_flag_meaning;
+
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;
+static void build_meaning_table_iter(JsonObject *object,
+ const gchar *member_name,
+ JsonNode *member_node,
+ gpointer user_data)
+{
+ int *i = user_data;
+
+ tab_flag_meaning[*i] = (struct flag_to_meaning) {
+ .name = g_strdup(member_name),
+ .meaning = g_strdup(json_node_get_string(member_node)),
+ };
+
+ (*i)++;
}
-const char *x86_flag_meaning(const char *flag) {
+void cpuflags_x86_init(void)
+{
+ gchar *flag_json = g_build_filename(g_get_user_config_dir(), "hardinfo2",
+ "cpuflags.json", NULL);
+ gboolean use_builtin_table = TRUE;
+
+ if (!g_file_test(flag_json, G_FILE_TEST_EXISTS))
+ goto use_builtin_table;
+
+ JsonParser *parser = json_parser_new();
+ if (!json_parser_load_from_file(parser, flag_json, NULL))
+ goto use_builtin_table_with_json;
+
+ JsonNode *root = json_parser_get_root(parser);
+ if (json_node_get_node_type(root) != JSON_NODE_OBJECT)
+ goto use_builtin_table_with_json;
+
+ JsonObject *x86_flags =
+ json_object_get_object_member(json_node_get_object(root), "x86");
+ if (!x86_flags)
+ goto use_builtin_table_with_json;
+
+ tab_flag_meaning =
+ g_new(struct flag_to_meaning, json_object_get_size(x86_flags) + 1);
int i = 0;
- if (flag)
- while(tab_flag_meaning[i].name != NULL) {
+ json_object_foreach_member(x86_flags, build_meaning_table_iter, &i);
+ tab_flag_meaning[i] = (struct flag_to_meaning){NULL, NULL};
+ use_builtin_table = FALSE;
+
+use_builtin_table_with_json:
+ g_object_unref(parser);
+use_builtin_table:
+ g_free(flag_json);
+
+ if (use_builtin_table)
+ tab_flag_meaning = (struct flag_to_meaning *)builtin_tab_flag_meaning;
+}
+
+const char *x86_flag_meaning(const char *flag) {
+ int i;
+
+ if (!flag)
+ return NULL;
+
+ for (i = 0; tab_flag_meaning[i].name; i++) {
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;
}