aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--deps/sysobj_early/include/util_edid.h29
-rw-r--r--deps/sysobj_early/src/util_edid.c118
-rw-r--r--modules/devices/monitors.c146
3 files changed, 222 insertions, 71 deletions
diff --git a/deps/sysobj_early/include/util_edid.h b/deps/sysobj_early/include/util_edid.h
index af9364e0..45dad136 100644
--- a/deps/sysobj_early/include/util_edid.h
+++ b/deps/sysobj_early/include/util_edid.h
@@ -23,11 +23,21 @@
#include <stdint.h> /* for *int*_t types */
+typedef struct {
+ float horiz_cm, vert_cm;
+ float diag_cm, diag_in;
+ int horiz_pixels, vert_lines, vert_pixels;
+ int is_interlaced;
+ int stereo_mode;
+ int pixel_clock_khz;
+ int src; /* 0: edid, 1: dtd, 2: cea-dtd, ... */
+ char class_inch[6];
+} edid_output;
+
struct edid_dtd {
uint8_t *ptr;
- int pixel_clock_khz;
- int horiz_pixels;
- int vert_lines;
+ int cea_ext;
+ edid_output out;
};
struct edid_cea_header {
@@ -96,13 +106,13 @@ typedef struct {
char *ut2;
int a_or_d; /* 0 = analog, 1 = digital */
- int bpc;
+ int interface; /* digital interface */
+ int bpc; /* digital bpc */
uint16_t product;
uint32_t n_serial;
int week, year;
- int horiz_cm, vert_cm;
- float diag_cm, diag_in;
-
+ edid_output img;
+ edid_output img_max;
} edid;
edid *edid_new(const char *data, unsigned int len);
edid *edid_new_from_hex(const char *hex_string);
@@ -110,12 +120,15 @@ void edid_free(edid *e);
char *edid_dump_hex(edid *e, int tabs, int breaks);
const char *edid_standard(int type);
+const char *edid_output_src(int src);
+const char *edid_interface(int type);
const char *edid_descriptor_type(int type);
const char *edid_ext_block_type(int type);
const char *edid_cea_block_type(int type);
const char *edid_cea_audio_type(int type);
-char *edid_dtd_describe(struct edid_dtd *dtd);
+char *edid_output_describe(edid_output *out);
+char *edid_dtd_describe(struct edid_dtd *dtd, int dump_bytes);
char *edid_cea_block_describe(struct edid_cea_block *blk);
char *edid_dump2(edid *e);
diff --git a/deps/sysobj_early/src/util_edid.c b/deps/sysobj_early/src/util_edid.c
index 80a71002..b998fb40 100644
--- a/deps/sysobj_early/src/util_edid.c
+++ b/deps/sysobj_early/src/util_edid.c
@@ -80,6 +80,22 @@ static void cea_block_decode(struct edid_cea_block *blk) {
}
}
+static void edid_output_fill(edid_output *out) {
+ out->diag_cm =
+ sqrt( (out->horiz_cm * out->horiz_cm)
+ + (out->vert_cm * out->vert_cm) );
+ out->diag_in = out->diag_cm / 2.54;
+
+ if (out->is_interlaced)
+ out->vert_pixels = out->vert_lines * 2;
+ else
+ out->vert_pixels = out->vert_lines;
+
+ static const char *inlbl = "\""; /* TODO: unicode */
+ sprintf(out->class_inch, "%0.1f%s", out->diag_in, inlbl);
+ util_strchomp_float(out->class_inch);
+}
+
edid *edid_new(const char *data, unsigned int len) {
if (len < 128) return NULL;
@@ -94,6 +110,8 @@ edid *edid_new(const char *data, unsigned int len) {
e->dtds = malloc(sizeof(struct edid_dtd) * 1000);
e->cea_blocks = malloc(sizeof(struct edid_cea_block) * 1000);
+ memset(e->dtds, 0, sizeof(struct edid_dtd) * 1000);
+ memset(e->cea_blocks, 0, sizeof(struct edid_cea_block) * 1000);
uint16_t vid = be16toh(e->u16[4]); /* bytes 8-9 */
e->ven[2] = 64 + (vid & 0x1f);
@@ -118,15 +136,14 @@ edid *edid_new(const char *data, unsigned int len) {
case 0x5: e->bpc = 14; break;
case 0x6: e->bpc = 16; break;
}
+ e->interface = e->u8[20] & 0xf;
}
if (e->u8[21] && e->u8[22]) {
- e->horiz_cm = e->u8[21];
- e->vert_cm = e->u8[22];
- e->diag_cm =
- sqrt( (e->horiz_cm * e->horiz_cm)
- + (e->vert_cm * e->vert_cm) );
- e->diag_in = e->diag_cm / 2.54;
+ e->img.horiz_cm = e->u8[21];
+ e->img.vert_cm = e->u8[22];
+ edid_output_fill(&e->img);
+ e->img_max = e->img;
}
uint16_t dh, dl;
@@ -191,6 +208,7 @@ edid *edid_new(const char *data, unsigned int len) {
if (u8[b]) {
//printf("DTD: %s\n", hex_bytes(&u8[b], 18));
e->dtds[e->dtd_count].ptr = &u8[b];
+ e->dtds[e->dtd_count].cea_ext = 1;
e->dtd_count++;
}
b += 18;
@@ -236,11 +254,29 @@ edid *edid_new(const char *data, unsigned int len) {
/* dtds */
for(i = 0; i < e->dtd_count; i++) {
uint8_t *u8 = e->dtds[i].ptr;
- e->dtds[i].pixel_clock_khz = u8[0] * 10;
- e->dtds[i].horiz_pixels =
+ edid_output *out = &e->dtds[i].out;
+ if (e->dtds[i].cea_ext) out->src = 2;
+ else out->src = 1;
+ out->pixel_clock_khz = u8[0] * 10;
+ out->horiz_pixels =
((u8[4] & 0xf0) << 4) + u8[2];
- e->dtds[i].vert_lines =
+ out->vert_lines =
((u8[7] & 0xf0) << 4) + u8[5];
+ out->horiz_cm =
+ ((u8[14] & 0xf0) << 4) + u8[12];
+ out->horiz_cm /= 10;
+ out->vert_cm =
+ ((u8[14] & 0x0f) << 8) + u8[13];
+ out->vert_cm /= 10;
+ out->is_interlaced = (u8[17] & 0x80) >> 7;
+ out->stereo_mode = (u8[17] & 0x60) >> 4;
+ out->stereo_mode += u8[17] & 0x01;
+ edid_output_fill(out);
+ }
+
+ if (e->dtd_count) {
+ /* first DTD replaces the basic EDID size */
+ e->img_max = e->dtds[0].out;
}
/* squeeze lists */
@@ -335,6 +371,26 @@ const char *edid_standard(int std) {
return N_("unknown");
}
+const char *edid_output_src(int src) {
+ switch(src) {
+ case 0: return N_("VESA EDID");
+ case 1: return N_("VESA EDID DTD");
+ case 2: return N_("EIA/CEA-861 DTD");
+ };
+ return N_("unknown");
+}
+
+const char *edid_interface(int type) {
+ switch(type) {
+ case 0: return N_("undefined");
+ case 0x2: return N_("HDMIa");
+ case 0x3: return N_("HDMIb");
+ case 0x4: return N_("MDDI");
+ case 0x5: return N_("DisplayPort");
+ };
+ return N_("unknown");
+}
+
const char *edid_cea_audio_type(int type) {
switch(type) {
case 0: case 15: return N_("reserved");
@@ -503,13 +559,31 @@ char *edid_cea_block_describe(struct edid_cea_block *blk) {
return ret;
}
-char *edid_dtd_describe(struct edid_dtd *dtd) {
+char *edid_output_describe(edid_output *out) {
+ gchar *ret = NULL;
+ if (out) {
+ ret = g_strdup_printf("%dx%d, %0.2fx%0.2f%s (%0.1f\") %s %s",
+ out->horiz_pixels, out->vert_pixels,
+ out->horiz_cm, out->vert_cm, _("cm"), out->diag_in,
+ out->is_interlaced ? "interlaced" : "non-interlaced",
+ out->stereo_mode ? "stereo" : "normal");
+ }
+ return ret;
+}
+
+char *edid_dtd_describe(struct edid_dtd *dtd, int dump_bytes) {
gchar *ret = NULL;
if (dtd) {
+ edid_output *out = &dtd->out;
char *hb = hex_bytes(dtd->ptr, 18);
- ret = g_strdup_printf("%dx%d %s",
- dtd->horiz_pixels, dtd->vert_lines,
- hb);
+ ret = g_strdup_printf("%dx%d, %0.2fx%0.2f%s (%0.1f\") %s %s (%s)%s%s",
+ out->horiz_pixels, out->vert_lines,
+ out->horiz_cm, out->vert_cm, _("cm"), out->diag_in,
+ out->is_interlaced ? "interlaced" : "non-interlaced",
+ out->stereo_mode ? "stereo" : "normal",
+ _(edid_output_src(out->src)),
+ dump_bytes ? " -- " : "",
+ dump_bytes ? hb : "");
free(hb);
}
return ret;
@@ -520,8 +594,8 @@ char *edid_dump2(edid *e) {
int i;
if (!e) return NULL;
- ret = appfnl(ret, "edid_version: %d.%d (%d bytes)", e->ver_major, e->ver_minor, e->len);
- ret = appfnl(ret, "standard: %s", _(edid_standard(e->std)) );
+ ret = appfnl(ret, "edid version: %d.%d (%d bytes)", e->ver_major, e->ver_minor, e->len);
+ ret = appfnl(ret, "extended to: %s", _(edid_standard(e->std)) );
ret = appfnl(ret, "mfg: %s, model: %u, n_serial: %u", e->ven, e->product, e->n_serial);
if (e->week && e->year)
@@ -532,11 +606,15 @@ char *edid_dump2(edid *e) {
ret = appfnl(ret, "type: %s", e->a_or_d ? "digital" : "analog");
if (e->bpc)
ret = appfnl(ret, "bits per color channel: %d", e->bpc);
+ if (e->interface)
+ ret = appfnl(ret, "interface: %s", _(edid_interface(e->interface)));
- if (e->horiz_cm && e->vert_cm)
- ret = appfnl(ret, "size: %d cm × %d cm", e->horiz_cm, e->vert_cm);
- if (e->diag_cm)
- ret = appfnl(ret, "diagonal: %0.2f cm (%0.2f in)", e->diag_cm, e->diag_in);
+ char *desc = edid_output_describe(&e->img);
+ char *desc_max = edid_output_describe(&e->img_max);
+ ret = appfnl(ret, "base(%s): %s", _(edid_output_src(e->img.src)), desc);
+ ret = appfnl(ret, "ext(%s): %s", _(edid_output_src(e->img_max.src)), desc_max);
+ g_free(desc);
+ g_free(desc_max);
ret = appfnl(ret, "checksum %s", e->checksum_ok ? "ok" : "failed!");
if (e->ext_blocks_ok || e->ext_blocks_fail)
@@ -555,7 +633,7 @@ char *edid_dump2(edid *e) {
}
for(i = 0; i < e->dtd_count; i++) {
- char *desc = edid_dtd_describe(&e->dtds[i]);
+ char *desc = edid_dtd_describe(&e->dtds[i], 0);
ret = appfnl(ret, "dtd[%d] %s", i, desc);
free(desc);
}
diff --git a/modules/devices/monitors.c b/modules/devices/monitors.c
index 482241fb..06faf6fb 100644
--- a/modules/devices/monitors.c
+++ b/modules/devices/monitors.c
@@ -26,6 +26,7 @@ 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;
@@ -99,24 +100,22 @@ const gchar *monitor_vendor_str(monitor *m) {
gchar *monitor_name(monitor *m, gboolean include_vendor) {
if (!m) return NULL;
gchar *desc = NULL;
+ edid *e = m->e;
if (include_vendor) {
- if (*m->e->ven)
+ if (*e->ven)
desc = appfsp(desc, "%s", vendor_get_shortest_name(monitor_vendor_str(m)));
else
desc = appfsp(desc, "%s", "Unknown");
}
- if (m->e->diag_in) {
- gchar *din = util_strchomp_float(g_strdup_printf("%0.1f", m->e->diag_in));
- desc = appfsp(desc, "%s\"", din);
- g_free(din);
- }
+ if (e->img_max.diag_in)
+ desc = appfsp(desc, "%s\"", e->img_max.class_inch);
- if (m->e->name)
- desc = appfsp(desc, "%s", m->e->name);
+ if (e->name)
+ desc = appfsp(desc, "%s", e->name);
else
- desc = appfsp(desc, "%s %s", m->e->a_or_d ? "Digital" : "Analog", "Display");
+ desc = appfsp(desc, "%s %s", e->a_or_d ? "Digital" : "Analog", "Display");
return desc;
}
@@ -158,58 +157,119 @@ static gchar *tag_make_safe_inplace(gchar *tag) {
}
static gchar *make_edid_section(monitor *m) {
- if (m->e->len) {
+ int i;
+ edid *e = m->e;
+ if (e->len) {
const gchar *vstr = monitor_vendor_str(m);
gchar *dom = NULL;
- if (m->e->week && m->e->year)
- dom = g_strdup_printf(_("Week %d of %d"), m->e->week, m->e->year);
- else if (m->e->year)
- dom = g_strdup_printf("%d", m->e->year);
+ if (e->week && e->year)
+ dom = g_strdup_printf(_("Week %d of %d"), e->week, e->year);
+ else if (e->year)
+ dom = g_strdup_printf("%d", e->year);
gchar *bpcc = NULL;
- if (m->e->bpc)
- bpcc = g_strdup_printf("%d", m->e->bpc);
-
- gchar *scr_size = NULL;
- if (m->e->horiz_cm && m->e->vert_cm)
- scr_size = g_strdup_printf("%d cm × %d cm", m->e->horiz_cm, m->e->vert_cm);
+ if (e->bpc)
+ bpcc = g_strdup_printf("%d", e->bpc);
- int aok = m->e->checksum_ok;
- if (m->e->ext_blocks_fail) aok = 0;
+ int aok = e->checksum_ok;
+ if (e->ext_blocks_fail) aok = 0;
gchar *csum = aok ? _("Ok") : _("Fail");
- gchar *ret = g_strdup_printf("[%s]\n"
+ const gchar *iface = e->interface ? _(edid_interface(e->interface)) : _("(Unspecified)");
+
+ gchar *d_list, *ext_list, *dtd_list, *cea_list;
+
+ d_list = g_strdup("");
+ for(i = 0; i < 4; i++)
+ d_list = appfnl(d_list, "descriptor%d = ([%02x] %s): %s", i, e->d_type[i], _(edid_descriptor_type(e->d_type[i])), *e->d_text[i] ? e->d_text[i] : "{...}");
+
+ ext_list = g_strdup("");
+ 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"
+ );
+ }
+
+ dtd_list = g_strdup("");
+ 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);
+ }
+
+ cea_list = g_strdup("");
+ 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);
+ }
+
+ 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=[%x] %s\n" /* interface */
+ "%s=%s\n" /* bpcc */
+ "[%s]\n"
+ "%s=%s\n" /* base out */
+ "%s=%s\n" /* ext out */
+ "[%s]\n"
+ "%s=%s\n" /* vendor */
+ "%s=%s\n" /* name */
+ "%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=%s\n" /* vendor */
- "%s=%s\n" /* name */
- "%s=%s\n" /* dom */
- "%s=%s\n" /* size */
- "%s=%s\n" /* sig type */
- "%s=%s\n" /* bpcc */
+ "[%s]\n%s\n"
+ "[%s]\n%s\n"
+ "[%s]\n%s\n"
+ "[%s]\n%s\n"
+ "[%s]\n%s=%s\n"
,
- _("EDID Meta"),
- _("Data Size"), m->e->len, _("bytes"),
- _("Version"), (int)m->e->ver_major, (int)m->e->ver_minor,
- _("Extension Blocks"), m->e->ext_blocks,
- _("Extended to"), _(edid_standard(m->e->std)),
- _("Checksum"), csum, aok ? "" : problem_marker(),
+ _("Signal Type"), e->a_or_d ? _("Digital") : _("Analog"),
+ _("Interface"), e->interface, iface,
+ _("Bits per Color Channel"), UNSPECIFNULL2(bpcc),
+ _("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"), m->e->name,
+ _("Name"), e->name,
_("Manufacture Date"), UNKIFNULL2(dom),
- _("Screen Size"), UNKIFNULL2(scr_size),
- _("Signal Type"), m->e->a_or_d ? _("Digital") : _("Analog"),
- _("Bits per Color Channel"), UNKIFNULL2(bpcc)
+ _("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,
+ _("E-EDID Extension Blocks"), ext_list,
+ _("EIA/CEA-861 Data Blocks"), cea_list,
+ _("Hex Dump"), _("Data"), hex
);
- g_free(scr_size);
g_free(bpcc);
g_free(dom);
+
+ g_free(d_list);
+ g_free(ext_list);
+ g_free(dtd_list);
+ g_free(cea_list);
+ g_free(hex);
//printf("ret: %s\n", ret);
return ret;
} else
@@ -217,7 +277,6 @@ static gchar *make_edid_section(monitor *m) {
}
gchar *monitors_get_info() {
-
gchar *icons = g_strdup("");
gchar *ret = g_strdup_printf("[%s]\n", _("Monitors"));
gchar tag_prefix[] = "DEV";
@@ -228,8 +287,9 @@ gchar *monitors_get_info() {
for(i = 0; edid_files[i]; i++) {
monitor *m = monitor_new_from_sysfs(edid_files[i]);
if (m) {
+ edid *e = m->e;
found++;
- if (m->e && m->e->checksum_ok && m->drm_connection) {
+ if (e && e->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);