aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--edid-decode.cpp80
-rw-r--r--edid-decode.h15
-rw-r--r--parse-base-block.cpp55
-rw-r--r--parse-cta-block.cpp41
-rw-r--r--parse-displayid-block.cpp25
5 files changed, 144 insertions, 72 deletions
diff --git a/edid-decode.cpp b/edid-decode.cpp
index 85fac26..ce6f65a 100644
--- a/edid-decode.cpp
+++ b/edid-decode.cpp
@@ -169,6 +169,14 @@ void calc_ratio(struct timings *t)
t->vratio = t->vact / d;
}
+std::string edid_state::dtd_name()
+{
+ unsigned len = std::to_string(preparse_total_dtds).length();
+ char buf[16];
+ sprintf(buf, "DTD %*u", len, dtd_cnt);
+ return buf;
+}
+
bool edid_state::match_timings(const timings &t1, const timings &t2)
{
if (t1.hact != t2.hact ||
@@ -191,13 +199,16 @@ bool edid_state::match_timings(const timings &t1, const timings &t2)
}
bool edid_state::print_timings(const char *prefix, const struct timings *t,
- const char *suffix, const char *flags)
+ const char *type, const char *flags,
+ bool detailed)
{
if (!t) {
// Should not happen
fail("Unknown video timings.\n");
return false;
}
+ if (!type)
+ type = "";
unsigned vact = t->vact;
unsigned hbl = t->hfp + t->hsync + t->hbp;
@@ -230,45 +241,54 @@ bool edid_state::print_timings(const char *prefix, const struct timings *t,
double refresh = (double)t->pixclk_khz * 1000.0 / (htotal * vtotal);
- if (flags) {
- printf("%sDetailed mode: Clock %.3f MHz", prefix, t->pixclk_khz / 1000.0);
+ std::string s;
+ if (t->rb) {
+ s = "RB";
+ if (t->rb == 2)
+ s += "v2";
+ }
+ if (flags && *flags) {
+ if (!s.empty())
+ s += ", ";
+ s += flags;
+ }
+ if (t->hsize_mm || t->vsize_mm) {
+ if (!s.empty())
+ s += ", ";
+ s += std::to_string(t->hsize_mm) + " mm x " + std::to_string(t->vsize_mm) + " mm";
+ }
+ if (!s.empty())
+ s = " (" + s + ")";
+
+ if (detailed) {
+ unsigned len = strlen(type) + 2;
+
+ printf("%s%s: Clock %.3f MHz", prefix, type, t->pixclk_khz / 1000.0);
if (flags && *flags)
printf(", %s", flags);
if (t->hsize_mm || t->vsize_mm)
printf(", %u mm x %u mm", t->hsize_mm, t->vsize_mm);
printf("\n");
- printf("%s %4u %4u %4u %4u (%3d %3u %3d)%s\n"
- "%s %4u %4u %4u %4u (%3u %3u %3d)%s\n"
- "%s %chsync%s\n"
- "%s VertFreq: %.3f%s Hz, HorFreq: %.3f kHz\n",
- prefix,
+ printf("%s%*s%4u %4u %4u %4u (%3d %3u %3d)%s\n"
+ "%s%*s%4u %4u %4u %4u (%3u %3u %3d)%s\n"
+ "%s%*s%chsync%s\n"
+ "%s%*sVertFreq: %.3f%s Hz, HorFreq: %.3f kHz\n",
+ prefix, len, "",
t->hact, t->hact + t->hfp, t->hact + t->hfp + t->hsync,
htotal, t->hfp, t->hsync, t->hbp,
t->hborder ? (std::string(" hborder ") + std::to_string(t->hborder)).c_str() : "",
- prefix,
+ prefix, len, "",
vact, vact + t->vfp, vact + t->vfp + t->vsync, vact + vbl, t->vfp, t->vsync, t->vbp,
t->vborder ? (std::string(" vborder ") + std::to_string(t->vborder)).c_str() : "",
- prefix,
+ prefix, len, "",
t->pos_pol_hsync ? '+' : '-', t->no_pol_vsync ? "" : (t->pos_pol_vsync ? " +vsync" : " -vsync"),
- prefix,
+ prefix, len, "",
refresh, t->interlaced ? "i" : "", hor_freq_khz);
} else {
- std::string s(suffix);
- if (t->rb) {
- if (s.empty())
- s = "RB";
- else
- s += ", RB";
- if (t->rb == 2)
- s += "v2";
- }
- if (!s.empty())
- s = " (" + s + ")";
-
char buf[10];
sprintf(buf, "%u%s", t->vact, t->interlaced ? "i" : "");
- printf("%s%5ux%-5s %7.3f Hz %3u:%-3u %7.3f kHz %7.3f MHz%s\n",
- prefix,
+ printf("%s%s: %5ux%-5s %7.3f Hz %3u:%-3u %7.3f kHz %7.3f MHz%s\n",
+ prefix, type,
t->hact, buf,
refresh,
t->hratio, t->vratio,
@@ -863,12 +883,12 @@ int edid_state::parse_edid()
if (options[OptExtract])
dump_breakdown(edid);
- block = block_name(0x00);
- parse_base_block(edid);
-
for (unsigned i = 1; i < num_blocks; i++)
preparse_extension(edid + i * EDID_PAGE_SIZE);
+ block = block_name(0x00);
+ parse_base_block(edid);
+
for (unsigned i = 1; i < num_blocks; i++) {
block_nr++;
printf("\n----------------\n");
@@ -909,7 +929,9 @@ int edid_state::parse_edid()
if (options[OptPreferredTiming]) {
printf("\n----------------\n");
printf("\nPreferred Video Timings:\n");
- print_timings("", &preferred_timings, "", "");
+ print_timings("", &preferred_timings,
+ preferred_type.c_str(),
+ preferred_flags.c_str(), true);
}
if (!options[OptCheck] && !options[OptCheckInline])
diff --git a/edid-decode.h b/edid-decode.h
index dd2608e..bb45fa4 100644
--- a/edid-decode.h
+++ b/edid-decode.h
@@ -61,6 +61,7 @@ struct edid_state {
min_vert_freq_hz = 0xffffffff;
warnings = failures = 0;
memset(&preferred_timings, 0, sizeof(preferred_timings));
+ preparse_total_dtds = 0;
// Base block state
edid_minor = 0;
@@ -69,7 +70,7 @@ struct edid_state {
supports_continuous_freq = supports_gtf =
supports_cvt = uses_gtf = uses_cvt = has_spwg =
seen_non_detailed_descriptor = false;
- timing_descr_cnt = 0;
+ detailed_block_cnt = dtd_cnt = 0;
min_display_hor_freq_hz = max_display_hor_freq_hz =
min_display_vert_freq_hz = max_display_vert_freq_hz =
@@ -99,6 +100,9 @@ struct edid_state {
std::string block;
std::string data_block;
timings preferred_timings;
+ std::string preferred_type;
+ std::string preferred_flags;
+ unsigned preparse_total_dtds;
unsigned min_hor_freq_hz;
unsigned max_hor_freq_hz;
@@ -121,7 +125,8 @@ struct edid_state {
bool uses_gtf;
bool uses_cvt;
bool has_spwg;
- int timing_descr_cnt;
+ unsigned detailed_block_cnt;
+ unsigned dtd_cnt;
bool seen_non_detailed_descriptor;
unsigned min_display_hor_freq_hz;
@@ -153,8 +158,10 @@ struct edid_state {
// Block Map block state
bool saw_block_1;
+ std::string dtd_name();
bool print_timings(const char *prefix, const struct timings *t,
- const char *suffix, const char *flags = 0);
+ const char *type, const char *flags = 0,
+ bool detailed = false);
bool match_timings(const timings &t1, const timings &t2);
void edid_gtf_mode(unsigned refresh, struct timings &t);
void edid_cvt_mode(unsigned refresh, struct timings &t);
@@ -164,7 +171,7 @@ struct edid_state {
void detailed_display_range_limits(const unsigned char *x);
void detailed_epi(const unsigned char *x);
timings detailed_timings(const char *prefix, const unsigned char *x);
- void detailed_block(const unsigned char *x, bool is_base_block = true);
+ void detailed_block(const unsigned char *x);
void parse_base_block(const unsigned char *x);
void print_vic_index(const char *prefix, unsigned idx, const char *suffix);
diff --git a/parse-base-block.cpp b/parse-base-block.cpp
index 55c967f..d4610c0 100644
--- a/parse-base-block.cpp
+++ b/parse-base-block.cpp
@@ -257,7 +257,7 @@ static const struct {
18, 108, 54, false, 12, 2, 35, true }, "IBM" },
{ 0x04 },
{ 0x00, { 640, 480, 4, 3, 30240, 0, false,
- 64, 64, 96, false, 3, 3, 39, false }, "Apple" },
+ 64, 64, 96, false, 3, 3, 39, false }, "Mac" },
{ 0x05 },
{ 0x06 },
{ 0x08 },
@@ -266,7 +266,7 @@ static const struct {
{ 0x0a },
{ 0x0b },
{ 0x00, { 832, 624, 4, 3, 57284, 0, false,
- 32, 64, 224, false, 1, 3, 39, false }, "Apple" },
+ 32, 64, 224, false, 1, 3, 39, false }, "Mac" },
{ 0x0f },
{ 0x10 },
{ 0x11 },
@@ -274,7 +274,7 @@ static const struct {
{ 0x24 },
/* 0x25 bit 7 */
{ 0x00, { 1152, 870, 192, 145, 100000, 0, false,
- 48, 128, 128, true, 3, 3, 39, true }, "Apple" },
+ 48, 128, 128, true, 3, 3, 39, true }, "Mac" },
};
// The bits in the Established Timings III map to DMT timings,
@@ -752,28 +752,28 @@ void edid_state::detailed_cvt_descriptor(const char *prefix, const unsigned char
if (!(x[2] & (1 << (4 - preferred))))
fail("The preferred CVT Vertical Rate is not supported.\n");
- static const char *s_pref = "CVT, preferred vertical rate";
+ static const char *s_pref = "preferred vertical rate";
if (x[2] & 0x10) {
edid_cvt_mode(50, cvt_t);
- print_timings(prefix, &cvt_t, preferred == 0 ? s_pref : "CVT");
+ print_timings(prefix, &cvt_t, "CVT", preferred == 0 ? s_pref : "");
}
if (x[2] & 0x08) {
edid_cvt_mode(60, cvt_t);
- print_timings(prefix, &cvt_t, preferred == 1 ? s_pref : "CVT");
+ print_timings(prefix, &cvt_t, "CVT", preferred == 1 ? s_pref : "");
}
if (x[2] & 0x04) {
edid_cvt_mode(75, cvt_t);
- print_timings(prefix, &cvt_t, preferred == 2 ? s_pref : "CVT");
+ print_timings(prefix, &cvt_t, "CVT", preferred == 2 ? s_pref : "");
}
if (x[2] & 0x02) {
edid_cvt_mode(85, cvt_t);
- print_timings(prefix, &cvt_t, preferred == 3 ? s_pref : "CVT");
+ print_timings(prefix, &cvt_t, "CVT", preferred == 3 ? s_pref : "");
}
if (x[2] & 0x01) {
cvt_t.rb = true;
edid_cvt_mode(60, cvt_t);
- print_timings(prefix, &cvt_t, preferred == 4 ? s_pref : "CVT");
+ print_timings(prefix, &cvt_t, "CVT", preferred == 4 ? s_pref : "");
}
}
@@ -874,14 +874,14 @@ void edid_state::print_standard_timing(const char *prefix, unsigned char b1, uns
if (!gtf_only && edid_minor >= 4) {
uses_cvt = true;
edid_cvt_mode(refresh, formula);
- print_timings(prefix, &formula, "EDID 1.4 source: CVT");
+ print_timings(prefix, &formula, "CVT", "EDID 1.4 source");
/*
* A EDID 1.3 source will assume GTF, so both GTF and CVT
* have to be supported.
*/
uses_gtf = true;
edid_gtf_mode(refresh, formula);
- print_timings(prefix, &formula, "EDID 1.3 source: GTF");
+ print_timings(prefix, &formula, "GTF", "EDID 1.3 source");
} else if (gtf_only || edid_minor >= 2) {
uses_gtf = true;
edid_gtf_mode(refresh, formula);
@@ -1233,7 +1233,7 @@ timings edid_state::detailed_timings(const char *prefix, const unsigned char *x)
unsigned char flags = x[17];
- if (has_spwg && timing_descr_cnt == 2)
+ if (has_spwg && detailed_block_cnt == 2)
flags = *(x - 1);
switch ((flags & 0x18) >> 3) {
@@ -1317,13 +1317,20 @@ timings edid_state::detailed_timings(const char *prefix, const unsigned char *x)
calc_ratio(&t);
- bool ok = print_timings(prefix, &t, "DTD", s_flags.c_str());
+ dtd_cnt++;
+ bool ok = print_timings(prefix, &t, dtd_name().c_str(), s_flags.c_str(), true);
+
+ if (block_nr == 0 && dtd_cnt == 1) {
+ preferred_timings = t;
+ preferred_type = dtd_name();
+ preferred_flags = s_flags;
+ }
if ((max_display_width_mm && !t.hsize_mm) ||
(max_display_height_mm && !t.vsize_mm)) {
fail("Mismatch of image size vs display size: image size is not set, but display size is.\n");
}
- if (has_spwg && timing_descr_cnt == 2)
+ if (has_spwg && detailed_block_cnt == 2)
printf("SPWG Module Revision: %hhu\n", x[17]);
if (!ok) {
std::string s = prefix;
@@ -1334,24 +1341,22 @@ timings edid_state::detailed_timings(const char *prefix, const unsigned char *x)
return t;
}
-void edid_state::detailed_block(const unsigned char *x, bool is_base_block)
+void edid_state::detailed_block(const unsigned char *x)
{
static const unsigned char zero_descr[18] = { 0 };
unsigned cnt;
unsigned i;
- timing_descr_cnt++;
+ detailed_block_cnt++;
if (x[0] || x[1]) {
- data_block = "Detailed Timings #" + std::to_string(timing_descr_cnt);
- timings t = detailed_timings("", x);
- if (is_base_block && timing_descr_cnt == 1)
- preferred_timings = t;
+ data_block = "Detailed Timings #" + std::to_string(dtd_cnt);
+ detailed_timings("", x);
if (seen_non_detailed_descriptor)
fail("Invalid detailed timing descriptor ordering.\n");
return;
}
- data_block = "Display Descriptor #" + std::to_string(timing_descr_cnt);
+ data_block = "Display Descriptor #" + std::to_string(detailed_block_cnt);
/* Monitor descriptor block, not detailed timing descriptor. */
if (x[2] != 0) {
/* 1.3, 3.10.3 */
@@ -1465,13 +1470,13 @@ void edid_state::detailed_block(const unsigned char *x, bool is_base_block)
detailed_display_range_limits(x);
return;
case 0xfe:
- if (!has_spwg || timing_descr_cnt < 3) {
+ if (!has_spwg || detailed_block_cnt < 3) {
data_block = "Alphanumeric Data String";
printf("%s: '%s'\n", data_block.c_str(),
extract_string(x + 5, 13));
return;
}
- if (timing_descr_cnt == 3) {
+ if (detailed_block_cnt == 3) {
char buf[6] = { 0 };
data_block = "SPWG Descriptor #3";
@@ -1788,6 +1793,10 @@ void edid_state::parse_base_block(const unsigned char *x)
(x[0x79] == 1 || x[0x79] == 2) && x[0x7a] <= 1)
has_spwg = true;
+ for (unsigned i = 0; i < (has_spwg ? 2 : 4); i++)
+ if (x[0x36 + i * 18] || x[0x37 + i * 18])
+ preparse_total_dtds++;
+
detailed_block(x + 0x36);
detailed_block(x + 0x48);
detailed_block(x + 0x5a);
diff --git a/parse-cta-block.cpp b/parse-cta-block.cpp
index 0132c8a..dc8200b 100644
--- a/parse-cta-block.cpp
+++ b/parse-cta-block.cpp
@@ -369,15 +369,19 @@ void edid_state::cta_svd(const unsigned char *x, unsigned n, int for_ycbcr420)
supported_hdmi_vic_vsb_codes |= 1 << 3;
break;
}
- char suffix[16];
bool override_pref = i == 0 && !for_ycbcr420 &&
first_svd_might_be_preferred &&
!match_timings(*t, preferred_timings);
- sprintf(suffix, "VIC %3u%s", vic, native ? ", native" : "");
- print_timings(" ", t, suffix);
+ char type[16];
+ sprintf(type, "VIC %3u", vic);
+ const char *flags = native ? "native" : "";
+
+ print_timings(" ", t, type, flags);
if (override_pref) {
preferred_timings = *t;
+ preferred_type = type;
+ preferred_flags = flags;
warn("VIC %u is the preferred timing, overriding the first detailed timings. Is this intended?\n", vic);
}
} else {
@@ -401,14 +405,15 @@ void edid_state::print_vic_index(const char *prefix, unsigned idx, const char *s
if (idx < preparsed_svds[0].size()) {
unsigned char vic = preparsed_svds[0][idx];
const struct timings *t = find_vic_id(vic);
- char buf[256];
+ char buf[16];
- sprintf(buf, "VIC %3u%s%s", vic, *suffix ? ", " : "", suffix);
+ sprintf(buf, "VIC %3u", vic);
if (t)
- print_timings(prefix, t, buf);
+ print_timings(prefix, t, buf, suffix);
else
- printf("%sUnknown (%s)\n", prefix, buf);
+ printf("%sUnknown (%s%s%s)\n", prefix, buf,
+ *suffix ? ", " : "", suffix);
} else {
// Should not happen!
printf("%sSVD Index %u is out of range", prefix, idx + 1);
@@ -479,7 +484,7 @@ void edid_state::cta_vfpdb(const unsigned char *x, unsigned length)
}
} else if (svr > 128 && svr < 145) {
- printf(" DTD number %02u\n", svr - 128);
+ printf(" DTD %u\n", svr - 128);
}
}
}
@@ -1754,6 +1759,17 @@ void edid_state::preparse_cta_block(const unsigned char *x)
unsigned version = x[1];
unsigned offset = x[2];
+ if (offset >= 4) {
+ const unsigned char *detailed;
+
+ for (detailed = x + offset; detailed + 18 < x + 127; detailed += 18) {
+ if (memchk(detailed, 18))
+ break;
+ if (detailed[0] || detailed[1])
+ preparse_total_dtds++;
+ }
+ }
+
if (version < 3)
return;
@@ -1793,6 +1809,10 @@ void edid_state::parse_cta_block(const unsigned char *x)
const unsigned char *detailed;
printf("%s Revision %u\n", block.c_str(), version);
+ if (version == 0)
+ fail("Invalid CTA Extension revision 0\n");
+ if (version > 3)
+ warn("Unknown CTA Extension revision %u\n", version);
if (version >= 1) do {
if (version == 1 && x[3] != 0)
@@ -1825,7 +1845,7 @@ void edid_state::parse_cta_block(const unsigned char *x)
if (!(x[3] & 0x0f))
first_svd_might_be_preferred = true;
}
- if (version == 3) {
+ if (version >= 3) {
unsigned i;
printf("%u bytes of CTA data blocks\n", offset - 4);
@@ -1838,11 +1858,10 @@ void edid_state::parse_cta_block(const unsigned char *x)
}
seen_non_detailed_descriptor = false;
- timing_descr_cnt = 0;
for (detailed = x + offset; detailed + 18 < x + 127; detailed += 18) {
if (memchk(detailed, 18))
break;
- detailed_block(detailed, false);
+ detailed_block(detailed);
}
if (!memchk(detailed, x + 0x7f - detailed)) {
data_block = "Padding";
diff --git a/parse-displayid-block.cpp b/parse-displayid-block.cpp
index bc24098..e2a987d 100644
--- a/parse-displayid-block.cpp
+++ b/parse-displayid-block.cpp
@@ -302,7 +302,8 @@ void edid_state::parse_displayid_type_1_7_timing(const unsigned char *x, bool ty
if (x[3] & 0x80)
s += ", preferred";
- print_timings(" ", &t, type7 ? "Type VII" : "Type I", s.c_str());
+ dtd_cnt++;
+ print_timings(" ", &t, dtd_name().c_str(), s.c_str(), true);
}
// tag 0x04
@@ -358,7 +359,8 @@ void edid_state::parse_displayid_type_2_timing(const unsigned char *x)
if (x[3] & 0x80)
s += ", preferred";
- print_timings(" ", &t, "Type II", s.c_str());
+ dtd_cnt++;
+ print_timings(" ", &t, dtd_name().c_str(), s.c_str(), true);
}
// tag 0x05
@@ -1005,7 +1007,8 @@ void edid_state::parse_displayid_type_6_timing(const unsigned char *x)
if (x[2] & 0x80)
s += ", preferred";
- print_timings(" ", &t, "Type VI", s.c_str());
+ dtd_cnt++;
+ print_timings(" ", &t, dtd_name().c_str(), s.c_str(), true);
}
static std::string ieee7542d(unsigned short fp)
@@ -1375,6 +1378,7 @@ void edid_state::preparse_displayid_block(const unsigned char *x)
while (length > 0) {
unsigned tag = x[offset];
+ unsigned len = x[offset + 2];
switch (tag) {
case 0x02:
@@ -1383,6 +1387,19 @@ void edid_state::preparse_displayid_block(const unsigned char *x)
case 0x0e:
preparse_xfer_ids |= 1 << ((x[offset + 1] >> 4) & 0x0f);
break;
+ case 0x03:
+ preparse_total_dtds += len / 20;
+ break;
+ case 0x04:
+ preparse_total_dtds += len / 11;
+ break;
+ case 0x13:
+ for (unsigned i = 0; i < len; i += (x[offset + 3 + i + 2] & 0x40) ? 17 : 14)
+ preparse_total_dtds++;
+ break;
+ case 0x22:
+ preparse_total_dtds += len / 20;
+ break;
default:
break;
}
@@ -1390,8 +1407,6 @@ void edid_state::preparse_displayid_block(const unsigned char *x)
if (length < 3)
break;
- unsigned len = x[offset + 2];
-
if (length < len + 3)
break;

Privacy Policy