[PATCH] xfree86: Add a xf86MonitorFindHDMIBlock()

Damien Lespiau damien.lespiau at intel.com
Mon Dec 16 14:33:36 PST 2013


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.lespiau at 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



More information about the xorg-devel mailing list