]> mj.ucw.cz Git - edid.git/commitdiff
Updated to EDID v1.4
authorMartin Mares <mj@ucw.cz>
Sat, 7 Nov 2015 21:15:13 +0000 (22:15 +0100)
committerMartin Mares <mj@ucw.cz>
Sat, 7 Nov 2015 21:15:13 +0000 (22:15 +0100)
Some parts are not fully decoded yet.

Makefile [new file with mode: 0644]
edid.c

diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..f2f96c9
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,8 @@
+CC=gcc
+LD=gcc
+CFLAGS=-O2 -Wall -W -Wno-parentheses -Wstrict-prototypes -Wmissing-prototypes -Wundef -Wredundant-decls -std=gnu99
+
+all: edid
+
+clean:
+       rm -f *.o edid
diff --git a/edid.c b/edid.c
index d6972d15973ac2056a0bbc0cb07b82d1cc65db61..d781536dadce8121442752195b772d3366d01149 100644 (file)
--- a/edid.c
+++ b/edid.c
@@ -1,7 +1,7 @@
 /*
  *     Parse VESA Extended Display Identification Data
  *
- *     (c) 2011 Martin Mares <mj@ucw.cz>
+ *     (c) 2011--2015 Martin Mares <mj@ucw.cz>
  *
  *     This program can be distributed and used under the terms
  *     of the GNU General Public License version 2 or later.
@@ -18,6 +18,8 @@ typedef unsigned char byte;
 
 static byte edid[128];
 static int version;
+static uns block;
+static uns num_ext_blocks;
 
 static void
 #ifdef __GNUC__
@@ -62,7 +64,14 @@ show_model(byte *p)
        ('A' - 1 + (p[1] & 0x1f)),
        u16_le(p+2),
        u32_le(p+4));
-  printf("Manufactured: %d week %d\n", p[9] + 1990, p[8]);
+
+  uns y = p[9] + 1990;
+  if (p[8] == 0xff)
+    printf("Model year: %d\n", y);
+  else if (p[8])
+    printf("Manufactured: %d week %d\n", y, p[8]);
+  else
+    printf("Manufactured: %d, week unspecified\n", y);
 }
 
 static void
@@ -70,9 +79,26 @@ show_basic(byte *p)
 {
   uns input = p[0];
   if (input & 0x80)
-    printf("Input: Digital DFP%c\n", B(input & 1));
+    {
+      printf("Input: Digital,");
+      if (version < 0x104)
+       printf(" DFP%c\n", B(input & 1));
+      else
+       {
+         uns depth = (input >> 4) & 7;
+         static const char * const depths[] = { "undefined", "6", "8", "10", "12", "14", "16", "RFU7" };
+
+         uns iface = input & 0x0f;
+         static const char * const ifaces[] = {
+           "undefined", "DVI", "HDMI-a", "HDMI-b", "MDDI", "DisplayPort", "RFU6", "RFU7",
+           "RFU8", "RFU9", "RFU10", "RFU11", "RFU12", "RFU13", "RFU14", "RFU16"
+         };
+
+         printf(" Depth=%s Iface=%s\n", depths[depth], ifaces[iface]);
+       }
+    }
   else
-    printf("Input: Analog SigLev=%d Setup%c SepSync%c CompSync%c GreenSync%c SerrSync%c\n",
+    printf("Input: Analog, SigLev=%d Setup%c SepSync%c CompSync%c GreenSync%c SerrSync%c\n",
        ((input >> 5) & 3),
        B(input & 0x10),
        B(input & 0x08),
@@ -80,22 +106,39 @@ show_basic(byte *p)
        B(input & 0x02),
        B(input & 0x01));
 
-  printf("Image size: %dx%dcm\n", p[1], p[2]);
+  if (!p[1] && !p[2])
+    printf("Image size: undefined\n");
+  else if (!p[2])
+    printf("Image aspect ratio: %u.%02u:1\n", 1 + p[1]/100, p[1] % 100);
+  else if (!p[1])
+    printf("Image aspect ratio: 1:%u.%02u\n", 1 + p[2]/100, p[2] % 100);
+  else
+    printf("Image size: %dx%dcm\n", p[1], p[2]);
+
   if (p[3] == 0xff)
     printf("Gamma: not given\n");
   else
-    printf("Gamma: %d.%02d\n", (p[3] / 100) + 1, p[3] % 100);
+    printf("Gamma: %d.%02d\n", 1 + p[3]/100, p[3] % 100);
 
   uns flags = p[4];
-  static const char * const types[4] = { "Mono/Gray", "RGB", "NonRGB", "Unknown" };
-  printf("Flags: Suspend%c Standby%c ActiveOff%c Colors=%s HasSRGB%c PrefTiming%c GTF%c\n",
+  static const char * const color_types[4] = { "Mono/Gray", "RGB", "NonRGB", "Unknown" };
+  static const char * const color_encodings[4] = {
+    "RGB444",
+    "RGB444/YCrCb444",
+    "RGB444/YCrCb422",
+    "RGB444/YCrCb444/YCrCb422",
+  };
+  printf("Flags: Suspend%c Standby%c ActiveOff%c",
        B(flags & 0x80),
        B(flags & 0x40),
-       B(flags & 0x20),
-       types[(flags >> 3) & 3],
-       B(flags & 0x04),
-       B(flags & 0x02),
-       B(flags & 0x01));
+       B(flags & 0x20));
+  if (version >= 0x104 && (input & 0x80))
+    printf(" Colors=%s", color_encodings[(flags >> 3) & 3]);
+  else
+    printf(" Colors=%s", color_types[(flags >> 3) & 3]);
+  printf(" HasSRGB%c", B(flags & 0x04));
+  printf(" %s%c", (version >= 0x104 ? "PreferredIsNative" : "PrefTiming"), B(flags & 0x02));
+  printf(" %s%c\n", (version >= 0x104 ? "ContinuousFreq" : "GTF"), B(flags & 0x01));
 }
 
 static void
@@ -135,7 +178,7 @@ show_timings(byte *p)
        "1024x768@70",
        "1024x768@75",
        "1280x1024@75",
-       "MFG7",
+       "1152x870@75",
        "MFG6",
        "MFG5",
        "MFG4",
@@ -150,7 +193,7 @@ show_timings(byte *p)
       printf(" %s", estab_timings[i]);
   printf("\n");
 
-  printf("Extended timings:");
+  printf("Standard timings:");
   for (int i=0; i<8; i++)
     {
       byte *q = p + 3 + 2*i;
@@ -209,20 +252,32 @@ show_detailed_timing(byte *p)
 
   uns flags = p[17];
   uns stereo = ((flags >> 4) & 6) | (flags & 1);
-  uns input = (flags >> 3) & 3;
+  static const char * const stereo_types[8] = {
+    "none",
+    "none",
+    "FieldSeq/RightOn1",
+    "2-wayIL/RightEven",
+    "FieldSeq/LeftOn1",
+    "2-wayIL/LeftEven",
+    "4-wayIL",
+    "SideBySide",
+  };
+  printf("\tFlags: Interlace%c Stereo=%s\n", B(flags & 0x80), stereo_types[stereo]);
   if (stereo >= 2)
     printf("\tStereo mode: #%d\n", stereo);
 
-  static const char * const input_types[4] = { "AnalogComposite", "BipolarAnalogComposite", "DigitalComposite", "DigitalSeparate" };
-  printf("\tInput: %s", input_types[input]);
-  if (input < 3)
+  uns sync = (flags >> 3) & 3;
+
+  static const char * const sync_types[4] = { "AnalogComposite", "BipolarAnalogComposite", "DigitalComposite", "DigitalSeparate" };
+  printf("\tSync: %s", sync_types[sync]);
+  if (sync < 3)
     printf(" Serrate%c", B(flags & 4));
   else
     printf(" VPolarity%c", B(flags & 4));
-  if (input < 2)
+  if (sync < 2)
     printf(" OnRGB%c", B(flags & 2));
-  else if (input == 2)
-    printf(" CompPolarity%c", B(flags & 2));
+  else if (sync == 2)
+    printf(" Polarity%c", B(flags & 2));
   else
     printf(" HPolarity%c", B(flags & 2));
   printf("\n");
@@ -250,6 +305,42 @@ show_ascii(char *field, byte *p, uns len)
   putchar('\n');
 }
 
+static void
+show_limits(byte *p)
+{
+  uns flags = p[4];
+  uns voffset = flags & 3;
+  uns hoffset = (flags >> 2) & 3;
+
+  printf("Limits: Vert=%d-%dHz Horiz=%d-%dkHz PixClk=%dMHz",
+    p[5] + (voffset == 3 ? 255 : 0),
+    p[6] + (voffset & 2 ? 255 : 0),
+    p[7] + (hoffset == 3 ? 255 : 0),
+    p[8] + (hoffset & 2 ? 255 : 0),
+    p[9]*10);
+
+  switch (p[10])
+    {
+    case 0:            // No secondary timing formula
+      printf(" (no formula)\n");
+      break;
+    case 1:            // Range limits only
+      printf(" (range only)\n");
+      break;
+    case 2:            // Secondary GTF
+      printf(" (2ndary GTF)\n");
+      printf("\tSecondary GTF parameters: fStart=%dkHz C=%.1f M=%d K=%d J=%.1f\n",
+       p[12]*2, p[13]/2., u16_le(p+14), p[16], p[17]/2.);
+      break;
+    case 4:
+      printf(" (CVT v%d.%d)\n", p[11] >> 4, p[11] & 0x0f);
+      printf("\t[...]\n");
+      break;
+    default:
+      printf(" (unknown formula #%02x)\n", p[10]);
+    }
+}
+
 static void
 show_descriptor(byte *p)
 {
@@ -262,22 +353,10 @@ show_descriptor(byte *p)
       show_ascii("Comment", p+5, 13);
       break;
     case 0xfd:         // Range limits
-      printf("Limits: Vert=%d-%dHz Horiz=%d-%dkHz PixClk=%dMHz\n",
-       p[5], p[6], p[7], p[8], p[9]*10);
-      switch (p[10])
-       {
-       case 0:         // No secondary timing formula
-         break;
-       case 2:         // Secondary GTF
-         printf("Secondary GTF parameters: fStart=%dkHz C=%.1f M=%d K=%d J=%.1f\n",
-           p[12]*2, p[13]/2., u16_le(p+14), p[16], p[17]/2.);
-         break;
-       default:
-         printf("Unidentified secondary timing formula #%02x\n", p[10]);
-       }
+      show_limits(p);
       break;
-    case 0xfc:         // Monitor name
-      show_ascii("Monitor name", p+5, 13);
+    case 0xfc:         // Product name
+      show_ascii("Product name", p+5, 13);
       break;
     case 0xfb:         // Color point
       printf("Color point: [...]\n");
@@ -285,13 +364,32 @@ show_descriptor(byte *p)
     case 0xfa:         // More standard timings
       printf("More standard timings: [...]\n");
       break;
+    case 0xf9:
+      printf("Display color management: [...]\n");
+      break;
+    case 0xf8:
+      printf("CVT-3: [...]\n");
+      break;
+    case 0xf7:
+      printf("Established timings 3: [...]\n");
+      break;
     case 0x10:         // Dummy descriptor -- entry unused
       return;
     default:
-      printf("Unknown descriptor type %02x\n", p[3]);
+      printf("%s descriptor type %02x\n", (p[3] <= 0x0f ? "Vendor-specific" : "Unknown"), p[3]);
     }
 }
 
+static void
+check_sum(void)
+{
+  byte sum = 0;
+  for (int i=0; i<128; i++)
+    sum += edid[i];
+  if (sum)
+    printf("Invalid checksum: off by %02x\n", sum);
+}
+
 static void
 show_edid(void)
 {
@@ -302,11 +400,9 @@ show_edid(void)
   printf("EDID %d.%d\n", ver, rev);
   version = (ver << 8) | rev;
 
-  byte sum = 0;
-  for (int i=0; i<128; i++)
-    sum += edid[i];
-  if (sum)
-    printf("Invalid checksum: off by %02x\n", sum);
+  if (version >= 0x200)
+    die("Unsupported version");
+  check_sum();
 
   show_model(edid + 8);
   show_basic(edid + 0x14);
@@ -321,8 +417,51 @@ show_edid(void)
        show_descriptor(p);
     }
 
-  if (edid[0x7e])
-    printf("### %d extension blocks follow, but they are not supported yet ###\n", edid[0x7e]);
+  num_ext_blocks = edid[0x7e];
+}
+
+static void ext_block_map(void)
+{
+  for (uns i=1; i<=0xfe; i++)
+    if (edid[i])
+      printf("Block %u: extension %u\n", i, edid[i]);
+}
+
+struct extension {
+  const char *name;
+  void (*parser)(void);
+};
+
+static const struct extension ext_table[0x100] = {
+  [0x02] = { "CEA 861",                                NULL },
+  [0x10] = { "Video Timing Block",             NULL },
+  [0x40] = { "Display Information",            NULL },
+  [0x50] = { "Localized Strings",              NULL },
+  [0x60] = { "Digital Packet Video Link",      NULL },
+  [0xf0] = { "Block map",                      ext_block_map },
+  [0xff] = { "Vendor-specific",                        NULL },
+};
+
+static void show_ext(void)
+{
+  byte ext = edid[0];
+  const struct extension *e = &ext_table[ext];
+
+  printf("\n>> Extension block %u: ", block);
+  if (e->name)
+    printf("%s", e->name);
+  else
+    printf("Extension #%02x", ext);
+  if (ext != 0xf0)
+    printf(" (version %02x)", edid[1]);
+  printf("\n\n");
+
+  check_sum();
+
+  if (e->parser)
+    e->parser();
+  else
+    printf("!!! Not decoded yet\n");
 }
 
 static void read_binary(void)
@@ -338,7 +477,7 @@ static void
 read_xorg_log(void)
 {
   char line[1024];
-  int mode = 0;
+  static int mode = 0;
   int cnt = 0;
 
   while (fgets(line, sizeof(line), stdin))
@@ -432,14 +571,22 @@ int main(int argc, char **argv)
   if (optind < argc)
     usage();
 
-  if (log_mode)
-    read_xorg_log();
-  else
-    read_binary();
+  while (block <= num_ext_blocks)
+    {
+      if (log_mode)
+       read_xorg_log();
+      else
+       read_binary();
+
+      if (!block)
+       show_edid();
+      else
+       show_ext();
 
-  show_edid();
+      if (hex_mode)
+       show_hex();
+      block++;
+    }
 
-  if (hex_mode)
-    show_hex();
   return 0;
 }