aboutsummaryrefslogtreecommitdiff
path: root/deps/sysobj_early
diff options
context:
space:
mode:
authorBurt P <pburt0@gmail.com>2019-08-18 02:32:58 -0500
committerLeandro A. F. Pereira <leandro@hardinfo.org>2019-08-18 23:49:29 +0200
commit0e0797a9257c8ee039746da9903138c19615e7a0 (patch)
tree9844f60b23370c1bf42692ce086a4ba7c935acff /deps/sysobj_early
parente49e438270cdffc4a80a2676c73ad95bedce33d4 (diff)
monitors: updated util_edid
Signed-off-by: Burt P <pburt0@gmail.com>
Diffstat (limited to 'deps/sysobj_early')
-rw-r--r--deps/sysobj_early/include/util_edid.h93
-rw-r--r--deps/sysobj_early/src/appf.c2
-rw-r--r--deps/sysobj_early/src/util_edid.c624
3 files changed, 512 insertions, 207 deletions
diff --git a/deps/sysobj_early/include/util_edid.h b/deps/sysobj_early/include/util_edid.h
index 3d54fa0d..af9364e0 100644
--- a/deps/sysobj_early/include/util_edid.h
+++ b/deps/sysobj_early/include/util_edid.h
@@ -23,16 +23,72 @@
#include <stdint.h> /* for *int*_t types */
-#define EDID_MAX_EXT_BLOCKS 254
+struct edid_dtd {
+ uint8_t *ptr;
+ int pixel_clock_khz;
+ int horiz_pixels;
+ int vert_lines;
+};
+
+struct edid_cea_header {
+ uint8_t *ptr;
+ int type, len;
+};
+
+struct edid_cea_block {
+ struct edid_cea_header header;
+ int reserved[8];
+};
+
+struct edid_cea_audio {
+ struct edid_cea_header header;
+ int format, channels, freq_bits;
+ int depth_bits; /* format 1 */
+ int max_kbps; /* formats 2-8 */
+};
+
+struct edid_cea_video {
+ struct edid_cea_header header;
+};
+
+struct edid_cea_vendor_spec {
+ struct edid_cea_header header;
+};
+
+struct edid_cea_speaker {
+ struct edid_cea_header header;
+ int alloc_bits;
+};
+
+typedef struct {
+ union {
+ void* data;
+ uint8_t* u8;
+ uint16_t* u16;
+ uint32_t* u32;
+ };
+ unsigned int len;
+
+ /* 0 - EDID
+ * 1 - EIA/CEA-861
+ * 2 - DisplayID
+ */
+ int std;
-/* just enough edid decoding */
-struct edid {
int ver_major, ver_minor;
- char ven[4];
+ int checksum_ok; /* first 128-byte block only */
+ int ext_blocks, ext_blocks_ok, ext_blocks_fail;
+ uint8_t *ext_ok;
+
+ int dtd_count;
+ struct edid_dtd *dtds;
+ int cea_block_count;
+ struct edid_cea_block *cea_blocks;
+
+ char ven[4];
int d_type[4];
char d_text[4][14];
-
/* point into d_text */
char *name;
char *serial;
@@ -41,28 +97,27 @@ struct edid {
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 */
+} edid;
+edid *edid_new(const char *data, unsigned int len);
+edid *edid_new_from_hex(const char *hex_string);
+void edid_free(edid *e);
+char *edid_dump_hex(edid *e, int tabs, int breaks);
- 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);
+const char *edid_standard(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);
-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);
+char *edid_dtd_describe(struct edid_dtd *dtd);
+char *edid_cea_block_describe(struct edid_cea_block *blk);
-const char *edid_descriptor_type(int type);
-char *edid_dump(struct edid *id);
+char *edid_dump2(edid *e);
#endif
diff --git a/deps/sysobj_early/src/appf.c b/deps/sysobj_early/src/appf.c
index 5969d945..e63e77d0 100644
--- a/deps/sysobj_early/src/appf.c
+++ b/deps/sysobj_early/src/appf.c
@@ -28,7 +28,7 @@
/* FIXME: if this isn't here, hardinfo will crash,
* I don't have the slightest idea why */
void wtf() {
- edid_fill(NULL, NULL, 0);
+ void *e = edid_new(NULL, 0);
}
char *appf(char *str, const char *sep, const char *fmt, ...) {
diff --git a/deps/sysobj_early/src/util_edid.c b/deps/sysobj_early/src/util_edid.c
index 3f953191..80a71002 100644
--- a/deps/sysobj_early/src/util_edid.c
+++ b/deps/sysobj_early/src/util_edid.c
@@ -25,12 +25,12 @@
#include <math.h>
#include <endian.h>
#include <stdio.h>
+#include "gettext.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) {
+static 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;
@@ -40,148 +40,238 @@ int block_check(const void *edid_block_bytes) {
return sum == 0 ? 1 : 0;
}
-int edid_fill(struct edid *id_out, const void *edid_bytes, int edid_len) {
+char *hex_bytes(uint8_t *bytes, int count) {
+ char *buffer = malloc(count*3+1), *p = buffer;
+ memset(buffer, 0, count*3+1);
int i;
+ for(i = 0; i < count; i++) {
+ sprintf(p, "%02x ", (unsigned int)bytes[i]);
+ p += 3;
+ }
+ return buffer;
+}
- 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++;
- }
+static void cea_block_decode(struct edid_cea_block *blk) {
+ struct edid_cea_audio *blk_audio = (void*)blk;
+ struct edid_cea_video *blk_video = (void*)blk;
+ struct edid_cea_speaker *blk_speaker = (void*)blk;
+ struct edid_cea_vendor_spec *blk_vendor_spec = (void*)blk;
+ if (blk) {
+ switch(blk->header.type) {
+ case 0x1:
+ blk_audio->format = (blk->header.ptr[1] & 0x78) >> 3;
+ blk_audio->channels = 1 + blk->header.ptr[1] & 0x7;
+ blk_audio->freq_bits = blk->header.ptr[2];
+ if (blk_audio->format == 1) {
+ blk_audio->depth_bits = blk->header.ptr[3];
+ } else if (blk_audio->format >= 2
+ && blk_audio->format <= 8) {
+ blk_audio->max_kbps = blk->header.ptr[3] * 8;
+ }
+ break;
+ case 0x4:
+ blk_speaker->alloc_bits = blk->header.ptr[1];
+ break;
+ case 0x3:
+ case 0x2:
+ default:
+ break;
}
+ }
+}
- /* 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;
- }
- }
+edid *edid_new(const char *data, unsigned int len) {
+ if (len < 128) return NULL;
- 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;
+ int i;
+ edid *e = malloc(sizeof(edid));
+ memset(e, 0, sizeof(edid));
+ e->data = malloc(len);
+ memcpy(e->data, data, len);
+ e->len = len;
+ e->ver_major = e->u8[18];
+ e->ver_minor = e->u8[19];
+
+ e->dtds = malloc(sizeof(struct edid_dtd) * 1000);
+ e->cea_blocks = malloc(sizeof(struct edid_cea_block) * 1000);
+
+ uint16_t vid = be16toh(e->u16[4]); /* bytes 8-9 */
+ e->ven[2] = 64 + (vid & 0x1f);
+ e->ven[1] = 64 + ((vid >> 5) & 0x1f);
+ e->ven[0] = 64 + ((vid >> 10) & 0x1f);
+ e->product = le16toh(e->u16[5]); /* bytes 10-11 */
+ e->n_serial = le32toh(e->u32[3]);/* bytes 12-15 */
+ e->week = e->u8[16]; /* byte 16 */
+ e->year = e->u8[17] + 1990; /* byte 17 */
+
+ if (e->week >= 52)
+ e->week = 0;
+
+ e->a_or_d = (e->u8[20] & 0x80) ? 1 : 0;
+ if (e->a_or_d == 1) {
+ /* digital */
+ switch((e->u8[20] >> 4) & 0x7) {
+ case 0x1: e->bpc = 6; break;
+ case 0x2: e->bpc = 8; break;
+ case 0x3: e->bpc = 10; break;
+ case 0x4: e->bpc = 12; break;
+ case 0x5: e->bpc = 14; break;
+ case 0x6: e->bpc = 16; break;
}
+ }
- uint16_t dh, dl;
+ 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;
+ }
- /* 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);
- }
+ uint16_t dh, dl;
+#define CHECK_DESCRIPTOR(index, offset) \
+ if (e->u8[offset] == 0) { \
+ dh = be16toh(e->u16[offset/2]); \
+ dl = be16toh(e->u16[offset/2+1]); \
+ e->d_type[index] = (dh << 16) + dl; \
+ switch(e->d_type[index]) { \
+ case 0xfc: case 0xff: case 0xfe: \
+ strncpy(e->d_text[index], (char*)e->u8+offset+5, 13); \
+ } \
+ } else e->dtds[e->dtd_count++].ptr = &e->u8[offset];
+
+ CHECK_DESCRIPTOR(0, 54);
+ CHECK_DESCRIPTOR(1, 72);
+ CHECK_DESCRIPTOR(2, 90);
+ CHECK_DESCRIPTOR(3, 108);
+
+ e->checksum_ok = block_check(e->data); /* first 128-byte block only */
+ if (len > 128) {
+ /* check extension blocks */
+ int blocks = len / 128;
+ blocks--;
+ e->ext_blocks = blocks;
+ e->ext_ok = malloc(sizeof(uint8_t) * blocks);
+ for(; blocks; blocks--) {
+ uint8_t *u8 = e->u8 + (blocks * 128);
+ int r = block_check(u8);
+ e->ext_ok[blocks-1] = r;
+ if (r) e->ext_blocks_ok++;
+ else e->ext_blocks_fail++;
+
+ if (u8[0] == 0x70) {
+ e->std = MAX(e->std, 2);
+ /* DisplayID */
+ // TODO: ...
+ }
- /* 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);
+ if (u8[0] == 0x02) {
+ e->std = MAX(e->std, 1);
+ /* CEA extension */
+ int db_end = u8[2];
+ //printf("db_end: %d\n", db_end);
+ if (db_end) {
+ int b = 4;
+ while(b < db_end) {
+ int db_type = (u8[b] & 0xe0) >> 5;
+ int db_size = u8[b] & 0x1f;
+ //printf("CEA BLK: %s\n", hex_bytes(&u8[b], db_size+1));
+ e->cea_blocks[e->cea_block_count].header.ptr = &u8[b];
+ e->cea_blocks[e->cea_block_count].header.type = db_type;
+ e->cea_blocks[e->cea_block_count].header.len = db_size;
+ cea_block_decode(&e->cea_blocks[e->cea_block_count]);
+ e->cea_block_count++;
+ b += db_size + 1;
+ }
+ if (b > db_end) b = db_end;
+ //printf("dtd start: %d\n", b);
+ /* DTDs */
+ while(b < 127) {
+ if (u8[b]) {
+ //printf("DTD: %s\n", hex_bytes(&u8[b], 18));
+ e->dtds[e->dtd_count].ptr = &u8[b];
+ e->dtd_count++;
+ }
+ b += 18;
+ }
+ }
+ }
}
+ }
- /* 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);
+ /* strings */
+ for(i = 0; i < 4; i++) {
+ g_strstrip(e->d_text[i]);
+ switch(e->d_type[i]) {
+ case 0xfc:
+ e->name = e->d_text[i];
+ break;
+ case 0xff:
+ e->serial = e->d_text[i];
+ break;
+ case 0xfe:
+ if (e->ut1)
+ e->ut2 = e->d_text[i];
+ else
+ e->ut1 = e->d_text[i];
+ break;
}
+ }
- /* 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);
+ /* quirks */
+ if (!e->name) {
+ if (SEQ(e->ut1, "LG Display") && e->ut2)
+ /* LG may use "uspecified text" for name and model */
+ e->name = e->ut2;
+ else if (SEQ(e->ut1, "AUO") && e->ut2)
+ /* Same with AUO */
+ e->name = e->ut2;
+ else {
+ if (e->ut1) e->name = e->ut1;
+ if (e->ut2 && !e->serial) e->serial = e->ut2;
}
+ }
- 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;
- }
- }
+ /* 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 =
+ ((u8[4] & 0xf0) << 4) + u8[2];
+ e->dtds[i].vert_lines =
+ ((u8[7] & 0xf0) << 4) + u8[5];
+ }
- 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;
- }
- }
+ /* squeeze lists */
+ if (!e->dtd_count) {
+ free(e->dtds);
+ e->dtds = NULL;
+ } else {
+ e->dtds = realloc(e->dtds, sizeof(struct edid_dtd) * e->dtd_count);
+ }
+ if (!e->cea_block_count) {
+ if (e->cea_blocks)
+ free(e->cea_blocks);
+ e->cea_blocks = NULL;
+ } else {
+ e->cea_blocks = realloc(e->cea_blocks, sizeof(struct edid_cea_block) * e->cea_block_count);
+ }
+
+ return e;
+}
+
+void edid_free(edid *e) {
+ if (e) {
+ g_free(e->ext_ok);
+ g_free(e->cea_blocks);
+ g_free(e->dtds);
+ g_free(e->data);
+ g_free(e);
}
- return 1;
}
-int edid_hex_to_bin(void **edid_bytes, int *edid_len, const char *hex_string) {
+edid *edid_new_from_hex(const char *hex_string) {
int blen = strlen(hex_string) / 2;
uint8_t *buffer = malloc(blen), *n = buffer;
memset(buffer, 0, blen);
@@ -202,24 +292,110 @@ int edid_hex_to_bin(void **edid_bytes, int *edid_len, const char *hex_string) {
p++;
}
- *edid_bytes = (void *)buffer;
- *edid_len = len;
- return 1;
+ edid *e = edid_new((char*)buffer, len);
+ free(buffer);
+ return e;
}
-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);
+char *edid_dump_hex(edid *e, int tabs, int breaks) {
+ if (!e) return NULL;
+ int lines = e->len / 16;
+ int blen = lines * 35 + 1;
+ unsigned int pc = 0;
+ char *ret = malloc(blen);
+ memset(ret, 0, blen);
+ uint8_t *u8 = e->u8;
+ char *p = ret;
+ for(; lines; lines--) {
+ int i;
+ for(i = 0; i < tabs; i++)
+ sprintf(p++, "\t");
+ for(i = 0; i < 16; i++) {
+ sprintf(p, "%02x", (unsigned int)*u8);
+ p+=2;
+ u8++;
+ pc++;
+ if (pc == e->len) {
+ if (breaks) sprintf(p++, "\n");
+ goto edid_dump_hex_done;
+ }
+ }
+ if (breaks) sprintf(p++, "\n");
+ }
+edid_dump_hex_done:
+ return ret;
+}
+
+const char *edid_standard(int std) {
+ switch(std) {
+ case 0: return N_("VESA EDID");
+ case 1: return N_("EIA/CEA-861");
+ case 2: return N_("VESA DisplayID");
+ };
+ return N_("unknown");
+}
+
+const char *edid_cea_audio_type(int type) {
+ switch(type) {
+ case 0: case 15: return N_("reserved");
+ case 1: return N_("LPCM");
+ case 2: return N_("AC-3");
+ case 3: return N_("MPEG1 (layers 1 and 2)");
+ case 4: return N_("MPEG1 layer 3");
+ case 5: return N_("MPEG2");
+ case 6: return N_("AAC");
+ case 7: return N_("DTS");
+ case 8: return N_("ATRAC");
+ case 9: return N_("DSD");
+ case 10: return N_("DD+");
+ case 11: return N_("DTS-HD");
+ case 12: return N_("MLP/Dolby TrueHD");
+ case 13: return N_("DST Audio");
+ case 14: return N_("WMA Pro");
+ }
+ return N_("unknown type");
+}
+
+const char *edid_cea_block_type(int type) {
+ switch(type) {
+ case 0x01:
+ return N_("audio");
+ case 0x02:
+ return N_("video");
+ case 0x03:
+ return N_("vendor specific");
+ case 0x04:
+ return N_("speaker allocation");
+ }
+ return N_("unknown type");
}
const char *edid_ext_block_type(int type) {
switch(type) {
- case 0xf0:
- return N_("extension block map");
+ case 0x00:
+ return N_("timing extension");
case 0x02:
return N_("EIA/CEA-861 extension block");
+ case 0x10:
+ return N_("video timing block");
+ case 0x20:
+ return N_("EDID 2.0 extension");
+ case 0x40:
+ return N_("DVI feature data/display information");
+ case 0x50:
+ return N_("localized strings");
+ case 0x60:
+ return N_("microdisplay interface");
+ case 0x70:
+ return N_("DisplayID");
+ case 0xa7:
+ case 0xaf:
+ case 0xbf:
+ return N_("display transfer characteristics data block");
+ case 0xf0:
+ return N_("extension block map");
+ case 0xff:
+ return N_("manufacturer-defined extension/display device data block");
}
return N_("unknown block type");
}
@@ -247,73 +423,147 @@ const char *edid_descriptor_type(int type) {
case 0x10:
return N_("dummy");
}
- if (type < 0x0f) return N_("manufacturer reserved descriptor");
+ if (type && type < 0x0f)
+ return N_("manufacturer reserved descriptor");
return N_("detailed timing descriptor");
}
-char *edid_dump(struct edid *id) {
+char *edid_cea_block_describe(struct edid_cea_block *blk) {
+ gchar *ret = NULL;
+ gchar *tmp[3] = {};
+ struct edid_cea_audio *blk_audio = (void*)blk;
+ struct edid_cea_video *blk_video = (void*)blk;
+ struct edid_cea_speaker *blk_speaker = (void*)blk;
+ struct edid_cea_vendor_spec *blk_vendor_spec = (void*)blk;
+
+ if (blk) {
+ char *hb = hex_bytes(blk->header.ptr, blk->header.len+1);
+ switch(blk->header.type) {
+ case 0x1:
+
+#define appfreq(b, f) if (blk_audio->freq_bits & (1 << b)) tmp[0] = appf(tmp[0], ", ", "%d", f);
+#define appdepth(b, d) if (blk_audio->depth_bits & (1 << b)) tmp[1] = appf(tmp[1], ", ", "%d%s", d, _("-bit"));
+ appfreq(0, 32);
+ appfreq(1, 44);
+ appfreq(2, 48);
+ appfreq(3, 88);
+ appfreq(4, 96);
+ appfreq(5, 176);
+ appfreq(6, 192);
+
+ if (blk_audio->format == 1) {
+ appdepth(0, 16);
+ appdepth(1, 20);
+ appdepth(2, 24);
+ tmp[2] = g_strdup_printf("depths: %s", tmp[1]);
+ } else if (blk_audio->format >= 2
+ && blk_audio->format <= 8 ) {
+ tmp[2] = g_strdup_printf("max_bitrate: %d %s", blk_audio->max_kbps, _("kbps"));
+ } else
+ tmp[2] = g_strdup("");
+
+ ret = g_strdup_printf("([%x] %s) len:%d format:([%x] %s) channels:%d rates:%s %s %s -- %s",
+ blk->header.type, _(edid_cea_block_type(blk->header.type)),
+ blk->header.len,
+ blk_audio->format, _(edid_cea_audio_type(blk_audio->format)),
+ blk_audio->channels, tmp[0], _("kHz"),
+ tmp[2],
+ hb);
+ g_free(tmp[0]);
+ g_free(tmp[1]);
+ g_free(tmp[2]);
+ break;
+ case 0x4:
+#define appspk(b, s) if (blk_speaker->alloc_bits & (1 << b)) tmp[0] = appf(tmp[0], ", ", "%s", s);
+ appspk(0, _("LF+LR: Front left and right"));
+ appspk(1, _("LFE: Low-frequency effects"));
+ appspk(2, _("FC: Front center"));
+ appspk(3, _("LR+LR: Rear left and right"));
+ appspk(4, _("RC: Rear center"));
+ appspk(5, _("???"));
+ appspk(6, _("???"));
+ ret = g_strdup_printf("([%x] %s) len:%d %s -- %s",
+ blk->header.type, _(edid_cea_block_type(blk->header.type)),
+ blk->header.len,
+ tmp[0],
+ hb);
+ g_free(tmp[0]);
+ break;
+ case 0x3:
+ case 0x2:
+ default:
+ ret = g_strdup_printf("([%x] %s) len:%d -- %s",
+ blk->header.type, _(edid_cea_block_type(blk->header.type)),
+ blk->header.len,
+ hb);
+ break;
+ }
+ free(hb);
+ }
+ return ret;
+}
+
+char *edid_dtd_describe(struct edid_dtd *dtd) {
+ gchar *ret = NULL;
+ if (dtd) {
+ char *hb = hex_bytes(dtd->ptr, 18);
+ ret = g_strdup_printf("%dx%d %s",
+ dtd->horiz_pixels, dtd->vert_lines,
+ hb);
+ free(hb);
+ }
+ return ret;
+}
+
+char *edid_dump2(edid *e) {
char *ret = NULL;
int i;
+ if (!e) return NULL;
- if (!id) return NULL;
- ret = appfnl(ret, "edid_version: %d.%d (%d bytes)", id->ver_major, id->ver_minor, id->size);
+ 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, "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, "mfg: %s, model: %u, n_serial: %u", e->ven, 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)
+ ret = appf(ret, "", ", dom: %d", e->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);
+ 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 (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);
+ 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);
- 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);
+ 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);
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] : "{...}");
+ ret = appfnl(ret, "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] : "{...}");
+
+ for(i = 0; i < e->ext_blocks; i++) {
+ int type = e->u8[(i+1)*128];
+ int version = e->u8[(i+1)*128 + 1];
+ ret = appfnl(ret, "ext[%d] ([%02x:v%02x] %s) %s", i,
+ type, version, _(edid_ext_block_type(type)),
+ e->ext_ok[i] ? "ok" : "fail"
+ );
+ }
- 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");
- }
+ for(i = 0; i < e->dtd_count; i++) {
+ char *desc = edid_dtd_describe(&e->dtds[i]);
+ 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);
}
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;
-}