[mutter] edid: Parse CTA-861 EDID extension



commit d76f9e6c4a477875e8db69ba8a11857bf4974ffa
Author: Sebastian Wick <sebastian wick redhat com>
Date:   Fri Mar 18 20:02:32 2022 +0100

    edid: Parse CTA-861 EDID extension
    
    This adds support for E-EDID extensions. Tags are allocated by VESA and
    the CTA has such an extension defined in CTA-861.
    
    The switch in `decode_ext_cta` is empty in this commit because we don't
    parse any CTA-861 data blocks, yet.
    
    Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2351>

 src/backends/edid-parse.c | 109 ++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 101 insertions(+), 8 deletions(-)
---
diff --git a/src/backends/edid-parse.c b/src/backends/edid-parse.c
index 223553d39a..c3c3f0a94a 100644
--- a/src/backends/edid-parse.c
+++ b/src/backends/edid-parse.c
@@ -31,6 +31,20 @@
 
 #include "backends/edid.h"
 
+/* VESA E-EDID */
+#define EDID_BLOCK_LENGTH   128
+#define EDID_EXT_FLAG_ADDR  0x7E
+#define EDID_EXT_TAG_ADDR   0x00
+
+/* VESA reserved IDs for extension blocks */
+#define EDID_EXT_ID_CTA     0x02
+
+/* CTA-861 extension block */
+#define EDID_EXT_CTA_REVISION_ADDR                        0x01
+#define EDID_EXT_CTA_DESCRIPTOR_OFFSET_ADDR               0x02
+#define EDID_EXT_CTA_DATA_BLOCK_OFFSET                    0x04
+#define EDID_EXT_CTA_TAG_EXTENDED                         0x07
+
 static int
 get_bit (int in, int bit)
 {
@@ -45,6 +59,19 @@ get_bits (int in, int begin, int end)
   return (in >> begin) & mask;
 }
 
+static void
+decode_check_sum (const uint8_t *edid,
+                  MetaEdidInfo  *info)
+{
+  int i;
+  uint8_t check = 0;
+
+  for (i = 0; i < 128; ++i)
+    check += edid[i];
+
+  info->checksum = check;
+}
+
 static gboolean
 decode_header (const uint8_t *edid)
 {
@@ -527,17 +554,82 @@ decode_descriptors (const uint8_t *edid,
   return TRUE;
 }
 
-static void
-decode_check_sum (const uint8_t *edid,
-                 MetaEdidInfo  *info)
+static gboolean
+decode_ext_cta (const uint8_t *cta_block,
+                MetaEdidInfo  *info)
+{
+  const uint8_t *data_block;
+  uint8_t data_block_end;
+  uint8_t data_block_offset;
+  int size;
+  int tag;
+
+  /* The CTA extension block is a number of data blocks followed by a number
+   * of (timing) descriptors. We only parse the data blocks. */
+
+  /* CTA-861-H Table 58: CTA Extension Version 3 */
+  data_block_end = cta_block[EDID_EXT_CTA_DESCRIPTOR_OFFSET_ADDR];
+  data_block_offset = EDID_EXT_CTA_DATA_BLOCK_OFFSET;
+
+  /* Table 58:
+   * If d=0, then no detailed timing descriptors are provided, and no data is
+   * provided in the data block collection */
+  if (data_block_end == 0)
+    return TRUE;
+
+  /* Table 58:
+   * If no data is provided in the data block collection, then d=4 */
+  if (data_block_end == 4)
+    return TRUE;
+
+  if (data_block_end < 4)
+    return FALSE;
+
+  while (data_block_offset < data_block_end)
+    {
+      /* CTA-861-H 7.4: CTA Data Block Collection */
+      data_block = cta_block + data_block_offset;
+      size = get_bits (data_block[0], 0, 4) + 1;
+      tag = get_bits (data_block[0], 5, 7);
+
+      data_block_offset += size;
+
+      /* CTA Data Block extended tag type is the second byte */
+      if (tag == EDID_EXT_CTA_TAG_EXTENDED)
+        tag = (tag << 8) + data_block[1];
+
+      switch (tag)
+        {
+        }
+    }
+
+  return TRUE;
+}
+
+static gboolean
+decode_extensions (const uint8_t *edid,
+                   MetaEdidInfo  *info)
 {
+  int blocks;
   int i;
-  uint8_t check = 0;
+  const uint8_t *block = NULL;
 
-  for (i = 0; i < 128; ++i)
-    check += edid[i];
+  blocks = edid[EDID_EXT_FLAG_ADDR];
 
-  info->checksum = check;
+  for (i = 0; i < blocks; i++)
+    {
+      block = edid + EDID_BLOCK_LENGTH * (i + 1);
+
+      switch (block[EDID_EXT_TAG_ADDR])
+        {
+        case EDID_EXT_ID_CTA:
+          if (!decode_ext_cta (block, info))
+            return FALSE;
+          break;
+        }
+    }
+
+  return TRUE;
 }
 
 MetaEdidInfo *
@@ -556,7 +648,8 @@ meta_edid_info_new_parse (const uint8_t *edid)
       && decode_color_characteristics (edid, info)
       && decode_established_timings (edid, info)
       && decode_standard_timings (edid, info)
-      && decode_descriptors (edid, info))
+      && decode_descriptors (edid, info)
+      && decode_extensions (edid, info))
     {
       return info;
     }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]