aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--deps/sysobj_early/include/util_edid.h16
-rw-r--r--deps/sysobj_early/src/util_edid.c155
-rw-r--r--modules/devices/monitors.c41
3 files changed, 189 insertions, 23 deletions
diff --git a/deps/sysobj_early/include/util_edid.h b/deps/sysobj_early/include/util_edid.h
index 45dad136..9714bfbb 100644
--- a/deps/sysobj_early/include/util_edid.h
+++ b/deps/sysobj_early/include/util_edid.h
@@ -26,14 +26,22 @@
typedef struct {
float horiz_cm, vert_cm;
float diag_cm, diag_in;
+ int horiz_blanking, vert_blanking;
int horiz_pixels, vert_lines, vert_pixels;
+ float vert_freq_hz;
int is_interlaced;
int stereo_mode;
int pixel_clock_khz;
- int src; /* 0: edid, 1: dtd, 2: cea-dtd, ... */
+ int src; /* 0: edid, 1: etb, 2: std, 3: dtd, 4: cea-dtd, ... */
+ uint64_t pixels; /* h*v: easier to compare */
char class_inch[6];
} edid_output;
+struct edid_std {
+ uint8_t *ptr;
+ edid_output out;
+};
+
struct edid_dtd {
uint8_t *ptr;
int cea_ext;
@@ -90,6 +98,12 @@ typedef struct {
int ext_blocks, ext_blocks_ok, ext_blocks_fail;
uint8_t *ext_ok;
+ int etb_count;
+ edid_output etbs[24];
+
+ int std_count;
+ struct edid_std stds[8];
+
int dtd_count;
struct edid_dtd *dtds;
diff --git a/deps/sysobj_early/src/util_edid.c b/deps/sysobj_early/src/util_edid.c
index b998fb40..7b004dc9 100644
--- a/deps/sysobj_early/src/util_edid.c
+++ b/deps/sysobj_early/src/util_edid.c
@@ -86,10 +86,28 @@ static void edid_output_fill(edid_output *out) {
+ (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;
+ if (out->is_interlaced) {
+ if (out->vert_lines)
+ out->vert_pixels = out->vert_lines * 2;
+ else
+ out->vert_lines = out->vert_pixels / 2;
+ } else {
+ if (out->vert_lines)
+ out->vert_pixels = out->vert_lines;
+ else
+ out->vert_lines = out->vert_pixels;
+ }
+
+ if (!out->vert_freq_hz && out->pixel_clock_khz) {
+ uint64_t h = out->horiz_pixels + out->horiz_blanking;
+ uint64_t v = out->vert_lines + out->vert_blanking;
+ uint64_t work = out->pixel_clock_khz * 1000;
+ work /= (h*v);
+ out->vert_freq_hz = work;
+ }
+
+ out->pixels = out->horiz_pixels;
+ out->pixels *= out->vert_pixels;
static const char *inlbl = "\""; /* TODO: unicode */
sprintf(out->class_inch, "%0.1f%s", out->diag_in, inlbl);
@@ -146,6 +164,71 @@ edid *edid_new(const char *data, unsigned int len) {
e->img_max = e->img;
}
+ /* established timing bitmap */
+#define ETB_CHECK(byte, bit, h, v, f, i) \
+ if (byte & (1<<bit)) { \
+ e->etbs[e->etb_count] = e->img; \
+ e->etbs[e->etb_count].horiz_pixels = h; \
+ e->etbs[e->etb_count].vert_pixels = v; \
+ e->etbs[e->etb_count].vert_freq_hz = f; \
+ e->etbs[e->etb_count].is_interlaced = i; \
+ e->etbs[e->etb_count].src = 1; \
+ edid_output_fill(&e->etbs[e->etb_count]);\
+ e->etb_count++; };
+ ETB_CHECK(35, 7, 720, 400, 70, 0); //(VGA)
+ ETB_CHECK(35, 6, 720, 400, 88, 0); //(XGA)
+ ETB_CHECK(35, 5, 640, 480, 60, 0); //(VGA)
+ ETB_CHECK(35, 4, 640, 480, 67, 0); //(Apple Macintosh II)
+ ETB_CHECK(35, 3, 640, 480, 72, 0);
+ ETB_CHECK(35, 2, 640, 480, 75, 0);
+ ETB_CHECK(35, 1, 800, 600, 56, 0);
+ ETB_CHECK(35, 0, 800, 600, 60, 0);
+ ETB_CHECK(36, 7, 800, 600, 72, 0);
+ ETB_CHECK(36, 6, 800, 600, 75, 0);
+ ETB_CHECK(36, 5, 832, 624, 75, 0); //(Apple Macintosh II)
+ ETB_CHECK(36, 4, 1024, 768, 87, 1); //(1024×768i)
+ ETB_CHECK(36, 3, 1024, 768, 60, 0);
+ ETB_CHECK(36, 2, 1024, 768, 70, 0);
+ ETB_CHECK(36, 1, 1024, 768, 75, 0);
+ ETB_CHECK(36, 0, 1280, 1024, 75, 0);
+ ETB_CHECK(35, 7, 1152, 870, 75, 0); //(Apple Macintosh II)
+
+ /* standard timings */
+ for(i = 38; i < 53; i+=2) {
+ /* 0101 is unused */
+ if (e->u8[i] == 0x01 && e->u8[i] == 0x01)
+ continue;
+ double xres = (e->u8[i] + 31) * 8;
+ double yres = 0;
+ int iar = (e->u8[i+1] >> 6) & 0x3;
+ int vf = (e->u8[i+1] & 0x3f) + 60;
+ switch(iar) {
+ case 0: /* 16:10 (v<1.3 1:1) */
+ if (e->ver_major == 1 && e->ver_minor < 3)
+ yres = xres;
+ else
+ yres = xres*10/16;
+ break;
+ case 0x1: /* 4:3 */
+ yres = xres*4/3;
+ break;
+ case 0x2: /* 5:4 */
+ yres = xres*4/5;
+ break;
+ case 0x3: /* 16:9 */
+ yres = xres*9/16;
+ break;
+ }
+ e->stds[e->std_count].ptr = &e->u8[i];
+ e->stds[e->std_count].out = e->img; /* inherit */
+ e->stds[e->std_count].out.horiz_pixels = xres;
+ e->stds[e->std_count].out.vert_pixels = yres;
+ e->stds[e->std_count].out.vert_freq_hz = vf;
+ e->stds[e->std_count].out.src = 2;
+ edid_output_fill(&e->stds[e->std_count].out);
+ e->std_count++;
+ }
+
uint16_t dh, dl;
#define CHECK_DESCRIPTOR(index, offset) \
if (e->u8[offset] == 0) { \
@@ -251,17 +334,40 @@ edid *edid_new(const char *data, unsigned int len) {
}
}
+ /* largest in ETB */
+ for (i = 0; i < e->etb_count; i++) {
+ if (e->etbs[i].pixels > e->img.pixels)
+ e->img = e->etbs[i];
+ if (e->etbs[i].pixels > e->img_max.pixels)
+ e->img_max = e->etbs[i];
+ }
+
+ /* largest in STDs */
+ for (i = 0; i < e->std_count; i++) {
+ if (e->stds[i].out.pixels > e->img.pixels)
+ e->img = e->stds[i].out;
+ if (e->stds[i].out.pixels > e->img_max.pixels)
+ e->img_max = e->stds[i].out;
+ }
+
/* dtds */
for(i = 0; i < e->dtd_count; i++) {
uint8_t *u8 = e->dtds[i].ptr;
+ uint16_t *u16 = (uint16_t*)e->dtds[i].ptr;
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;
+ if (e->dtds[i].cea_ext) out->src = 4;
+ else out->src = 3;
+ out->pixel_clock_khz = le16toh(u16[0]) * 10;
out->horiz_pixels =
((u8[4] & 0xf0) << 4) + u8[2];
out->vert_lines =
((u8[7] & 0xf0) << 4) + u8[5];
+
+ out->horiz_blanking =
+ ((u8[4] & 0x0f) << 8) + u8[3];
+ out->vert_blanking =
+ ((u8[7] & 0x0f) << 8) + u8[6];
+
out->horiz_cm =
((u8[14] & 0xf0) << 4) + u8[12];
out->horiz_cm /= 10;
@@ -275,7 +381,7 @@ edid *edid_new(const char *data, unsigned int len) {
}
if (e->dtd_count) {
- /* first DTD replaces the basic EDID size */
+ /* first DTD is "preferred" */
e->img_max = e->dtds[0].out;
}
@@ -374,8 +480,10 @@ const char *edid_standard(int std) {
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");
+ case 1: return N_("VESA EDID ETB");
+ case 2: return N_("VESA EDID STD");
+ case 3: return N_("VESA EDID DTD");
+ case 4: return N_("EIA/CEA-861 DTD");
};
return N_("unknown");
}
@@ -562,10 +670,10 @@ char *edid_cea_block_describe(struct edid_cea_block *blk) {
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,
+ ret = g_strdup_printf("%dx%d@%.0f%s, %0.1fx%0.1f%s (%0.1f\") %s %s",
+ out->horiz_pixels, out->vert_pixels, out->vert_freq_hz, _("Hz"),
out->horiz_cm, out->vert_cm, _("cm"), out->diag_in,
- out->is_interlaced ? "interlaced" : "non-interlaced",
+ out->is_interlaced ? "interlaced" : "progressive",
out->stereo_mode ? "stereo" : "normal");
}
return ret;
@@ -576,10 +684,10 @@ char *edid_dtd_describe(struct edid_dtd *dtd, int dump_bytes) {
if (dtd) {
edid_output *out = &dtd->out;
char *hb = hex_bytes(dtd->ptr, 18);
- ret = g_strdup_printf("%dx%d, %0.2fx%0.2f%s (%0.1f\") %s %s (%s)%s%s",
- out->horiz_pixels, out->vert_lines,
+ ret = g_strdup_printf("%dx%d@%.0f%s, %0.1fx%0.1f%s (%0.1f\") %s %s (%s)%s%s",
+ out->horiz_pixels, out->vert_lines, out->vert_freq_hz, _("Hz"),
out->horiz_cm, out->vert_cm, _("cm"), out->diag_in,
- out->is_interlaced ? "interlaced" : "non-interlaced",
+ out->is_interlaced ? "interlaced" : "progressive",
out->stereo_mode ? "stereo" : "normal",
_(edid_output_src(out->src)),
dump_bytes ? " -- " : "",
@@ -597,7 +705,7 @@ char *edid_dump2(edid *e) {
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);
+ ret = appfnl(ret, "mfg: %s, model: [%04x-%08x] %u-%u", e->ven, e->product, e->n_serial, e->product, e->n_serial);
if (e->week && e->year)
ret = appf(ret, "", ", dom: week %d of %d", e->week, e->year);
else if (e->year)
@@ -616,6 +724,18 @@ char *edid_dump2(edid *e) {
g_free(desc);
g_free(desc_max);
+ for(i = 0; i < e->etb_count; i++) {
+ char *desc = edid_output_describe(&e->etbs[i]);
+ ret = appfnl(ret, "etb[%d]: %s", i, desc);
+ g_free(desc);
+ }
+
+ for(i = 0; i < e->std_count; i++) {
+ char *desc = edid_output_describe(&e->stds[i].out);
+ ret = appfnl(ret, "std[%d]: %s", i, desc);
+ g_free(desc);
+ }
+
ret = appfnl(ret, "checksum %s", e->checksum_ok ? "ok" : "failed!");
if (e->ext_blocks_ok || e->ext_blocks_fail)
ret = appf(ret, "", ", extension blocks: %d of %d ok", e->ext_blocks_ok, e->ext_blocks_ok + e->ext_blocks_fail);
@@ -637,6 +757,7 @@ char *edid_dump2(edid *e) {
ret = appfnl(ret, "dtd[%d] %s", i, desc);
free(desc);
}
+
for(i = 0; i < e->cea_block_count; i++) {
char *desc = edid_cea_block_describe(&e->cea_blocks[i]);
ret = appfnl(ret, "cea_block[%d] %s", i, desc);
diff --git a/modules/devices/monitors.c b/modules/devices/monitors.c
index 06faf6fb..71f506c2 100644
--- a/modules/devices/monitors.c
+++ b/modules/devices/monitors.c
@@ -178,13 +178,31 @@ static gchar *make_edid_section(monitor *m) {
const gchar *iface = e->interface ? _(edid_interface(e->interface)) : _("(Unspecified)");
- gchar *d_list, *ext_list, *dtd_list, *cea_list;
+ gchar *d_list, *ext_list, *dtd_list, *cea_list,
+ *etb_list, *std_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 = g_strdup("");
+ d_list = NULL;
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] : "{...}");
+ if (!d_list) d_list = g_strdup_printf("%s=\n", _("(Empty List)"));
- ext_list = g_strdup("");
+ 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];
@@ -193,19 +211,22 @@ static gchar *make_edid_section(monitor *m) {
e->ext_ok[i] ? "ok" : "fail"
);
}
+ if (!ext_list) ext_list = g_strdup_printf("%s=\n", _("(Empty List)"));
- dtd_list = g_strdup("");
+ 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 = g_strdup("");
+ 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)"));
gchar *hex = edid_dump_hex(e, 0, 1);
gchar *hex_esc = gg_key_file_parse_string_as_value(hex, '|');
@@ -227,6 +248,8 @@ static gchar *make_edid_section(monitor *m) {
"[%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 */
@@ -238,6 +261,8 @@ static gchar *make_edid_section(monitor *m) {
"[%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"),
@@ -249,6 +274,8 @@ static gchar *make_edid_section(monitor *m) {
_("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"),
@@ -258,6 +285,8 @@ static gchar *make_edid_section(monitor *m) {
_("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,
_("Hex Dump"), _("Data"), hex
@@ -267,6 +296,8 @@ static gchar *make_edid_section(monitor *m) {
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(hex);