The HDMI CEA vendor specific block has some interesting information, such as the maximum TMDS dot clock.
v2: Don't parse CEA blocks with invalid offsets, remove spurious brackets (Chris Wilson) v3: Fix the looping through the CEA data blocks, it had a typo using the wrong variable coming from the code it was ported from. Replace x << 16 + y << 8 + z by x << 16 | y << 8 | z (Chris Wilson) v4: Remove the stray ';' at the end of "if (*end == 0)". (Dominik Behr on IRC) Signed-off-by: Damien Lespiau <damien.lesp...@intel.com> --- hw/xfree86/ddc/interpret_edid.c | 91 +++++++++++++++++++++++++++++++++++++++++ hw/xfree86/ddc/xf86DDC.h | 2 + 2 files changed, 93 insertions(+) diff --git a/hw/xfree86/ddc/interpret_edid.c b/hw/xfree86/ddc/interpret_edid.c index e6b4d5b..71c605b 100644 --- a/hw/xfree86/ddc/interpret_edid.c +++ b/hw/xfree86/ddc/interpret_edid.c @@ -332,6 +332,97 @@ xf86ForEachVideoBlock(xf86MonPtr mon, handle_video_fn fn, void *data) } } +static Bool +cea_db_offsets(Uchar *cea, int *start, int *end) +{ + /* Data block offset in CEA extension block */ + *start = CEA_EXT_MIN_DATA_OFFSET; + *end = cea[2]; + if (*end == 0) + *end = CEA_EXT_MAX_DATA_OFFSET; + if (*end < CEA_EXT_MIN_DATA_OFFSET || *end > CEA_EXT_MAX_DATA_OFFSET) + return FALSE; + return TRUE; +} + +static int +cea_db_len(Uchar *db) +{ + return db[0] & 0x1f; +} + +static int +cea_db_tag(Uchar *db) +{ + return db[0] >> 5; +} + +typedef void (*handle_cea_db_fn) (Uchar *, void *); + +static void +cea_for_each_db(xf86MonPtr mon, handle_cea_db_fn fn, void *data) +{ + int i; + + if (!mon) + return; + + if (!(mon->flags & EDID_COMPLETE_RAWDATA)) + return; + + if (!mon->no_sections) + return; + + if (!mon->rawData) + return; + + for (i = 0; i < mon->no_sections; i++) { + int start, end, offset; + Uchar *ext; + + ext = mon->rawData + EDID1_LEN * (i + 1); + if (ext[EXT_TAG] != CEA_EXT) + continue; + + if (!cea_db_offsets(ext, &start, &end)) + continue; + + for (offset = start; + offset < end && offset + cea_db_len(&ext[offset]) < end; + offset += cea_db_len(&ext[offset]) + 1) + fn(&ext[offset], data); + } +} + +struct find_hdmi_block_data { + struct cea_data_block *hdmi; +}; + +static void find_hdmi_block(Uchar *db, void *data) +{ + struct find_hdmi_block_data *result = data; + int oui; + + if (cea_db_tag(db) != CEA_VENDOR_BLK) + return; + + if (cea_db_len(db) < 5) + return; + + oui = (db[3] << 16) | (db[2] << 8) | db[1]; + if (oui == IEEE_ID_HDMI) + result->hdmi = (struct cea_data_block *)db; +} + +struct cea_data_block *xf86MonitorFindHDMIBlock(xf86MonPtr mon) +{ + struct find_hdmi_block_data result = { NULL }; + + cea_for_each_db(mon, find_hdmi_block, &result); + + return result.hdmi; +} + xf86MonPtr xf86InterpretEEDID(int scrnIndex, Uchar * block) { diff --git a/hw/xfree86/ddc/xf86DDC.h b/hw/xfree86/ddc/xf86DDC.h index bdc7648..de8e718 100644 --- a/hw/xfree86/ddc/xf86DDC.h +++ b/hw/xfree86/ddc/xf86DDC.h @@ -98,4 +98,6 @@ typedef void (*handle_video_fn) (struct cea_video_block *, void *); void xf86ForEachVideoBlock(xf86MonPtr, handle_video_fn, void *); +struct cea_data_block *xf86MonitorFindHDMIBlock(xf86MonPtr mon); + #endif -- 1.8.3.1 _______________________________________________ xorg-devel@lists.x.org: X.Org development Archives: http://lists.x.org/archives/xorg-devel Info: http://lists.x.org/mailman/listinfo/xorg-devel