aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBurt P <pburt0@gmail.com>2019-08-16 22:55:18 -0500
committerLeandro A. F. Pereira <leandro@hardinfo.org>2019-08-18 23:49:29 +0200
commite49e438270cdffc4a80a2676c73ad95bedce33d4 (patch)
tree769017d433a3004202ea6769d4d0fca40f3099d1
parentd55a8f33188eb35e918d5c6c355d686867315337 (diff)
Devices/Monitors
Signed-off-by: Burt P <pburt0@gmail.com>
-rw-r--r--CMakeLists.txt5
-rw-r--r--deps/sysobj_early/data/edid.ids98
-rw-r--r--deps/sysobj_early/include/util_edid.h68
-rw-r--r--deps/sysobj_early/src/appf.c8
-rw-r--r--deps/sysobj_early/src/util_edid.c319
-rw-r--r--hardinfo/x_util.c3
-rw-r--r--modules/devices.c23
-rw-r--r--modules/devices/dmi_memory.c2
-rw-r--r--modules/devices/monitors.c282
9 files changed, 804 insertions, 4 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 4326e892..e41cbf4a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -124,6 +124,7 @@ set(HARDINFO_RESOURCES
"deps/sysobj_early/data/sdcard.ids"
"deps/sysobj_early/data/usb.ids"
"deps/sysobj_early/data/arm.ids"
+ "deps/sysobj_early/data/edid.ids"
)
set(HARDINFO_MANPAGES
@@ -152,6 +153,7 @@ set(MODULE_devices_SOURCES
modules/devices.c
modules/devices/${HARDINFO_ARCH}/processor.c
modules/devices/gpu.c
+ modules/devices/monitors.c
modules/devices/battery.c
modules/devices/dmi.c
modules/devices/dmi_memory.c
@@ -209,6 +211,7 @@ set_source_files_properties(
)
set_source_files_properties(
+ modules/devices/monitors.c
modules/devices/dmi_memory.c
# modules/devices/spd-decode.c
hardinfo/problem_marker.c
@@ -230,8 +233,10 @@ add_library(sysobj_early STATIC
deps/sysobj_early/src/appf.c
deps/sysobj_early/src/nice_name.c
deps/sysobj_early/gui/uri_handler.c
+ deps/sysobj_early/src/util_edid.c
)
set_target_properties(sysobj_early PROPERTIES COMPILE_FLAGS "-std=c99 -Wall -Wextra -Wno-parentheses -Wno-unused-function")
+target_link_libraries(sysobj_early m)
if (HARDINFO_GTK3)
add_library(uber-graph STATIC
diff --git a/deps/sysobj_early/data/edid.ids b/deps/sysobj_early/data/edid.ids
new file mode 100644
index 00000000..575287b6
--- /dev/null
+++ b/deps/sysobj_early/data/edid.ids
@@ -0,0 +1,98 @@
+#
+# https://github.com/bp0/verbose-spork/blob/master/data/edid.ids
+#
+# List of known/observed EDID three-letter vendor codes
+# See http://edid.tv/manufacturer
+# These codes are also the three-letter "EISA" or "PNP" codes.
+# See http://uefi.org/sites/default/files/resources/PNPID_List.pdf
+#
+# Syntax:
+# VEN Vendor Name
+#
+# Please keep sorted.
+#
+
+AAA Avolites
+ACI Ancor Communications
+ACR Acer Technologies
+ADA Addi-Data GmbH
+AGO AlgolTek
+AOC AOC International
+APP Apple Computer
+ATO ASTRO DESIGN
+AUO AU Optronics
+AVT Avtek
+BMD Blackmagic Design
+BNO Bang & Olufsen
+BNQ BenQ
+BOE BOE
+CMN Chimei Innolux Corporation
+CMO Chi Mei Optoelectronics
+CRO Extraordinary Technologies
+CUK Calibre UK
+DEL Dell
+DGC Data General Corporation
+DON DENON
+ENC Eizo Nanao Corporation
+EPH Epiphan Systems
+EXP Data Export Corporation
+FNI Funai Electric
+FUS Fujitsu Siemens Computers
+GSM Goldstar Company
+HIQ Kaohsiung Opto Electronics Americas
+HPN Hewlett-Packard Company
+HSD HannStar Display Corporation
+HTC Hitachi
+HWP Hewlett-Packard Company
+IBM International Business Machines
+INO Innolab Pte Ltd
+INT Interphase Corporation
+INX Communications Supply Corporation (A division of WESCO)
+ITE Integrated Tech Express
+IVM Iiyama North America
+JVC Victor Company of Japan (JVC)
+KTC Kingston Tech Corporation
+LEN Lenovo Group
+LGD LG Display
+LNX The Linux Foundation
+LWR Lightware Visual Engineering
+MAX Rogen Tech Distribution
+MEG Abeam Tech
+MEI Panasonic Industry Company
+MGW Magewell
+MST MS Telematica
+MTC Mars-Tech Corporation
+MTX Matrox
+NEC NEC Corporation
+NEX Nexgen Mediatech
+ONK ONKYO Corporation
+ORN ORION ELECTRIC
+OTM Optoma Corporation
+OVR Oculus VR
+PHL Koninklijke Philips
+PIO Pioneer Electronic Corporation
+PLN Planar
+PNR Planar Systems
+QDS Quanta Display
+RAT Rent-A-Tech
+REN Renesas Technology Corporation
+SAM Samsung Electric Company
+SAN Sanyo Electric Company
+SEC Seiko Epson Corporation
+SHP Sharp Corporation
+SII Silicon Image
+SNY Sony
+STD STD Computer
+SVS AMX (Harman, SVSI)
+SYN Synaptics
+TCL Technical Concepts
+TDC Teradici
+TOP Orion Communications Company
+TSB Toshiba Corporation
+TST Transtream
+VES Vestel Elektronik Sanayi ve Ticaret A. S.
+VIT Visitech
+VIZ Vizio
+VSC ViewSonic Corporation
+WDE Westinghouse Digital Electronics
+YMH Yamaha Corporation
diff --git a/deps/sysobj_early/include/util_edid.h b/deps/sysobj_early/include/util_edid.h
new file mode 100644
index 00000000..3d54fa0d
--- /dev/null
+++ b/deps/sysobj_early/include/util_edid.h
@@ -0,0 +1,68 @@
+/*
+ * sysobj - https://github.com/bp0/verbose-spork
+ * 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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef __UTIL_EDID_H__
+#define __UTIL_EDID_H__
+
+#include <stdint.h> /* for *int*_t types */
+
+#define EDID_MAX_EXT_BLOCKS 254
+
+/* just enough edid decoding */
+struct edid {
+ int ver_major, ver_minor;
+ char ven[4];
+
+ int d_type[4];
+ char d_text[4][14];
+
+ /* point into d_text */
+ char *name;
+ char *serial;
+ char *ut1;
+ char *ut2;
+
+ int a_or_d; /* 0 = analog, 1 = digital */
+ int bpc;
+
+ uint16_t product;
+ uint32_t n_serial;
+ int week, year;
+
+ int horiz_cm, vert_cm;
+ float diag_cm, diag_in;
+
+ int size; /* bytes */
+ int checksum_ok; /* block 0 */
+
+ int ext_blocks, ext_blocks_ok, ext_blocks_fail;
+ uint8_t ext[EDID_MAX_EXT_BLOCKS][2]; /* block type, checksum_ok */
+};
+
+int edid_fill(struct edid *id_out, const void *edid_bytes, int edid_len);
+int edid_fill_xrandr(struct edid *id_out, const char *xrandr_edid_dump);
+
+int edid_hex_to_bin(void **edid_bytes, int *edid_len, const char *hex_string);
+char *edid_bin_to_hex(const void *edid_bytes, int edid_len);
+
+const char *edid_descriptor_type(int type);
+char *edid_dump(struct edid *id);
+
+#endif
diff --git a/deps/sysobj_early/src/appf.c b/deps/sysobj_early/src/appf.c
index 432e0f30..5969d945 100644
--- a/deps/sysobj_early/src/appf.c
+++ b/deps/sysobj_early/src/appf.c
@@ -18,12 +18,18 @@
*
*/
-#include "appf.h"
#define _GNU_SOURCE /* for vasprintf() */
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
+#include "appf.h"
+
+/* FIXME: if this isn't here, hardinfo will crash,
+ * I don't have the slightest idea why */
+void wtf() {
+ edid_fill(NULL, NULL, 0);
+}
char *appf(char *str, const char *sep, const char *fmt, ...) {
char *buf = NULL;
diff --git a/deps/sysobj_early/src/util_edid.c b/deps/sysobj_early/src/util_edid.c
new file mode 100644
index 00000000..3f953191
--- /dev/null
+++ b/deps/sysobj_early/src/util_edid.c
@@ -0,0 +1,319 @@
+/*
+ * sysobj - https://github.com/bp0/verbose-spork
+ * 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; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ */
+
+#define _GNU_SOURCE
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <math.h>
+#include <endian.h>
+#include <stdio.h>
+#include "util_edid.h"
+#include "util_sysobj.h"
+#include "gettext.h"
+
+/* block must be 128 bytes */
+int block_check(const void *edid_block_bytes) {
+ if (!edid_block_bytes) return 0;
+ uint8_t sum = 0;
+ uint8_t *data = (uint8_t*)edid_block_bytes;
+ int i;
+ for(i=0; i<128; i++)
+ sum += data[i];
+ return sum == 0 ? 1 : 0;
+}
+
+int edid_fill(struct edid *id_out, const void *edid_bytes, int edid_len) {
+ int i;
+
+ if (!id_out) return 0;
+
+ memset(id_out, 0, sizeof(struct edid));
+ id_out->size = edid_len;
+
+ if (edid_len >= 128) {
+ uint8_t *u8 = (uint8_t*)edid_bytes;
+ uint16_t *u16 = (uint16_t*)edid_bytes;
+ uint32_t *u32 = (uint32_t*)edid_bytes;
+
+ id_out->ver_major = u8[18]; /* byte 18 */
+ id_out->ver_minor = u8[19]; /* byte 19 */
+
+ /* checksum first block */
+ id_out->checksum_ok = block_check(edid_bytes);
+ if (edid_len > 128) {
+ int blocks = edid_len / 128;
+ if (blocks > EDID_MAX_EXT_BLOCKS) blocks = EDID_MAX_EXT_BLOCKS;
+ blocks--;
+ id_out->ext_blocks = blocks;
+ for(; blocks; blocks--) {
+ id_out->ext[blocks-1][0] = *(u8 + (blocks * 128));
+ int r = block_check(u8 + (blocks * 128));
+ id_out->ext[blocks-1][1] = (uint8_t)r;
+ if (r) id_out->ext_blocks_ok++;
+ else id_out->ext_blocks_fail++;
+ }
+ }
+
+ /* expect 1.3 */
+
+ uint16_t vid = be16toh(u16[4]); /* bytes 8-9 */
+ id_out->ven[2] = 64 + (vid & 0x1f);
+ id_out->ven[1] = 64 + ((vid >> 5) & 0x1f);
+ id_out->ven[0] = 64 + ((vid >> 10) & 0x1f);
+
+ id_out->product = le16toh(u16[5]); /* bytes 10-11 */
+ id_out->n_serial = le32toh(u32[3]);/* bytes 12-15 */
+ id_out->week = u8[16]; /* byte 16 */
+ id_out->year = u8[17] + 1990; /* byte 17 */
+
+ if (id_out->week >= 52)
+ id_out->week = 0;
+
+ id_out->a_or_d = (u8[20] & 0x80) ? 1 : 0;
+ if (id_out->a_or_d == 1) {
+ /* digital */
+ switch((u8[20] >> 4) & 0x7) {
+ case 0x1: id_out->bpc = 6; break;
+ case 0x2: id_out->bpc = 8; break;
+ case 0x3: id_out->bpc = 10; break;
+ case 0x4: id_out->bpc = 12; break;
+ case 0x5: id_out->bpc = 14; break;
+ case 0x6: id_out->bpc = 16; break;
+ }
+ }
+
+ if (u8[21] && u8[22]) {
+ id_out->horiz_cm = u8[21];
+ id_out->vert_cm = u8[22];
+ id_out->diag_cm =
+ sqrt( (id_out->horiz_cm * id_out->horiz_cm)
+ + (id_out->vert_cm * id_out->vert_cm) );
+ id_out->diag_in = id_out->diag_cm / 2.54;
+ }
+
+ uint16_t dh, dl;
+
+ /* descriptor at byte 54 */
+ dh = be16toh(u16[54/2]);
+ dl = be16toh(u16[54/2+1]);
+ id_out->d_type[0] = (dh << 16) + dl;
+ switch(id_out->d_type[0]) {
+ case 0xfc: case 0xff: case 0xfe:
+ strncpy(id_out->d_text[0], (char*)u8+54+5, 13);
+ }
+
+ /* descriptor at byte 72 */
+ dh = be16toh(u16[72/2]);
+ dl = be16toh(u16[72/2+1]);
+ id_out->d_type[1] = (dh << 16) + dl;
+ switch(id_out->d_type[1]) {
+ case 0xfc: case 0xff: case 0xfe:
+ strncpy(id_out->d_text[1], (char*)u8+72+5, 13);
+ }
+
+ /* descriptor at byte 90 */
+ dh = be16toh(u16[90/2]);
+ dl = be16toh(u16[90/2+1]);
+ id_out->d_type[2] = (dh << 16) + dl;
+ switch(id_out->d_type[2]) {
+ case 0xfc: case 0xff: case 0xfe:
+ strncpy(id_out->d_text[2], (char*)u8+90+5, 13);
+ }
+
+ /* descriptor at byte 108 */
+ dh = be16toh(u16[108/2]);
+ dl = be16toh(u16[108/2+1]);
+ id_out->d_type[3] = (dh << 16) + dl;
+ switch(id_out->d_type[3]) {
+ case 0xfc: case 0xff: case 0xfe:
+ strncpy(id_out->d_text[3], (char*)u8+108+5, 13);
+ }
+
+ for(i = 0; i < 4; i++) {
+ g_strstrip(id_out->d_text[i]);
+ switch(id_out->d_type[i]) {
+ case 0xfc:
+ id_out->name = id_out->d_text[i];
+ break;
+ case 0xff:
+ id_out->serial = id_out->d_text[i];
+ break;
+ case 0xfe:
+ if (id_out->ut1)
+ id_out->ut2 = id_out->d_text[i];
+ else
+ id_out->ut1 = id_out->d_text[i];
+ break;
+ }
+ }
+
+ if (!id_out->name) {
+ if (SEQ(id_out->ut1, "LG Display") && id_out->ut2)
+ /* LG may use "uspecified text" for name and model */
+ id_out->name = id_out->ut2;
+ else if (SEQ(id_out->ut1, "AUO") && id_out->ut2)
+ /* Same with AUO */
+ id_out->name = id_out->ut2;
+ else {
+ if (id_out->ut1) id_out->name = id_out->ut1;
+ if (id_out->ut2 && !id_out->serial) id_out->serial = id_out->ut2;
+ }
+ }
+ }
+ return 1;
+}
+
+int edid_hex_to_bin(void **edid_bytes, int *edid_len, const char *hex_string) {
+ int blen = strlen(hex_string) / 2;
+ uint8_t *buffer = malloc(blen), *n = buffer;
+ memset(buffer, 0, blen);
+ int len = 0;
+
+ const char *p = hex_string;
+ char byte[3] = "..";
+
+ while(p && *p) {
+ if (isxdigit(p[0]) && isxdigit(p[1])) {
+ byte[0] = p[0];
+ byte[1] = p[1];
+ *n = strtol(byte, NULL, 16);
+ n++;
+ len++;
+ p += 2;
+ } else
+ p++;
+ }
+
+ *edid_bytes = (void *)buffer;
+ *edid_len = len;
+ return 1;
+}
+
+int edid_fill_xrandr(struct edid *id_out, const char *xrandr_edid_dump) {
+ void *buffer = NULL;
+ int len = 0;
+ edid_hex_to_bin(&buffer, &len, xrandr_edid_dump);
+ return edid_fill(id_out, buffer, len);
+}
+
+const char *edid_ext_block_type(int type) {
+ switch(type) {
+ case 0xf0:
+ return N_("extension block map");
+ case 0x02:
+ return N_("EIA/CEA-861 extension block");
+ }
+ return N_("unknown block type");
+}
+
+const char *edid_descriptor_type(int type) {
+ switch(type) {
+ case 0xff:
+ return N_("display serial number");
+ case 0xfe:
+ return N_("unspecified text");
+ case 0xfd:
+ return N_("display range limits");
+ case 0xfc:
+ return N_("display name");
+ case 0xfb:
+ return N_("additional white point");
+ case 0xfa:
+ return N_("additional standard timing identifiers");
+ case 0xf9:
+ return N_("Display Color Management");
+ case 0xf8:
+ return N_("CVT 3-byte timing codes");
+ case 0xf7:
+ return N_("additional standard timing");
+ case 0x10:
+ return N_("dummy");
+ }
+ if (type < 0x0f) return N_("manufacturer reserved descriptor");
+ return N_("detailed timing descriptor");
+}
+
+char *edid_dump(struct edid *id) {
+ char *ret = NULL;
+ int i;
+
+ if (!id) return NULL;
+ ret = appfnl(ret, "edid_version: %d.%d (%d bytes)", id->ver_major, id->ver_minor, id->size);
+
+ ret = appfnl(ret, "mfg: %s, model: %u, n_serial: %u", id->ven, id->product, id->n_serial);
+ if (id->week && id->year)
+ ret = appf(ret, "", ", dom: week %d of %d", id->week, id->year);
+ else if (id->year)
+ ret = appf(ret, "", ", dom: %d", id->year);
+
+ ret = appfnl(ret, "type: %s", id->a_or_d ? "digital" : "analog");
+ if (id->bpc)
+ ret = appfnl(ret, "bits per color channel: %d", id->bpc);
+
+ if (id->horiz_cm && id->vert_cm)
+ ret = appfnl(ret, "size: %d cm × %d cm", id->horiz_cm, id->vert_cm);
+ if (id->diag_cm)
+ ret = appfnl(ret, "diagonal: %0.2f cm (%0.2f in)", id->diag_cm, id->diag_in);
+
+ ret = appfnl(ret, "checksum %s", id->checksum_ok ? "ok" : "failed!");
+ if (id->ext_blocks_ok || id->ext_blocks_fail)
+ ret = appf(ret, "", ", extension blocks: %d of %d ok", id->ext_blocks_ok, id->ext_blocks_ok + id->ext_blocks_fail);
+
+ for(i = 0; i < 4; i++)
+ ret = appfnl(ret, "descriptor[%d] (%s): %s", i, _(edid_descriptor_type(id->d_type[i])), *id->d_text[i] ? id->d_text[i] : "{...}");
+
+ for(i = 0; i < EDID_MAX_EXT_BLOCKS; i++) {
+ if (id->ext[i][0]) {
+ ret = appfnl(ret, "ext_block[%d]: (%s): %s", i, _(edid_ext_block_type(id->ext[i][0])), id->ext[i][1] ? "ok" : "fail");
+ }
+ }
+
+ return ret;
+}
+
+char *edid_bin_to_hex(const void *edid_bytes, int edid_len) {
+ int lines = edid_len / 16;
+ int blen = lines * 35 + 1;
+ int pc = 0;
+ char *ret = malloc(blen);
+ memset(ret, 0, blen);
+ uint8_t *u8 = (uint8_t*)edid_bytes;
+ char *p = ret;
+ for(; lines; lines--) {
+ sprintf(p, "\t\t");
+ p+=2;
+ int i;
+ for(i = 0; i < 16; i++) {
+ sprintf(p, "%02x", (unsigned int)*u8);
+ p+=2;
+ u8++;
+ pc++;
+ if (pc == blen-1) {
+ sprintf(p, "\n");
+ goto edid_print_done;
+ }
+ }
+ sprintf(p, "\n");
+ p++;
+ }
+edid_print_done:
+ return ret;
+}
diff --git a/hardinfo/x_util.c b/hardinfo/x_util.c
index 52888a8c..07d5226a 100644
--- a/hardinfo/x_util.c
+++ b/hardinfo/x_util.c
@@ -151,7 +151,7 @@ gboolean fill_xinfo(xinfo *xi) {
gboolean fill_xrr_info(xrr_info *xrr) {
gboolean spawned;
gchar *out, *err, *p, *next_nl;
- gchar *xrr_cmd = g_strdup("xrandr");
+ gchar *xrr_cmd = g_strdup("xrandr --prop");
int ec;
x_screen ts;
@@ -192,7 +192,6 @@ gboolean fill_xrr_info(xrr_info *xrr) {
goto xrr_next_line;
}
-
/* looking for:
* <output_id> (connected|disconnected|unknown connection) (primary|?) <%dx%d+%d+%d> (attribute_list) mm x mm
*/
diff --git a/modules/devices.c b/modules/devices.c
index 02597e65..14b3708c 100644
--- a/modules/devices.c
+++ b/modules/devices.c
@@ -42,6 +42,7 @@
gchar *callback_processors();
gchar *callback_gpu();
+gchar *callback_monitors();
gchar *callback_battery();
gchar *callback_pci();
gchar *callback_sensors();
@@ -57,6 +58,7 @@ gchar *callback_device_resources();
void scan_processors(gboolean reload);
void scan_gpu(gboolean reload);
+void scan_monitors(gboolean reload);
void scan_battery(gboolean reload);
void scan_pci(gboolean reload);
void scan_sensors(gboolean reload);
@@ -80,6 +82,7 @@ enum {
ENTRY_DMI,
ENTRY_PROCESSOR,
ENTRY_GPU,
+ ENTRY_MONITORS,
ENTRY_DMI_MEM,
ENTRY_PCI,
ENTRY_USB,
@@ -95,6 +98,7 @@ enum {
static ModuleEntry entries[] = {
[ENTRY_PROCESSOR] = {N_("Processor"), "processor.png", callback_processors, scan_processors, MODULE_FLAG_NONE},
[ENTRY_GPU] = {N_("Graphics Processors"), "devices.png", callback_gpu, scan_gpu, MODULE_FLAG_NONE},
+ [ENTRY_MONITORS] = {N_("Monitors"), "monitor.png", callback_monitors, scan_monitors, MODULE_FLAG_NONE},
[ENTRY_PCI] = {N_("PCI Devices"), "devices.png", callback_pci, scan_pci, MODULE_FLAG_NONE},
[ENTRY_USB] = {N_("USB Devices"), "usb.png", callback_usb, scan_usb, MODULE_FLAG_NONE},
[ENTRY_FW] = {N_("Firmware"), "processor.png", callback_firmware, scan_firmware, MODULE_FLAG_NONE},
@@ -134,6 +138,11 @@ gchar *firmware_get_info();
gboolean firmware_hinote(const char **msg);
gchar *firmware_info = NULL;
+/* in monitors.c */
+gchar *monitors_get_info();
+gboolean monitors_hinote(const char **msg);
+gchar *monitors_info = NULL;
+
#include <vendor.h>
extern gchar *gpu_summary;
@@ -551,6 +560,15 @@ void scan_dmi_mem(gboolean reload)
SCAN_END();
}
+void scan_monitors(gboolean reload)
+{
+ SCAN_START();
+ if (monitors_info)
+ g_free(monitors_info);
+ monitors_info = monitors_get_info();
+ SCAN_END();
+}
+
void scan_firmware(gboolean reload)
{
SCAN_START();
@@ -656,6 +674,11 @@ gchar *callback_dmi_mem()
return g_strdup(memory_devices_info);
}
+gchar *callback_monitors()
+{
+ return g_strdup(monitors_info);
+}
+
gchar *callback_firmware()
{
return g_strdup(firmware_info);
diff --git a/modules/devices/dmi_memory.c b/modules/devices/dmi_memory.c
index 753c4c74..f266193c 100644
--- a/modules/devices/dmi_memory.c
+++ b/modules/devices/dmi_memory.c
@@ -618,7 +618,7 @@ gchar *make_spd_section(spd_data *spd) {
return ret;
}
-gchar *tag_make_safe_inplace(gchar *tag) {
+static gchar *tag_make_safe_inplace(gchar *tag) {
if (!tag)
return tag;
if (!g_utf8_validate(tag, -1, NULL))
diff --git a/modules/devices/monitors.c b/modules/devices/monitors.c
new file mode 100644
index 00000000..4e8ba915
--- /dev/null
+++ b/modules/devices/monitors.c
@@ -0,0 +1,282 @@
+/*
+ * HardInfo - Displays System Information
+ * Copyright (C) 2003-2019 Leandro A. F. Pereira <leandro@hardinfo.org>
+ * 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.
+ *
+ * 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)"))
+
+gboolean no_monitors = FALSE;
+
+gchar *edid_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(), "hardinfo", "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);
+}
+
+typedef struct {
+ gchar *drm_connection;
+ uint8_t *edid_bin;
+ gsize edid_len;
+ struct edid id;
+ gchar *_vstr; /* use monitor_vendor_str() */
+} monitor;
+#define monitor_new() g_new0(monitor, 1)
+
+monitor *monitor_new_from_sysfs(const gchar *sysfs_edid_file) {
+ monitor *m = monitor_new();
+ g_file_get_contents(sysfs_edid_file, (gchar**)&(m->edid_bin), &m->edid_len, NULL);
+ if (m->edid_len) {
+ edid_fill(&m->id, (void*)(m->edid_bin), m->edid_len);
+ }
+
+ gchar *pd = g_path_get_dirname(sysfs_edid_file);
+ m->drm_connection = g_path_get_basename(pd);
+ g_free(pd);
+
+ return m;
+}
+
+void monitor_free(monitor *m) {
+ if (m) {
+ g_free(m->_vstr);
+ g_free(m->drm_connection);
+ g_free(m->edid_bin);
+ g_free(m);
+ }
+}
+
+const gchar *monitor_vendor_str(monitor *m) {
+ if (m->_vstr)
+ return m->_vstr;
+
+ ids_query_result result = {};
+
+ if (!edid_ids_file)
+ find_edid_ids_file();
+
+ scan_ids_file(edid_ids_file, m->id.ven, &result, -1);
+ if (result.results[0]) {
+ m->_vstr = g_strdup(result.results[0]);
+ return m->_vstr;
+ }
+ return g_strdup(m->id.ven);
+}
+
+gchar *monitor_name(monitor *m, gboolean include_vendor) {
+ if (!m) return NULL;
+ gchar *desc = NULL;
+
+ if (include_vendor) {
+ if (*m->id.ven)
+ desc = appfsp(desc, "%s", vendor_get_shortest_name(monitor_vendor_str(m)));
+ else
+ desc = appfsp(desc, "%s", "Unknown");
+ }
+
+ if (m->id.diag_in) {
+ gchar *din = util_strchomp_float(g_strdup_printf("%0.1f", m->id.diag_in));
+ desc = appfsp(desc, "%s\"", din);
+ g_free(din);
+ }
+
+ if (m->id.name)
+ desc = appfsp(desc, "%s", m->id.name);
+ else
+ desc = appfsp(desc, "%s %s", m->id.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) {
+ if (m->edid_len) {
+ const gchar *vstr = monitor_vendor_str(m);
+
+ gchar *dom = NULL;
+ if (m->id.week && m->id.year)
+ dom = g_strdup_printf(_("Week %d of %d"), m->id.week, m->id.year);
+ else if (m->id.year)
+ dom = g_strdup_printf("%d", m->id.year);
+
+ gchar *bpcc = NULL;
+ if (m->id.bpc)
+ bpcc = g_strdup_printf("%d", m->id.bpc);
+
+ gchar *scr_size = NULL;
+ if (m->id.horiz_cm && m->id.vert_cm)
+ scr_size = g_strdup_printf("%d cm × %d cm", m->id.horiz_cm, m->id.vert_cm);
+
+ int aok = m->id.checksum_ok;
+ if (m->id.ext_blocks_fail) aok = 0;
+ gchar *csum = aok ? _("Ok") : _("Fail");
+
+ gchar *ret = g_strdup_printf("[%s]\n"
+ "%s=%d.%d\n" /* version */
+ "%s=%d %s\n" /* size */
+ "%s=%d\n" /* ext block */
+ "%s=%s %s\n" /* checksum */
+ "[%s]\n"
+ "%s=%s\n" /* vendor */
+ "%s=%s\n" /* name */
+ "%s=%s\n" /* dom */
+ "%s=%s\n" /* size */
+ "%s=%s\n" /* sig type */
+ "%s=%s\n" /* bpcc */
+ ,
+ _("EDID Meta"),
+ _("Version"), (int)m->id.ver_major, (int)m->id.ver_minor,
+ _("Data Size"), m->id.size, _("bytes"),
+ _("Extension Blocks"), m->id.ext_blocks,
+ _("Checksum"), csum, aok ? "" : problem_marker(),
+ _("EDID Device"),
+ _("Vendor"), vstr,
+ _("Name"), m->id.name,
+ _("Manufacture Date"), UNKIFNULL2(dom),
+ _("Screen Size"), UNKIFNULL2(scr_size),
+ _("Signal Type"), m->id.a_or_d ? _("Digital") : _("Analog"),
+ _("Bits per Color Channel"), UNKIFNULL2(bpcc)
+ );
+ g_free(scr_size);
+ g_free(bpcc);
+ g_free(dom);
+ //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/edid/ -name edid.*");
+ int i, found = 0;
+ for(i = 0; edid_files[i]; i++) {
+ monitor *m = monitor_new_from_sysfs(edid_files[i]);
+ if (m) {
+ found++;
+ if (m->id.checksum_ok && m->drm_connection) {
+ 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 = make_edid_section(m);
+ gchar *details = g_strdup_printf("[%s]\n"
+ "%s=%s\n"
+ "%s\n",
+ _("Connection"),
+ _("DRM"), m->drm_connection,
+ edid_section
+ );
+ moreinfo_add_with_prefix(tag_prefix, tag, details); /* moreinfo now owns *details */
+ ret = h_strdup_cprintf("$!%s$%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);
+ }
+ monitor_free(m);
+ }
+ }
+
+ 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;
+}