diff options
| author | Burt P <pburt0@gmail.com> | 2019-08-18 15:16:22 -0500 | 
|---|---|---|
| committer | Leandro A. F. Pereira <leandro@hardinfo.org> | 2019-08-18 23:49:29 +0200 | 
| commit | e468a3b02dd5dac177b5ae0b611cfe95393a60d1 (patch) | |
| tree | 83e915ae63eb80a05a1933ff61bedd330a3d2348 | |
| parent | 0e0797a9257c8ee039746da9903138c19615e7a0 (diff) | |
monitors: more
Signed-off-by: Burt P <pburt0@gmail.com>
| -rw-r--r-- | deps/sysobj_early/include/util_edid.h | 29 | ||||
| -rw-r--r-- | deps/sysobj_early/src/util_edid.c | 118 | ||||
| -rw-r--r-- | modules/devices/monitors.c | 146 | 
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); | 
