xserver: Branch 'master' - 6 commits

Keith Packard keithp at kemper.freedesktop.org
Thu Oct 29 12:15:34 PDT 2009


 hw/xfree86/common/xf86Configure.c |   56 ++--
 hw/xfree86/common/xf86Mode.c      |   29 +-
 hw/xfree86/ddc/edid.h             |   97 ++++++++
 hw/xfree86/ddc/interpret_edid.c   |  375 +++++++++++++++++++++++---------
 hw/xfree86/ddc/print_edid.c       |  264 ++++++++++++----------
 hw/xfree86/ddc/xf86DDC.h          |   50 ++++
 hw/xfree86/modes/xf86Crtc.c       |  164 +++++++-------
 hw/xfree86/modes/xf86EdidModes.c  |  442 +++++++++++++++++++++++++-------------
 hw/xfree86/modes/xf86Modes.c      |   42 +++
 hw/xfree86/modes/xf86Modes.h      |    3 
 10 files changed, 1037 insertions(+), 485 deletions(-)

New commits:
commit ec98d7fc78efefcf9fc61492529157c0d289c3f2
Author: Adam Jackson <ajax at redhat.com>
Date:   Mon Sep 21 10:23:16 2009 -0400

    EDID: Extend the HDTV hack to handle "1368x769"
    
    Hate televisions so much.
    
    Signed-off-by: Adam Jackson <ajax at redhat.com>

diff --git a/hw/xfree86/modes/xf86EdidModes.c b/hw/xfree86/modes/xf86EdidModes.c
index 15021a8..449078e 100644
--- a/hw/xfree86/modes/xf86EdidModes.c
+++ b/hw/xfree86/modes/xf86EdidModes.c
@@ -473,8 +473,10 @@ DDCModesFromStandardTiming(struct std_timings *timing, ddc_quirk_t quirks,
 	vsize = timing[i].vsize;
 	refresh = timing[i].refresh;
 
-	/* HDTV hack.  Hooray. */
-	if (hsize == 1360 && vsize == 765 && refresh == 60) {
+	/* HDTV hack, because you can't say 1366 */
+	if (refresh == 60 &&
+	    ((hsize == 1360 && vsize == 765) ||
+	     (hsize == 1368 && vsize == 769))) {
 	    Mode = xf86CVTMode(1366, 768, 60, FALSE, FALSE);
 	    Mode->HDisplay = 1366;
 	    Mode->VSyncStart--;
commit 7c0803f555782dbf451b7c79112d7deae02e5c9f
Author: Adam Jackson <ajax at redhat.com>
Date:   Wed Oct 28 15:44:37 2009 -0400

    modes: Fix duplicate detection, and do it more consistently
    
    Signed-off-by: Adam Jackson <ajax at redhat.com>

diff --git a/hw/xfree86/modes/xf86Crtc.c b/hw/xfree86/modes/xf86Crtc.c
index 138adc0..fad50a2 100644
--- a/hw/xfree86/modes/xf86Crtc.c
+++ b/hw/xfree86/modes/xf86Crtc.c
@@ -1377,34 +1377,6 @@ xf86InitialPanning (ScrnInfoPtr scrn)
     }
 }
 
-/*
- * XXX walk the monitor mode list and prune out duplicates that
- * are inserted by xf86DDCMonitorSet. In an ideal world, that
- * function would do this work by itself.
- */
-
-static void
-xf86PruneDuplicateMonitorModes (MonPtr Monitor)
-{
-    DisplayModePtr  master, clone, next;
-
-    for (master = Monitor->Modes; 
-	 master && master != Monitor->Last; 
-	 master = master->next)
-    {
-	for (clone = master->next; clone && clone != Monitor->Modes; clone = next)
-	{
-	    next = clone->next;
-	    if (xf86ModesEqual (master, clone))
-	    {
-		if (Monitor->Last == clone)
-		    Monitor->Last = clone->prev;
-		xf86DeleteMode (&Monitor->Modes, clone);
-	    }
-	}
-    }
-}
-
 /** Return - 0 + if a should be earlier, same or later than b in list
  */
 static int
@@ -1575,9 +1547,6 @@ xf86ProbeOutputModes (ScrnInfoPtr scrn, int maxX, int maxY)
 	maxY = config->maxHeight;
     }
 
-    /* Elide duplicate modes before defaulting code uses them */
-    xf86PruneDuplicateMonitorModes (scrn->monitor);
-    
     /* Probe the list of modes for each output. */
     for (o = 0; o < config->num_output; o++) 
     {
diff --git a/hw/xfree86/modes/xf86EdidModes.c b/hw/xfree86/modes/xf86EdidModes.c
index 23d6416..15021a8 100644
--- a/hw/xfree86/modes/xf86EdidModes.c
+++ b/hw/xfree86/modes/xf86EdidModes.c
@@ -1082,6 +1082,8 @@ xf86DDCGetModes(int scrnIndex, xf86MonPtr DDC)
     if (quirks & DDC_QUIRK_PREFER_LARGE_75)
 	xf86DDCSetPreferredRefresh(scrnIndex, Modes, 75);
 
+    Modes = xf86PruneDuplicateModes(Modes);
+
     return Modes;
 }
 
diff --git a/hw/xfree86/modes/xf86Modes.c b/hw/xfree86/modes/xf86Modes.c
index ae6d956..75aedaa 100644
--- a/hw/xfree86/modes/xf86Modes.c
+++ b/hw/xfree86/modes/xf86Modes.c
@@ -691,3 +691,37 @@ xf86GetDefaultModes (void)
     }
     return head;
 }
+
+/*
+ * Walk a mode list and prune out duplicates.  Will preserve the preferred
+ * mode of an otherwise-duplicate pair.
+ *
+ * Probably best to call this on lists that are all of a single class
+ * (driver, default, user, etc.), otherwise, which mode gets deleted is
+ * not especially well defined.
+ *
+ * Returns the new list.
+ */
+
+DisplayModePtr
+xf86PruneDuplicateModes(DisplayModePtr modes)
+{
+    DisplayModePtr m, n, o;
+
+top:
+    for (m = modes; m; m = m->next) {
+	for (n = m->next; n; n = o) {
+	    o = n->next;
+	    if (xf86ModesEqual(m, n)) {
+		if (n->type & M_T_PREFERRED) {
+		    xf86DeleteMode(&modes, m);
+		    goto top;
+		}
+		else
+		    xf86DeleteMode(&modes, n);
+	    }
+	}
+    }
+
+    return modes;
+}
diff --git a/hw/xfree86/modes/xf86Modes.h b/hw/xfree86/modes/xf86Modes.h
index 908f59b..38927b1 100644
--- a/hw/xfree86/modes/xf86Modes.h
+++ b/hw/xfree86/modes/xf86Modes.h
@@ -95,6 +95,9 @@ extern _X_EXPORT void
 xf86PruneInvalidModes(ScrnInfoPtr pScrn, DisplayModePtr *modeList,
 		      Bool verbose);
 
+extern _X_EXPORT DisplayModePtr
+xf86PruneDuplicateModes(DisplayModePtr modes);
+
 extern _X_EXPORT void
 xf86ValidateModesFlags(ScrnInfoPtr pScrn, DisplayModePtr modeList,
 		       int flags);
commit ba2d39dd5428cb5922b797a1d4ea45b859412b40
Author: Adam Jackson <ajax at redhat.com>
Date:   Mon Oct 26 15:10:30 2009 -0400

    modes: De-duplicate a clock range check.
    
    Signed-off-by: Adam Jackson <ajax at redhat.com>

diff --git a/hw/xfree86/common/xf86Mode.c b/hw/xfree86/common/xf86Mode.c
index 0e43946..4a948d7 100644
--- a/hw/xfree86/common/xf86Mode.c
+++ b/hw/xfree86/common/xf86Mode.c
@@ -249,6 +249,15 @@ xf86ShowClockRanges(ScrnInfoPtr scrp, ClockRangePtr clockRanges)
     }
 }
 
+static Bool
+modeInClockRange(ClockRangePtr cp, DisplayModePtr p)
+{
+    return ((p->Clock >= cp->minClock) &&
+	    (p->Clock <= cp->maxClock) &&
+	    (cp->interlaceAllowed || !(p->Flags & V_INTERLACE)) &&
+	    (cp->doubleScanAllowed ||
+	     ((p->VScan <= 1) && !(p->Flags & V_DBLSCAN))));
+}
 
 /*
  * xf86FindClockRangeForMode()    [... like the name says ...]
@@ -259,12 +268,7 @@ xf86FindClockRangeForMode(ClockRangePtr clockRanges, DisplayModePtr p)
     ClockRangePtr cp;
 
     for (cp = clockRanges; ; cp = cp->next)
-	if (!cp ||
-	    ((p->Clock >= cp->minClock) &&
-	     (p->Clock <= cp->maxClock) &&
-	     (cp->interlaceAllowed || !(p->Flags & V_INTERLACE)) &&
-	     (cp->doubleScanAllowed ||
-	      ((p->VScan <= 1) && !(p->Flags & V_DBLSCAN)))))
+	if (!cp || modeInClockRange(cp, p))
 	    return cp;
 }
 
@@ -979,11 +983,7 @@ xf86CheckModeForDriver(ScrnInfoPtr scrp, DisplayModePtr mode, int flags)
     if (scrp->progClock) {
 	/* Check clock is in range */
 	for (cp = scrp->clockRanges; cp != NULL; cp = cp->next) {
-	    if ((cp->minClock <= mode->Clock) &&
-		(cp->maxClock >= mode->Clock) &&
-		(cp->interlaceAllowed || !(mode->Flags & V_INTERLACE)) &&
-		(cp->doubleScanAllowed ||
-		 ((!(mode->Flags & V_DBLSCAN)) && (mode->VScan <= 1))))
+	    if (modeInClockRange(cp, mode))
 	        break;
 	}
 	if (cp == NULL) {
@@ -999,12 +999,7 @@ xf86CheckModeForDriver(ScrnInfoPtr scrp, DisplayModePtr mode, int flags)
 	 status = MODE_CLOCK_RANGE;
 	/* Check clock is in range */
 	for (cp = scrp->clockRanges; cp != NULL; cp = cp->next) {
-	    if ((cp->minClock <= mode->Clock) &&
-		(cp->maxClock >= mode->Clock) &&
-		(cp->interlaceAllowed || !(mode->Flags & V_INTERLACE)) &&
-		(cp->doubleScanAllowed ||
-		 ((!(mode->Flags & V_DBLSCAN)) && (mode->VScan <= 1)))) {
-
+	    if (modeInClockRange(cp, mode)) {
 		/*
 	 	 * Clock is in range, so if it is not a programmable clock,
 		 * find a matching clock.
commit 25236d19e6ef07fcb2c71569f1b7b0c12810834a
Author: Adam Jackson <ajax at redhat.com>
Date:   Mon Oct 26 14:49:57 2009 -0400

    EDID: Fix interlaced detailed timings to be frame size, not field size
    
    Signed-off-by: Adam Jackson <ajax at redhat.com>

diff --git a/hw/xfree86/modes/xf86EdidModes.c b/hw/xfree86/modes/xf86EdidModes.c
index 6fef1e0..23d6416 100644
--- a/hw/xfree86/modes/xf86EdidModes.c
+++ b/hw/xfree86/modes/xf86EdidModes.c
@@ -502,6 +502,45 @@ DDCModesFromStandardTiming(struct std_timings *timing, ddc_quirk_t quirks,
     return Modes;
 }
 
+static void
+DDCModeDoInterlaceQuirks(DisplayModePtr mode)
+{
+    /*
+     * EDID is delightfully ambiguous about how interlaced modes are to be
+     * encoded.  X's internal representation is of frame height, but some
+     * HDTV detailed timings are encoded as field height.
+     *
+     * The format list here is from CEA, in frame size.  Technically we
+     * should be checking refresh rate too.  Whatever.
+     */
+    static const struct {
+	int w, h;
+    } cea_interlaced[] = {
+	{ 1920, 1080 },
+	{  720,  480 },
+	{ 1440,  480 },
+	{ 2880,  480 },
+	{  720,  576 },
+	{ 1440,  576 },
+	{ 2880,  576 },
+    };
+    static const int n_modes = sizeof(cea_interlaced)/sizeof(cea_interlaced[0]);
+    int i;
+
+    for (i = 0; i < n_modes; i++) {
+	if ((mode->HDisplay == cea_interlaced[i].w) &&
+	    (mode->VDisplay == cea_interlaced[i].h / 2)) {
+	    mode->VDisplay *= 2;
+	    mode->VSyncStart *= 2;
+	    mode->VSyncEnd *= 2;
+	    mode->VTotal *= 2;
+	    mode->VTotal |= 1;
+	}
+    }
+
+    mode->Flags |= V_INTERLACE;
+}
+
 /*
  *
  */
@@ -569,7 +608,7 @@ DDCModeFromDetailedTiming(int scrnIndex, struct detailed_timings *timing,
     /* We ignore h/v_size and h/v_border for now. */
 
     if (timing->interlaced)
-        Mode->Flags |= V_INTERLACE;
+	DDCModeDoInterlaceQuirks(Mode);
 
     if (quirks & DDC_QUIRK_DETAILED_SYNC_PP)
 	Mode->Flags |= V_PVSYNC | V_PHSYNC;
commit fb86433d897c116315cc7994390d11ac2f577511
Author: Adam Jackson <ajax at redhat.com>
Date:   Mon Oct 26 14:04:23 2009 -0400

    modes: Decorate interlaced mode names with a trailing 'i'
    
    Signed-off-by: Adam Jackson <ajax at redhat.com>

diff --git a/hw/xfree86/modes/xf86EdidModes.c b/hw/xfree86/modes/xf86EdidModes.c
index 8885a7c..6fef1e0 100644
--- a/hw/xfree86/modes/xf86EdidModes.c
+++ b/hw/xfree86/modes/xf86EdidModes.c
@@ -566,8 +566,6 @@ DDCModeFromDetailedTiming(int scrnIndex, struct detailed_timings *timing,
 	return NULL;
     }
 
-    xf86SetModeDefaultName(Mode);
-
     /* We ignore h/v_size and h/v_border for now. */
 
     if (timing->interlaced)
@@ -587,6 +585,8 @@ DDCModeFromDetailedTiming(int scrnIndex, struct detailed_timings *timing,
 	    Mode->Flags |= V_NHSYNC;
     }
 
+    xf86SetModeDefaultName(Mode);
+
     return Mode;
 }
 
diff --git a/hw/xfree86/modes/xf86Modes.c b/hw/xfree86/modes/xf86Modes.c
index d105b48..ae6d956 100644
--- a/hw/xfree86/modes/xf86Modes.c
+++ b/hw/xfree86/modes/xf86Modes.c
@@ -136,10 +136,12 @@ xf86ModeBandwidth(DisplayModePtr mode, int depth)
 void
 xf86SetModeDefaultName(DisplayModePtr mode)
 {
-    if (mode->name != NULL)
-	xfree(mode->name);
+    Bool interlaced = !!(mode->Flags & V_INTERLACE);
 
-    mode->name = XNFprintf("%dx%d", mode->HDisplay, mode->VDisplay);
+    xfree(mode->name);
+
+    mode->name = XNFprintf("%dx%d%s", mode->HDisplay, mode->VDisplay,
+			   interlaced ? "i" : "");
 }
 
 /*
commit fc2ec95664d55f45f77f1ebb039a7c17a1fcdaa3
Author: Ma Ling <ling.ma at intel.com>
Date:   Wed Feb 18 17:41:26 2009 +0800

    EDID: CEA extension support
    
    Reviewed-by: Adam Jackson <ajax at redhat.com>

diff --git a/hw/xfree86/common/xf86Configure.c b/hw/xfree86/common/xf86Configure.c
index 3b7828a..2df6b4e 100644
--- a/hw/xfree86/common/xf86Configure.c
+++ b/hw/xfree86/common/xf86Configure.c
@@ -544,6 +544,36 @@ configureMonitorSection (int screennum)
     return ptr;
 }
 
+/* Initialize Configure Monitor from Detailed Timing Block */
+static void handle_detailed_input(struct detailed_monitor_section *det_mon,
+                                  void *data)
+{
+    XF86ConfMonitorPtr ptr = (XF86ConfMonitorPtr) data;
+
+    switch (det_mon->type) {
+    case DS_NAME:
+        ptr->mon_modelname = realloc(ptr->mon_modelname,
+                                     strlen((char*)(det_mon->section.name)) +
+                                     1);
+        strcpy(ptr->mon_modelname,
+	      (char*)(det_mon->section.name));
+        break;
+    case DS_RANGES:
+        ptr->mon_hsync[ptr->mon_n_hsync].lo =
+            det_mon->section.ranges.min_h;
+        ptr->mon_hsync[ptr->mon_n_hsync].hi =
+            det_mon->section.ranges.max_h;
+        ptr->mon_n_vrefresh = 1;
+        ptr->mon_vrefresh[ptr->mon_n_hsync].lo =
+            det_mon->section.ranges.min_v;
+        ptr->mon_vrefresh[ptr->mon_n_hsync].hi =
+            det_mon->section.ranges.max_v;
+        ptr->mon_n_hsync++;
+    default:
+        break;
+    }
+}
+
 static XF86ConfMonitorPtr
 configureDDCMonitorSection (int screennum)
 {
@@ -590,30 +620,8 @@ configureDDCMonitorSection (int screennum)
     }
 #endif /* def CONFIGURE_DISPLAYSIZE */
 
-    for (i=0;i<4;i++) {
-	switch (ConfiguredMonitor->det_mon[i].type) {
-	    case DS_NAME:
-		ptr->mon_modelname  = realloc(ptr->mon_modelname, 
-		  strlen((char*)(ConfiguredMonitor->det_mon[i].section.name))
-		    + 1);
-		strcpy(ptr->mon_modelname,
-		       (char*)(ConfiguredMonitor->det_mon[i].section.name));
-		break;
-	    case DS_RANGES:
-		ptr->mon_hsync[ptr->mon_n_hsync].lo =
-		    ConfiguredMonitor->det_mon[i].section.ranges.min_h;
-		ptr->mon_hsync[ptr->mon_n_hsync].hi =
-		    ConfiguredMonitor->det_mon[i].section.ranges.max_h;
-		ptr->mon_n_vrefresh = 1;
-		ptr->mon_vrefresh[ptr->mon_n_hsync].lo =
-		    ConfiguredMonitor->det_mon[i].section.ranges.min_v;
-		ptr->mon_vrefresh[ptr->mon_n_hsync].hi =
-		    ConfiguredMonitor->det_mon[i].section.ranges.max_v;
-		ptr->mon_n_hsync++;
-	    default:
-		break;
-	}
-    }
+    xf86ForEachDetailedBlock(ConfiguredMonitor, handle_detailed_input,
+                             ptr);
 
     if (ConfiguredMonitor->features.dpms) {
       ptr->mon_option_lst = xf86addNewOption(ptr->mon_option_lst, xstrdup("DPMS"), NULL);
diff --git a/hw/xfree86/ddc/edid.h b/hw/xfree86/ddc/edid.h
index 3feb979..cc4bd02 100644
--- a/hw/xfree86/ddc/edid.h
+++ b/hw/xfree86/ddc/edid.h
@@ -562,4 +562,101 @@ typedef struct {
 
 extern _X_EXPORT xf86MonPtr ConfiguredMonitor;
 
+#define EXT_TAG 0
+#define EXT_REV 1
+#define CEA_EXT   0x02
+#define VTB_EXT   0x10
+#define DI_EXT    0x40
+#define LS_EXT    0x50
+#define MI_EXT    0x60
+
+#define CEA_EXT_MIN_DATA_OFFSET 4
+#define CEA_EXT_MAX_DATA_OFFSET 127
+#define CEA_EXT_DET_TIMING_NUM 6
+
+#define IEEE_ID_HDMI    0x000C03
+#define CEA_AUDIO_BLK   1
+#define CEA_VIDEO_BLK   2
+#define CEA_VENDOR_BLK  3
+#define CEA_SPEAKER_ALLOC_BLK 4
+#define CEA_VESA_DTC_BLK 5
+#define VENDOR_SUPPORT_AI(x) ((x) >> 7)
+#define VENDOR_SUPPORT_DC_48bit(x)  ( ( (x) >> 6) & 0x01)
+#define VENDOR_SUPPORT_DC_36bit(x)  ( ( (x) >> 5) & 0x01)
+#define VENDOR_SUPPORT_DC_30bit(x)  ( ( (x) >> 4) & 0x01)
+#define VENDOR_SUPPORT_DC_Y444(x)   ( ( (x) >> 3) & 0x01)
+#define VENDOR_LATENCY_PRESENT(x)     ( (x) >> 7)
+#define VENDOR_LATENCY_PRESENT_I(x) ( ( (x) >> 6) & 0x01)
+#define HDMI_MAX_TMDS_UNIT   (5000)
+
+struct cea_video_block {
+  Uchar video_code;
+};
+
+struct cea_audio_block_descriptor {
+  Uchar audio_code[3];
+};
+
+struct cea_audio_block {
+  struct cea_audio_block_descriptor descriptor[10];
+};
+
+struct cea_vendor_block_hdmi {
+  Uchar  portB:4;
+  Uchar  portA:4;
+  Uchar  portD:4;
+  Uchar  portC:4;
+  Uchar  support_flags;
+  Uchar  max_tmds_clock;
+  Uchar  latency_present;
+  Uchar  video_latency;
+  Uchar  audio_latency;
+  Uchar  interlaced_video_latency;
+  Uchar  interlaced_audio_latency;
+};
+
+struct cea_vendor_block {
+  unsigned char ieee_id[3];
+  union {
+      struct cea_vendor_block_hdmi hdmi;
+      /* any other vendor blocks we know about */
+  };
+};
+
+struct cea_speaker_block
+{
+  Uchar FLR:1;
+  Uchar LFE:1;
+  Uchar FC:1;
+  Uchar RLR:1;
+  Uchar RC:1;
+  Uchar FLRC:1;
+  Uchar RLRC:1;
+  Uchar FLRW:1;
+  Uchar FLRH:1;
+  Uchar TC:1;
+  Uchar FCH:1;
+  Uchar Resv:5;
+  Uchar ResvByte;
+};
+
+struct cea_data_block {
+  Uchar len:5;
+  Uchar tag:3;
+  union{
+    struct cea_video_block video;
+    struct cea_audio_block audio;
+    struct cea_vendor_block vendor;
+    struct cea_speaker_block speaker;
+  }u;
+};
+
+struct cea_ext_body {
+  Uchar tag;
+  Uchar rev;
+  Uchar dt_offset;
+  Uchar flags;
+  struct cea_data_block data_collection;
+};
+
 #endif /* _EDID_H_ */
diff --git a/hw/xfree86/ddc/interpret_edid.c b/hw/xfree86/ddc/interpret_edid.c
index 12a5254..f3e593a 100644
--- a/hw/xfree86/ddc/interpret_edid.c
+++ b/hw/xfree86/ddc/interpret_edid.c
@@ -42,6 +42,8 @@ static void get_display_section(Uchar*, struct disp_features *,
 static void get_established_timing_section(Uchar*, struct established_timings *);
 static void get_std_timing_section(Uchar*, struct std_timings *,
 				   struct edid_version *);
+static void fetch_detailed_block(Uchar *c, struct edid_version *ver,
+                                 struct detailed_monitor_section *det_mon);
 static void get_dt_md_section(Uchar *, struct edid_version *,
 			      struct detailed_monitor_section *det_mon);
 static void copy_string(Uchar *, Uchar *);
@@ -53,11 +55,25 @@ static void get_detailed_timing_section(Uchar*, struct 	detailed_timings *);
 static Bool validate_version(int scrnIndex, struct edid_version *);
 
 static void
+find_ranges_section(struct detailed_monitor_section *det, void *ranges)
+{
+   if (det->type == DS_RANGES && det->section.ranges.max_clock)
+       *(struct monitor_ranges **)ranges = &det->section.ranges;
+}
+
+static void
+find_max_detailed_clock(struct detailed_monitor_section *det, void *ret)
+{
+    if (det->type == DT) {
+        *(int *)ret = max(*((int *)ret),
+                          det->section.d_timings.clock);
+    }
+}
+
+static void
 handle_edid_quirks(xf86MonPtr m)
 {
-    int i, j;
-    struct detailed_timings *preferred_timing;
-    struct monitor_ranges *ranges;
+    struct monitor_ranges *ranges = NULL;
 
     /*
      * max_clock is only encoded in EDID in tens of MHz, so occasionally we
@@ -65,28 +81,49 @@ handle_edid_quirks(xf86MonPtr m)
      * similar.  Strictly we should refuse to round up too far, but let's
      * see how well this works.
      */
-    for (i = 0; i < 4; i++) {
-	if (m->det_mon[i].type == DS_RANGES) {
-	    ranges = &m->det_mon[i].section.ranges;
-	    for (j = 0; j < 4; j++) {
-		if (m->det_mon[j].type == DT) {
-		    preferred_timing = &m->det_mon[j].section.d_timings;
-		    if (!ranges->max_clock) continue; /* zero is legal */
-		    if (ranges->max_clock * 1000000 < preferred_timing->clock) {
-			xf86Msg(X_WARNING,
-			    "EDID preferred timing clock %.2fMHz exceeds "
-			    "claimed max %dMHz, fixing\n",
-			    preferred_timing->clock / 1.0e6,
-			    ranges->max_clock);
-			ranges->max_clock =
-			    (preferred_timing->clock+999999)/1000000;
-			return;
-		    }
-		}
-	    }
-	}
+
+    /* Try to find Monitor Range and max clock, then re-set range value*/
+    xf86ForEachDetailedBlock(m, find_ranges_section, &ranges);
+    if (ranges && ranges->max_clock) {
+        int clock = 0;
+        xf86ForEachDetailedBlock(m, find_max_detailed_clock, &clock);
+        if (clock && (ranges->max_clock * 1e6 < clock)) {
+            xf86Msg(X_WARNING, "EDID timing clock %.2f exceeds claimed max "
+                    "%dMHz, fixing\n", clock / 1.0e6, ranges->max_clock);
+            ranges->max_clock = (clock+999999)/1e6;
+        }
+    }
+}
+
+struct det_hv_parameter {
+    int real_hsize;
+    int real_vsize;
+    float target_aspect;
+};
+
+static void handle_detailed_hvsize(struct detailed_monitor_section *det_mon,
+                                   void *data)
+{
+    struct det_hv_parameter *p = (struct det_hv_parameter *)data;
+    float timing_aspect;
+
+    if (det_mon->type == DT) {
+        struct detailed_timings *timing;
+        timing = &det_mon->section.d_timings;
+
+        if (!timing->v_size)
+            return;
+
+        timing_aspect = (float)timing->h_size / timing->v_size;
+        if (fabs(1 - (timing_aspect / p->target_aspect)) < 0.05) {
+            p->real_hsize = max(p->real_hsize, timing->h_size);
+            p->real_vsize = max(p->real_vsize, timing->v_size);
+        }
     }
+}
 
+static void encode_aspect_ratio(xf86MonPtr m)
+{
     /*
      * some monitors encode the aspect ratio instead of the physical size.
      * try to find the largest detailed timing that matches that aspect
@@ -96,38 +133,26 @@ handle_edid_quirks(xf86MonPtr m)
 	(m->features.hsize == 16 && m->features.vsize == 10) ||
 	(m->features.hsize == 4 && m->features.vsize == 3) ||
 	(m->features.hsize == 5 && m->features.vsize == 4)) {
-	int real_hsize = 0, real_vsize = 0;
-	float target_aspect, timing_aspect;
-	
-	target_aspect = (float)m->features.hsize / (float)m->features.vsize;
-	for (i = 0; i < 4; i++) {
-	    if (m->det_mon[i].type == DT) {
-		struct detailed_timings *timing;
-		timing = &m->det_mon[i].section.d_timings;
-
-		if (!timing->v_size)
-		    continue;
-
-		timing_aspect = (float)timing->h_size / (float)timing->v_size;
-		if (fabs(1 - (timing_aspect / target_aspect)) < 0.05) {
-		    real_hsize = max(real_hsize, timing->h_size);
-		    real_vsize = max(real_vsize, timing->v_size);
-		}
-	    }
-	}
 
-	if (!real_hsize || !real_vsize) {
+        struct det_hv_parameter p;
+        p.real_hsize = 0;
+        p.real_vsize = 0;
+        p.target_aspect = (float)m->features.hsize /m->features.vsize;
+
+        xf86ForEachDetailedBlock(m, handle_detailed_hvsize, &p);
+
+	if (!p.real_hsize || !p.real_vsize) {
 	    m->features.hsize = m->features.vsize = 0;
-	} else if ((m->features.hsize * 10 == real_hsize) &&
-		   (m->features.vsize * 10 == real_vsize)) {
+	} else if ((m->features.hsize * 10 == p.real_hsize) &&
+		   (m->features.vsize * 10 == p.real_vsize)) {
 	    /* exact match is just unlikely, should do a better check though */
 	    m->features.hsize = m->features.vsize = 0;
 	} else {
 	    /* convert mm to cm */
-	    m->features.hsize = (real_hsize + 5) / 10;
-	    m->features.vsize = (real_vsize + 5) / 10;
+	    m->features.hsize = (p.real_hsize + 5) / 10;
+	    m->features.vsize = (p.real_vsize + 5) / 10;
 	}
-	
+
 	xf86Msg(X_INFO, "Quirked EDID physical size to %dx%d cm\n",
 		m->features.hsize, m->features.vsize);
     }
@@ -156,6 +181,7 @@ xf86InterpretEDID(int scrnIndex, Uchar *block)
     m->no_sections = (int)*(char *)SECTION(NO_EDID,block);
 
     handle_edid_quirks(m);
+    encode_aspect_ratio(m);
 
     return (m);
 
@@ -164,6 +190,141 @@ xf86InterpretEDID(int scrnIndex, Uchar *block)
     return NULL;
 }
 
+static int get_cea_detail_timing(Uchar *blk, xf86MonPtr mon,
+                                 struct detailed_monitor_section *det_mon)
+{
+    int dt_num;
+    int dt_offset = ((struct cea_ext_body *)blk)->dt_offset;
+
+    dt_num = 0;
+
+    if (dt_offset < CEA_EXT_MIN_DATA_OFFSET)
+        return dt_num;
+
+    for (; dt_offset < (CEA_EXT_MAX_DATA_OFFSET - DET_TIMING_INFO_LEN) &&
+           dt_num < CEA_EXT_DET_TIMING_NUM;
+	   _NEXT_DT_MD_SECTION(dt_offset)) {
+
+        fetch_detailed_block(blk + dt_offset, &mon->ver, det_mon + dt_num);
+        dt_num = dt_num + 1 ;
+    }
+
+    return dt_num;
+}
+
+static void handle_cea_detail_block(Uchar *ext, xf86MonPtr mon,
+                                    handle_detailed_fn fn,
+                                    void *data)
+{
+    int i;
+    struct detailed_monitor_section det_mon[CEA_EXT_DET_TIMING_NUM];
+    int det_mon_num;
+
+    det_mon_num = get_cea_detail_timing(ext, mon, det_mon);
+
+    for (i = 0; i < det_mon_num; i++)
+        fn(det_mon + i, data);
+}
+
+void xf86ForEachDetailedBlock(xf86MonPtr mon,
+                              handle_detailed_fn fn,
+                              void *data)
+{
+    int i;
+    Uchar *ext;
+
+    if (mon == NULL)
+        return;
+
+    for (i = 0; i < DET_TIMINGS; i++)
+        fn(mon->det_mon + i, data);
+
+    for (i = 0; i < mon->no_sections; i++) {
+        ext = mon->rawData + EDID1_LEN * (i + 1);
+        switch (ext[EXT_TAG]){
+        case CEA_EXT:
+            handle_cea_detail_block(ext, mon, fn, data);
+            break;
+        case VTB_EXT:
+        case DI_EXT:
+        case LS_EXT:
+        case MI_EXT:
+	    break;
+        }
+    }
+}
+
+static struct cea_data_block *
+extract_cea_data_block(Uchar *ext, int data_type)
+{
+    struct cea_ext_body *cea;
+    struct cea_data_block *data_collection;
+    struct cea_data_block *data_end;
+
+    cea = (struct cea_ext_body *)ext;
+
+    if (cea->dt_offset <= CEA_EXT_MIN_DATA_OFFSET)
+        return NULL;
+
+    data_collection = &cea->data_collection;
+    data_end = (struct cea_data_block *)(cea->dt_offset + ext);
+
+    for ( ;data_collection < data_end;) {
+
+	if (data_type == data_collection->tag) {
+	    return data_collection;
+	}
+	data_collection = (void *)((unsigned char *)data_collection +
+	    data_collection->len + 1);
+    }
+
+    return NULL;
+}
+
+static void handle_cea_video_block(Uchar *ext, handle_video_fn fn, void *data)
+{
+    struct cea_video_block *video;
+    struct cea_video_block *video_end;
+    struct cea_data_block *data_collection;
+
+    data_collection = extract_cea_data_block(ext, CEA_VIDEO_BLK);
+    if (data_collection == NULL)
+        return;
+
+    video = &data_collection->u.video;
+    video_end = (struct cea_video_block *)
+	((Uchar *)video + data_collection->len);
+
+    for (; video < video_end; video = video + 1) {
+	fn(video, data);
+    }
+}
+
+void xf86ForEachVideoBlock(xf86MonPtr mon,
+	                   handle_video_fn fn,
+                           void *data)
+{
+    int i;
+    Uchar *ext;
+
+    if (mon == NULL)
+	return;
+
+    for (i = 0; i < mon->no_sections; i++) {
+	ext = mon->rawData + EDID1_LEN * (i + 1);
+	switch (ext[EXT_TAG]) {
+	case CEA_EXT:
+	    handle_cea_video_block(ext, fn, data);
+	    break;
+	case VTB_EXT:
+	case DI_EXT:
+	case LS_EXT:
+	case MI_EXT:
+	    break;
+	}
+    }
+}
+
 xf86MonPtr
 xf86InterpretEEDID(int scrnIndex, Uchar *block)
 {
@@ -288,66 +449,72 @@ get_std_timing_section(Uchar *c, struct std_timings *r,
 static const unsigned char empty_block[18];
 
 static void
-get_dt_md_section(Uchar *c, struct edid_version *ver, 
-		  struct detailed_monitor_section *det_mon)
+fetch_detailed_block(Uchar *c, struct edid_version *ver,
+                     struct detailed_monitor_section *det_mon)
 {
-  int i;
- 
-  for (i=0;i<DET_TIMINGS;i++) {  
     if (ver->version == 1 && ver->revision >= 1 && IS_MONITOR_DESC) {
-
-      switch (MONITOR_DESC_TYPE) {
-      case SERIAL_NUMBER:
-	det_mon[i].type = DS_SERIAL;
-	copy_string(c,det_mon[i].section.serial);
-	break;
-      case ASCII_STR:
-	det_mon[i].type = DS_ASCII_STR;
-	copy_string(c,det_mon[i].section.ascii_data);
-	break;
-      case MONITOR_RANGES:
-	det_mon[i].type = DS_RANGES;
-	get_monitor_ranges(c,&det_mon[i].section.ranges);
-	break;
-      case MONITOR_NAME:
-	det_mon[i].type = DS_NAME;
-	copy_string(c,det_mon[i].section.name);
-	break;
-      case ADD_COLOR_POINT:
-	det_mon[i].type = DS_WHITE_P;
-	get_whitepoint_section(c,det_mon[i].section.wp);
-	break;
-      case ADD_STD_TIMINGS:
-	det_mon[i].type = DS_STD_TIMINGS;
-	get_dst_timing_section(c,det_mon[i].section.std_t, ver);
-	break;
-      case COLOR_MANAGEMENT_DATA:
-	det_mon[i].type = DS_CMD;
-	break;
-      case CVT_3BYTE_DATA:
-	det_mon[i].type = DS_CVT;
-	get_cvt_timing_section(c, det_mon[i].section.cvt);
-	break;
-      case ADD_EST_TIMINGS:
-	det_mon[i].type = DS_EST_III;
-	memcpy(det_mon[i].section.est_iii, c + 6, 6);
-	break;
-      case ADD_DUMMY:
-	det_mon[i].type = DS_DUMMY;
-        break;
-      default:
-        det_mon[i].type = DS_UNKOWN;
-        break;
-      }
-      if (c[3] <= 0x0F && memcmp(c, empty_block, sizeof(empty_block))) {
-	det_mon[i].type = DS_VENDOR + c[3];
-      }
+        switch (MONITOR_DESC_TYPE) {
+        case SERIAL_NUMBER:
+            det_mon->type = DS_SERIAL;
+            copy_string(c,det_mon->section.serial);
+            break;
+        case ASCII_STR:
+            det_mon->type = DS_ASCII_STR;
+            copy_string(c,det_mon->section.ascii_data);
+            break;
+        case MONITOR_RANGES:
+            det_mon->type = DS_RANGES;
+            get_monitor_ranges(c,&det_mon->section.ranges);
+            break;
+        case MONITOR_NAME:
+            det_mon->type = DS_NAME;
+            copy_string(c,det_mon->section.name);
+            break;
+        case ADD_COLOR_POINT:
+            det_mon->type = DS_WHITE_P;
+            get_whitepoint_section(c,det_mon->section.wp);
+            break;
+        case ADD_STD_TIMINGS:
+            det_mon->type = DS_STD_TIMINGS;
+            get_dst_timing_section(c,det_mon->section.std_t, ver);
+            break;
+        case COLOR_MANAGEMENT_DATA:
+            det_mon->type = DS_CMD;
+            break;
+        case CVT_3BYTE_DATA:
+            det_mon->type = DS_CVT;
+            get_cvt_timing_section(c, det_mon->section.cvt);
+            break;
+        case ADD_EST_TIMINGS:
+            det_mon->type = DS_EST_III;
+	    memcpy(det_mon->section.est_iii, c + 6, 6);
+            break;
+        case ADD_DUMMY:
+            det_mon->type = DS_DUMMY;
+            break;
+        default:
+            det_mon->type = DS_UNKOWN;
+            break;
+        }
+	if (c[3] <= 0x0F && memcmp(c, empty_block, sizeof(empty_block))) {
+            det_mon->type = DS_VENDOR + c[3];
+        }
     } else {
-      det_mon[i].type = DT;
-      get_detailed_timing_section(c,&det_mon[i].section.d_timings);
+        det_mon->type = DT;
+        get_detailed_timing_section(c, &det_mon->section.d_timings);
+    }
+}
+
+static void
+get_dt_md_section(Uchar *c, struct edid_version *ver,
+		  struct detailed_monitor_section *det_mon)
+{
+    int i;
+
+    for (i=0; i < DET_TIMINGS; i++) {
+        fetch_detailed_block(c, ver, det_mon + i);
+        NEXT_DT_MD_SECTION;
     }
-    NEXT_DT_MD_SECTION;
-  }
 }
 
 static void
diff --git a/hw/xfree86/ddc/print_edid.c b/hw/xfree86/ddc/print_edid.c
index ff0b39c..1faae1e 100644
--- a/hw/xfree86/ddc/print_edid.c
+++ b/hw/xfree86/ddc/print_edid.c
@@ -334,129 +334,147 @@ print_detailed_timings(int scrnIndex, struct detailed_timings *t)
     }
 }
 
+/* This function handle all detailed patchs,
+ * including EDID and EDID-extension
+ */
+struct det_print_parameter{
+  xf86MonPtr m;
+  int index;
+  ddc_quirk_t quirks;
+};
+
 static void
-print_detailed_monitor_section(int scrnIndex,
-			       struct detailed_monitor_section *m)
+handle_detailed_print(struct detailed_monitor_section *det_mon,
+                      void *data)
 {
-    int i,j;
-  
-    for (i=0;i<DET_TIMINGS;i++) {
-	switch (m[i].type) {
-	case DT:
-	    print_detailed_timings(scrnIndex,&m[i].section.d_timings);
-	    break;
-	case DS_SERIAL:
-	    xf86DrvMsg(scrnIndex,X_INFO,"Serial No: %s\n",m[i].section.serial);
-	    break;
-	case DS_ASCII_STR:
-	    xf86DrvMsg(scrnIndex,X_INFO," %s\n",m[i].section.ascii_data);
-	    break;
-	case DS_NAME:
-	    xf86DrvMsg(scrnIndex,X_INFO,"Monitor name: %s\n",m[i].section.name);
-	    break;
-	case DS_RANGES:
-	{
-	    struct monitor_ranges *r = &m[i].section.ranges;
+    int j, scrnIndex;
+    struct det_print_parameter *p;
+
+    p = (struct det_print_parameter *)data;
+    scrnIndex = p->m->scrnIndex;
+    xf86DetTimingApplyQuirks(det_mon,p->quirks,
+                             p->m->features.hsize,
+                             p->m->features.vsize);
+
+    switch (det_mon->type) {
+    case DT:
+        print_detailed_timings(scrnIndex,&det_mon->section.d_timings);
+        break;
+    case DS_SERIAL:
+        xf86DrvMsg(scrnIndex,X_INFO,"Serial No: %s\n",det_mon->section.serial);
+        break;
+    case DS_ASCII_STR:
+        xf86DrvMsg(scrnIndex,X_INFO," %s\n",det_mon->section.ascii_data);
+        break;
+    case DS_NAME:
+        xf86DrvMsg(scrnIndex,X_INFO,"Monitor name: %s\n",det_mon->section.name);
+        break;
+    case DS_RANGES:
+    {
+        struct monitor_ranges *r = &det_mon->section.ranges;
+        xf86DrvMsg(scrnIndex,X_INFO,
+                   "Ranges: V min: %i V max: %i Hz, H min: %i H max: %i kHz,",
+                   r->min_v, r->max_v, r->min_h, r->max_h);
+        if (r->max_clock_khz != 0) {
+            xf86ErrorF(" PixClock max %i kHz\n", r->max_clock_khz);
+        if (r->maxwidth)
+            xf86DrvMsg(scrnIndex, X_INFO, "Maximum pixel width: %d\n",
+                       r->maxwidth);
+	xf86DrvMsg(scrnIndex, X_INFO, "Supported aspect ratios:");
+	if (r->supported_aspect & SUPPORTED_ASPECT_4_3)
+	    xf86ErrorF(" 4:3%s",
+                       r->preferred_aspect == PREFERRED_ASPECT_4_3?"*":"");
+	if (r->supported_aspect & SUPPORTED_ASPECT_16_9)
+	    xf86ErrorF(" 16:9%s",
+                       r->preferred_aspect == PREFERRED_ASPECT_16_9?"*":"");
+        if (r->supported_aspect & SUPPORTED_ASPECT_16_10)
+            xf86ErrorF(" 16:10%s",
+                       r->preferred_aspect == PREFERRED_ASPECT_16_10?"*":"");
+	if (r->supported_aspect & SUPPORTED_ASPECT_5_4)
+	    xf86ErrorF(" 5:4%s",
+                       r->preferred_aspect == PREFERRED_ASPECT_5_4?"*":"");
+	if (r->supported_aspect & SUPPORTED_ASPECT_15_9)
+	    xf86ErrorF(" 15:9%s",
+                       r->preferred_aspect == PREFERRED_ASPECT_15_9?"*":"");
+        xf86ErrorF("\n");
+	xf86DrvMsg(scrnIndex, X_INFO, "Supported blankings:");
+	if (r->supported_blanking & CVT_STANDARD)
+	    xf86ErrorF(" standard");
+	if (r->supported_blanking & CVT_REDUCED)
+	    xf86ErrorF(" reduced");
+	xf86ErrorF("\n");
+	xf86DrvMsg(scrnIndex, X_INFO, "Supported scalings:");
+	if (r->supported_scaling & SCALING_HSHRINK)
+	    xf86ErrorF(" hshrink");
+	if (r->supported_scaling & SCALING_HSTRETCH)
+	    xf86ErrorF(" hstretch");
+	if (r->supported_scaling & SCALING_VSHRINK)
+	    xf86ErrorF(" vshrink");
+	if (r->supported_scaling & SCALING_VSTRETCH)
+	    xf86ErrorF(" vstretch");
+        xf86ErrorF("\n");
+	if (r->preferred_refresh)
+	    xf86DrvMsg(scrnIndex, X_INFO, "Preferred refresh rate: %d\n",
+		    r->preferred_refresh);
+	else
+	    xf86DrvMsg(scrnIndex, X_INFO, "Buggy monitor, no preferred "
+		       "refresh rate given\n");
+        } else if (r->max_clock != 0) {
+	    xf86ErrorF(" PixClock max %i MHz\n", r->max_clock);
+        } else {
+	    xf86ErrorF("\n");
+        }
+        if (r->gtf_2nd_f > 0)
+            xf86DrvMsg(scrnIndex,X_INFO," 2nd GTF parameters: f: %i kHz "
+                       "c: %i m: %i k %i j %i\n", r->gtf_2nd_f,
+                       r->gtf_2nd_c, r->gtf_2nd_m, r->gtf_2nd_k,
+                       r->gtf_2nd_j);
+        break;
+    }
+    case DS_STD_TIMINGS:
+        for (j = 0; j<5; j++)
 	    xf86DrvMsg(scrnIndex,X_INFO,
-		       "Ranges: V min: %i V max: %i Hz, H min: %i H max: %i kHz,",
-		       r->min_v, r->max_v, r->min_h, r->max_h);
-	    if (r->max_clock_khz != 0) {
-		xf86ErrorF(" PixClock max %i kHz\n", r->max_clock_khz);
-		if (r->maxwidth)
-		    xf86DrvMsg(scrnIndex, X_INFO, "Maximum pixel width: %d\n",
-			       r->maxwidth);
-		xf86DrvMsg(scrnIndex, X_INFO, "Supported aspect ratios:");
-		if (r->supported_aspect & SUPPORTED_ASPECT_4_3)
-		    xf86ErrorF(" 4:3%s",
-			r->preferred_aspect == PREFERRED_ASPECT_4_3?"*":"");
-		if (r->supported_aspect & SUPPORTED_ASPECT_16_9)
-		    xf86ErrorF(" 16:9%s",
-			r->preferred_aspect == PREFERRED_ASPECT_16_9?"*":"");
-		if (r->supported_aspect & SUPPORTED_ASPECT_16_10)
-		    xf86ErrorF(" 16:10%s",
-			r->preferred_aspect == PREFERRED_ASPECT_16_10?"*":"");
-		if (r->supported_aspect & SUPPORTED_ASPECT_5_4)
-		    xf86ErrorF(" 5:4%s",
-			r->preferred_aspect == PREFERRED_ASPECT_5_4?"*":"");
-		if (r->supported_aspect & SUPPORTED_ASPECT_15_9)
-		    xf86ErrorF(" 15:9%s",
-			r->preferred_aspect == PREFERRED_ASPECT_15_9?"*":"");
-		xf86ErrorF("\n");
-		xf86DrvMsg(scrnIndex, X_INFO, "Supported blankings:");
-		if (r->supported_blanking & CVT_STANDARD)
-		    xf86ErrorF(" standard");
-		if (r->supported_blanking & CVT_REDUCED)
-		    xf86ErrorF(" reduced");
-		xf86ErrorF("\n");
-		xf86DrvMsg(scrnIndex, X_INFO, "Supported scalings:");
-		if (r->supported_scaling & SCALING_HSHRINK)
-		    xf86ErrorF(" hshrink");
-		if (r->supported_scaling & SCALING_HSTRETCH)
-		    xf86ErrorF(" hstretch");
-		if (r->supported_scaling & SCALING_VSHRINK)
-		    xf86ErrorF(" vshrink");
-		if (r->supported_scaling & SCALING_VSTRETCH)
-		    xf86ErrorF(" vstretch");
-		xf86ErrorF("\n");
-		if (r->preferred_refresh)
-		    xf86DrvMsg(scrnIndex, X_INFO, "Preferred refresh rate: %d\n",
-			       r->preferred_refresh);
-		else
-		    xf86DrvMsg(scrnIndex, X_INFO, "Buggy monitor, no preferred "
-			       "refresh rate given\n");
-	    } else if (r->max_clock != 0) {
-		xf86ErrorF(" PixClock max %i MHz\n", r->max_clock);
-	    } else {
-		xf86ErrorF("\n");
-	    }
-	    if (r->gtf_2nd_f > 0)
-		xf86DrvMsg(scrnIndex,X_INFO," 2nd GTF parameters: f: %i kHz "
-			   "c: %i m: %i k %i j %i\n", r->gtf_2nd_f,
-			   r->gtf_2nd_c, r->gtf_2nd_m, r->gtf_2nd_k,
-			   r->gtf_2nd_j);
-	    break;
-	}
-	case DS_STD_TIMINGS:
-	    for (j = 0; j<5; j++) 
-		xf86DrvMsg(scrnIndex,X_INFO,"#%i: hsize: %i  vsize %i  refresh: %i  "
-			   "vid: %i\n",i,m[i].section.std_t[i].hsize,
-			   m[i].section.std_t[j].vsize,m[i].section.std_t[j].refresh,
-			   m[i].section.std_t[j].id);
-	    break;
-	case DS_WHITE_P:
-	    for (j = 0; j<2; j++)
-		if (m[i].section.wp[j].index != 0)
-		    xf86DrvMsg(scrnIndex,X_INFO,
-			       "White point %i: whiteX: %f, whiteY: %f; gamma: %f\n",
-			       m[i].section.wp[j].index,m[i].section.wp[j].white_x,
-			       m[i].section.wp[j].white_y,
-			       m[i].section.wp[j].white_gamma);
-	    break;
-	case DS_CMD:
-	    xf86DrvMsg(scrnIndex, X_INFO,
-		       "Color management data: (not decoded)\n");
-	    break;
-	case DS_CVT:
-	    xf86DrvMsg(scrnIndex, X_INFO,
-		       "CVT 3-byte-code modes:\n");
-	    print_cvt_timings(scrnIndex, m[i].section.cvt);
-	    break;
-	case DS_EST_III:
-	    xf86DrvMsg(scrnIndex, X_INFO,
-		       "Established timings III: (not decoded)\n");
-	    break;
-	case DS_DUMMY:
-	default:
-	    break;
-	}
-	if (m[i].type >= DS_VENDOR && m[i].type <= DS_VENDOR_MAX) {
-	    xf86DrvMsg(scrnIndex, X_INFO,
-		       "Unknown vendor-specific block %hx\n",
-		       m[i].type - DS_VENDOR);
-	}
+		    "#%i: hsize: %i  vsize %i  refresh: %i  "
+		    "vid: %i\n",p->index ,det_mon->section.std_t[j].hsize,
+		    det_mon->section.std_t[j].vsize,
+		    det_mon->section.std_t[j].refresh,
+		    det_mon->section.std_t[j].id);
+        break;
+    case DS_WHITE_P:
+        for (j = 0; j<2; j++)
+        if (det_mon->section.wp[j].index != 0)
+            xf86DrvMsg(scrnIndex,X_INFO,
+                       "White point %i: whiteX: %f, whiteY: %f; gamma: %f\n",
+                       det_mon->section.wp[j].index,det_mon->section.wp[j].white_x,
+                       det_mon->section.wp[j].white_y,
+                       det_mon->section.wp[j].white_gamma);
+        break;
+    case DS_CMD:
+        xf86DrvMsg(scrnIndex, X_INFO,
+                   "Color management data: (not decoded)\n");
+        break;
+    case DS_CVT:
+        xf86DrvMsg(scrnIndex, X_INFO,
+                   "CVT 3-byte-code modes:\n");
+        print_cvt_timings(scrnIndex, det_mon->section.cvt);
+        break;
+    case DS_EST_III:
+        xf86DrvMsg(scrnIndex, X_INFO,
+                   "Established timings III: (not decoded)\n");
+        break;
+    case DS_DUMMY:
+    default:
+        break;
+    }
+    if (det_mon->type >= DS_VENDOR && det_mon->type <= DS_VENDOR_MAX) {
+        xf86DrvMsg(scrnIndex, X_INFO,
+                   "Unknown vendor-specific block %hx\n",
+                   det_mon->type - DS_VENDOR);
     }
+
+    p->index = p->index + 1;
 }
-  
+
 static void
 print_number_sections(int scrnIndex, int num)
 {
@@ -470,6 +488,7 @@ xf86PrintEDID(xf86MonPtr m)
 {
     CARD16 i, j, n;
     char buf[EDID_WIDTH * 2 + 1];
+    struct det_print_parameter p;
 
     if (!m) return NULL;
 
@@ -478,7 +497,12 @@ xf86PrintEDID(xf86MonPtr m)
     print_display(m->scrnIndex, &m->features, &m->ver);
     print_established_timings(m->scrnIndex, &m->timings1);
     print_std_timings(m->scrnIndex, m->timings2);
-    print_detailed_monitor_section(m->scrnIndex, m->det_mon);
+    p.m = m;
+    p.index = 0;
+    p.quirks = xf86DDCDetectQuirks(m->scrnIndex, m, FALSE);
+    xf86ForEachDetailedBlock(m,
+                             handle_detailed_print ,
+                             &p);
     print_number_sections(m->scrnIndex, m->no_sections);
 
     /* extension block section stuff */
@@ -495,6 +519,6 @@ xf86PrintEDID(xf86MonPtr m)
 	}
 	xf86DrvMsg(m->scrnIndex, X_INFO, "\t%s\n", buf);
     }
-    
+
     return m;
 }
diff --git a/hw/xfree86/ddc/xf86DDC.h b/hw/xfree86/ddc/xf86DDC.h
index 64869da..af3ba06 100644
--- a/hw/xfree86/ddc/xf86DDC.h
+++ b/hw/xfree86/ddc/xf86DDC.h
@@ -73,4 +73,54 @@ FindDMTMode(int hsize, int vsize, int refresh, Bool rb);
 
 extern _X_EXPORT const DisplayModeRec DMTModes[];
 
+/*
+ * Quirks to work around broken EDID data from various monitors.
+ */
+typedef enum {
+    DDC_QUIRK_NONE = 0,
+    /* First detailed mode is bogus, prefer largest mode at 60hz */
+    DDC_QUIRK_PREFER_LARGE_60 = 1 << 0,
+    /* 135MHz clock is too high, drop a bit */
+    DDC_QUIRK_135_CLOCK_TOO_HIGH = 1 << 1,
+    /* Prefer the largest mode at 75 Hz */
+    DDC_QUIRK_PREFER_LARGE_75 = 1 << 2,
+    /* Convert detailed timing's horizontal from units of cm to mm */
+    DDC_QUIRK_DETAILED_H_IN_CM = 1 << 3,
+    /* Convert detailed timing's vertical from units of cm to mm */
+    DDC_QUIRK_DETAILED_V_IN_CM = 1 << 4,
+    /* Detailed timing descriptors have bogus size values, so just take the
+     * maximum size and use that.
+     */
+    DDC_QUIRK_DETAILED_USE_MAXIMUM_SIZE = 1 << 5,
+    /* Monitor forgot to set the first detailed is preferred bit. */
+    DDC_QUIRK_FIRST_DETAILED_PREFERRED = 1 << 6,
+    /* use +hsync +vsync for detailed mode */
+    DDC_QUIRK_DETAILED_SYNC_PP = 1 << 7,
+    /* Force single-link DVI bandwidth limit */
+    DDC_QUIRK_DVI_SINGLE_LINK = 1 << 8,
+} ddc_quirk_t;
+
+DisplayModePtr xf86DDCGetModes(int scrnIndex, xf86MonPtr DDC);
+
+extern Bool
+xf86MonitorIsHDMI(xf86MonPtr mon);
+
+typedef void (* handle_detailed_fn)(struct detailed_monitor_section *,void *);
+
+void xf86ForEachDetailedBlock(xf86MonPtr mon,
+                              handle_detailed_fn,
+                              void *data);
+
+ddc_quirk_t
+xf86DDCDetectQuirks(int scrnIndex, xf86MonPtr DDC, Bool verbose);
+
+void xf86DetTimingApplyQuirks(struct detailed_monitor_section *det_mon,
+                              ddc_quirk_t quirks, int hsize, int vsize);
+
+typedef void (* handle_video_fn)(struct cea_video_block *, void *);
+
+void xf86ForEachVideoBlock(xf86MonPtr,
+                           handle_video_fn,
+                           void *);
+
 #endif
diff --git a/hw/xfree86/modes/xf86Crtc.c b/hw/xfree86/modes/xf86Crtc.c
index 506fbb9..138adc0 100644
--- a/hw/xfree86/modes/xf86Crtc.c
+++ b/hw/xfree86/modes/xf86Crtc.c
@@ -1523,6 +1523,42 @@ GuessRangeFromModes(MonPtr mon, DisplayModePtr mode)
        mon->vrefresh[0].lo = 58.0;
 }
 
+struct det_monrec_parameter {
+    MonRec *mon_rec;
+    int *max_clock;
+    Bool set_hsync;
+    Bool set_vrefresh;
+    enum { sync_config, sync_edid, sync_default } *sync_source;
+};
+
+static void handle_detailed_monrec(struct detailed_monitor_section *det_mon,
+                                   void *data)
+{
+    enum { sync_config, sync_edid, sync_default };
+    struct det_monrec_parameter *p;
+    p = (struct det_monrec_parameter *)data;
+
+    if (det_mon->type == DS_RANGES) {
+        struct monitor_ranges *ranges = &det_mon->section.ranges;
+        if (p->set_hsync && ranges->max_h) {
+            p->mon_rec->hsync[p->mon_rec->nHsync].lo = ranges->min_h;
+            p->mon_rec->hsync[p->mon_rec->nHsync].hi = ranges->max_h;
+            p->mon_rec->nHsync++;
+            if (*p->sync_source == sync_default)
+                *p->sync_source = sync_edid;
+        }
+        if (p->set_vrefresh && ranges->max_v) {
+            p->mon_rec->vrefresh[p->mon_rec->nVrefresh].lo = ranges->min_v;
+            p->mon_rec->vrefresh[p->mon_rec->nVrefresh].hi = ranges->max_v;
+            p->mon_rec->nVrefresh++;
+            if (*p->sync_source == sync_default)
+                *p->sync_source = sync_edid;
+        }
+        if (ranges->max_clock * 1000 > *p->max_clock)
+            *p->max_clock = ranges->max_clock * 1000;
+    }
+}
+
 void
 xf86ProbeOutputModes (ScrnInfoPtr scrn, int maxX, int maxY)
 {
@@ -1601,42 +1637,24 @@ xf86ProbeOutputModes (ScrnInfoPtr scrn, int maxX, int maxY)
 	
 	edid_monitor = output->MonInfo;
 	
-	if (edid_monitor)
-	{
-	    int			    i;
-	    Bool		    set_hsync = mon_rec.nHsync == 0;
-	    Bool		    set_vrefresh = mon_rec.nVrefresh == 0;
-	    struct disp_features    *features = &edid_monitor->features;
+        if (edid_monitor)
+        {
+            struct det_monrec_parameter p;
+            struct disp_features    *features = &edid_monitor->features;
 
 	    /* if display is not continuous-frequency, don't add default modes */
 	    if (!GTF_SUPPORTED(features->msc))
 		add_default_modes = FALSE;
 
-	    for (i = 0; i < sizeof (edid_monitor->det_mon) / sizeof (edid_monitor->det_mon[0]); i++)
-	    {
-		if (edid_monitor->det_mon[i].type == DS_RANGES)
-		{
-		    struct monitor_ranges   *ranges = &edid_monitor->det_mon[i].section.ranges;
-		    if (set_hsync && ranges->max_h)
-		    {
-			mon_rec.hsync[mon_rec.nHsync].lo = ranges->min_h;
-			mon_rec.hsync[mon_rec.nHsync].hi = ranges->max_h;
-			mon_rec.nHsync++;
-			if (sync_source == sync_default)
-			    sync_source = sync_edid;
-		    }
-		    if (set_vrefresh && ranges->max_v)
-		    {
-			mon_rec.vrefresh[mon_rec.nVrefresh].lo = ranges->min_v;
-			mon_rec.vrefresh[mon_rec.nVrefresh].hi = ranges->max_v;
-			mon_rec.nVrefresh++;
-			if (sync_source == sync_default)
-			    sync_source = sync_edid;
-		    }
-		    if (ranges->max_clock * 1000 > max_clock)
-			max_clock = ranges->max_clock * 1000;
-		}
-	    }
+	    p.mon_rec = &mon_rec;
+	    p.max_clock = &max_clock;
+	    p.set_hsync = mon_rec.nHsync == 0;
+	    p.set_vrefresh = mon_rec.nVrefresh == 0;
+	    p.sync_source = &sync_source;
+
+	    xf86ForEachDetailedBlock(edid_monitor,
+			             handle_detailed_monrec,
+			             &p);
 	}
 
 	if (xf86GetOptValFreq (output->options, OPTION_MIN_CLOCK,
@@ -2900,6 +2918,35 @@ xf86OutputSetEDIDProperty (xf86OutputPtr output, void *data, int data_len)
 
 #endif
 
+/* Pull out a phyiscal size from a detailed timing if available. */
+struct det_phySize_parameter {
+    xf86OutputPtr output;
+    ddc_quirk_t quirks;
+    Bool ret;
+};
+
+static void  handle_detailed_physical_size(struct detailed_monitor_section
+		                          *det_mon, void *data)
+{
+    struct det_phySize_parameter *p;
+    p = (struct det_phySize_parameter *)data;
+
+    if (p->ret == TRUE )
+        return ;
+
+    xf86DetTimingApplyQuirks(det_mon, p->quirks,
+                             p->output->MonInfo->features.hsize,
+                             p->output->MonInfo->features.vsize);
+    if (det_mon->type == DT &&
+        det_mon->section.d_timings.h_size != 0 &&
+        det_mon->section.d_timings.v_size != 0) {
+
+        p->output->mm_width = det_mon->section.d_timings.h_size;
+        p->output->mm_height = det_mon->section.d_timings.v_size;
+        p->ret = TRUE;
+    }
+}
+
 /**
  * Set the EDID information for the specified output
  */
@@ -2908,7 +2955,6 @@ xf86OutputSetEDID (xf86OutputPtr output, xf86MonPtr edid_mon)
 {
     ScrnInfoPtr		scrn = output->scrn;
     xf86CrtcConfigPtr	config = XF86_CRTC_CONFIG_PTR(scrn);
-    int			i;
 #ifdef RANDR_12_INTERFACE
     int			size;
 #endif
@@ -2943,20 +2989,15 @@ xf86OutputSetEDID (xf86OutputPtr output, xf86MonPtr edid_mon)
     xf86OutputSetEDIDProperty (output, edid_mon ? edid_mon->rawData : NULL, size);
 #endif
 
-    if (edid_mon)
-    {
-	/* Pull out a phyiscal size from a detailed timing if available. */
-	for (i = 0; i < 4; i++) {
-	    if (edid_mon->det_mon[i].type == DT &&
-		edid_mon->det_mon[i].section.d_timings.h_size != 0 &&
-		edid_mon->det_mon[i].section.d_timings.v_size != 0)
-	    {
-		output->mm_width = edid_mon->det_mon[i].section.d_timings.h_size;
-		output->mm_height = edid_mon->det_mon[i].section.d_timings.v_size;
-		break;
-	    }
-	}
-    
+    if (edid_mon) {
+
+        struct det_phySize_parameter p;
+        p.output = output;
+        p.quirks = xf86DDCDetectQuirks(scrn->scrnIndex,edid_mon, FALSE);
+        p.ret = FALSE;
+        xf86ForEachDetailedBlock(edid_mon,
+                                 handle_detailed_physical_size, &p);
+
 	/* if no mm size is available from a detailed timing, check the max size field */
 	if ((!output->mm_width || !output->mm_height) &&
 	    (edid_mon->features.hsize && edid_mon->features.vsize))
diff --git a/hw/xfree86/modes/xf86EdidModes.c b/hw/xfree86/modes/xf86EdidModes.c
index 058e75d..8885a7c 100644
--- a/hw/xfree86/modes/xf86EdidModes.c
+++ b/hw/xfree86/modes/xf86EdidModes.c
@@ -45,20 +45,23 @@
 #include <string.h>
 #include <math.h>
 
+static void handle_detailed_rblank(struct detailed_monitor_section *det_mon,
+                                   void *data)
+{
+    if (det_mon->type == DS_RANGES)
+        if (det_mon->section.ranges.supported_blanking & CVT_REDUCED)
+            *(Bool*)data = TRUE;
+}
+
 static Bool
 xf86MonitorSupportsReducedBlanking(xf86MonPtr DDC)
 {
     /* EDID 1.4 explicitly defines RB support */
     if (DDC->ver.revision >= 4) {
-	int i;
-	for (i = 0; i < DET_TIMINGS; i++) {
-	    struct detailed_monitor_section *det_mon = &DDC->det_mon[i];
-	    if (det_mon->type == DS_RANGES)
-		if (det_mon->section.ranges.supported_blanking & CVT_REDUCED)
-		    return TRUE;
-	}
-	
-	return FALSE;
+        Bool ret = FALSE;
+
+        xf86ForEachDetailedBlock(DDC, handle_detailed_rblank, &ret);
+        return ret;
     }
 
     /* For anything older, assume digital means RB support. Boo. */
@@ -68,34 +71,6 @@ xf86MonitorSupportsReducedBlanking(xf86MonPtr DDC)
     return FALSE;
 }
 
-/*
- * Quirks to work around broken EDID data from various monitors.
- */
-
-typedef enum {
-    DDC_QUIRK_NONE = 0,
-    /* First detailed mode is bogus, prefer largest mode at 60hz */
-    DDC_QUIRK_PREFER_LARGE_60 = 1 << 0,
-    /* 135MHz clock is too high, drop a bit */
-    DDC_QUIRK_135_CLOCK_TOO_HIGH = 1 << 1,
-    /* Prefer the largest mode at 75 Hz */
-    DDC_QUIRK_PREFER_LARGE_75 = 1 << 2,
-    /* Convert detailed timing's horizontal from units of cm to mm */
-    DDC_QUIRK_DETAILED_H_IN_CM = 1 << 3,
-    /* Convert detailed timing's vertical from units of cm to mm */
-    DDC_QUIRK_DETAILED_V_IN_CM = 1 << 4,
-    /* Detailed timing descriptors have bogus size values, so just take the
-     * maximum size and use that.
-     */
-    DDC_QUIRK_DETAILED_USE_MAXIMUM_SIZE = 1 << 5,
-    /* Monitor forgot to set the first detailed is preferred bit. */
-    DDC_QUIRK_FIRST_DETAILED_PREFERRED = 1 << 6,
-    /* use +hsync +vsync for detailed mode */
-    DDC_QUIRK_DETAILED_SYNC_PP = 1 << 7,
-    /* Force single-link DVI bandwidth limit */
-    DDC_QUIRK_DVI_SINGLE_LINK = 1 << 8,
-} ddc_quirk_t;
-
 static Bool quirk_prefer_large_60 (int scrnIndex, xf86MonPtr DDC)
 {
     /* Belinea 10 15 55 */
@@ -774,7 +749,7 @@ DDCGuessRangesFromModes(int scrnIndex, MonPtr Monitor, DisplayModePtr Modes)
     }
 }
 
-static ddc_quirk_t
+ddc_quirk_t
 xf86DDCDetectQuirks(int scrnIndex, xf86MonPtr DDC, Bool verbose)
 {
     ddc_quirk_t	quirks;
@@ -794,6 +769,25 @@ xf86DDCDetectQuirks(int scrnIndex, xf86MonPtr DDC, Bool verbose)
     return quirks;
 }
 
+void xf86DetTimingApplyQuirks(struct detailed_monitor_section *det_mon,
+                              ddc_quirk_t quirks,
+                              int hsize, int vsize)
+{
+    if (det_mon->type != DT)
+        return;
+
+    if (quirks & DDC_QUIRK_DETAILED_H_IN_CM)
+        det_mon->section.d_timings.h_size *= 10;
+
+    if (quirks & DDC_QUIRK_DETAILED_V_IN_CM)
+        det_mon->section.d_timings.v_size *= 10;
+
+    if (quirks & DDC_QUIRK_DETAILED_USE_MAXIMUM_SIZE) {
+        det_mon->section.d_timings.h_size = 10 * hsize;
+        det_mon->section.d_timings.v_size = 10 * vsize;
+    }
+}
+
 /**
  * Applies monitor-specific quirks to the decoded EDID information.
  *
@@ -807,21 +801,9 @@ xf86DDCApplyQuirks(int scrnIndex, xf86MonPtr DDC)
     int i;
 
     for (i = 0; i < DET_TIMINGS; i++) {
-	struct detailed_monitor_section *det_mon = &DDC->det_mon[i];
-
-	if (det_mon->type != DT)
-	    continue;
-
-	if (quirks & DDC_QUIRK_DETAILED_H_IN_CM)
-	    det_mon->section.d_timings.h_size *= 10;
-
-	if (quirks & DDC_QUIRK_DETAILED_V_IN_CM)
-	    det_mon->section.d_timings.v_size *= 10;
-
-	if (quirks & DDC_QUIRK_DETAILED_USE_MAXIMUM_SIZE) {
-	    det_mon->section.d_timings.h_size = 10 * DDC->features.hsize;
-	    det_mon->section.d_timings.v_size = 10 * DDC->features.vsize;
-	}
+        xf86DetTimingApplyQuirks(DDC->det_mon + i, quirks,
+                                 DDC->features.hsize,
+                                 DDC->features.vsize);
     }
 }
 
@@ -866,14 +848,156 @@ xf86DDCSetPreferredRefresh(int scrnIndex, DisplayModePtr modes,
 	    best->type |= M_T_PREFERRED;
 }
 
+#define CEA_VIDEO_MODES_NUM  64
+static const DisplayModeRec CEAVideoModes[CEA_VIDEO_MODES_NUM] = {
+    { MODEPREFIX,    25175,  640,  656,  752,  800, 0,  480,  490,  492,  525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 1:640x480 at 60Hz */
+    { MODEPREFIX,    27000,  720,  736,  798,  858, 0,  480,  489,  495,  525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 2:720x480 at 60Hz */
+    { MODEPREFIX,    27000,  720,  736,  798,  858, 0,  480,  489,  495,  525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 3:720x480 at 60Hz */
+    { MODEPREFIX,    74250, 1280, 1390, 1430, 1650, 0,  720,  725,  730,  750, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 4: 1280x720 at 60Hz */
+    { MODEPREFIX,    74250, 1920, 2008, 2052, 2200, 0, 1080, 1084, 1094, 1125, 0, V_PHSYNC | V_PVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 5:1920x1080i at 60Hz */
+    { MODEPREFIX,    27000, 1440, 1478, 1602, 1716, 0,  480,  488,  494,  525, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 6:1440x480i at 60Hz */
+    { MODEPREFIX,    27000, 1440, 1478, 1602, 1716, 0,  480,  488,  494,  525, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 7:1440x480i at 60Hz */
+    { MODEPREFIX,    27000, 1440, 1478, 1602, 1716, 0,  240,  244,  247,  262, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 8:1440x240 at 60Hz */
+    { MODEPREFIX,    27000, 1440, 1478, 1602, 1716, 0,  240,  244,  247,  262, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 9:1440x240 at 60Hz */
+    { MODEPREFIX,    54000, 2880, 2956, 3204, 3432, 0,  480,  488,  494,  525, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 10:2880x480i at 60Hz */
+    { MODEPREFIX,    54000, 2880, 2956, 3204, 3432, 0,  480,  488,  494,  525, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 11:2880x480i at 60Hz */
+    { MODEPREFIX,    54000, 2880, 2956, 3204, 3432, 0,  240,  244,  247,  262, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 12:2880x240 at 60Hz */
+    { MODEPREFIX,    54000, 2880, 2956, 3204, 3432, 0,  240,  244,  247,  262, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 13:2880x240 at 60Hz */
+    { MODEPREFIX,    54000, 1440, 1472, 1596, 1716, 0,  480,  489,  495,  525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 14:1440x480 at 60Hz */
+    { MODEPREFIX,    54000, 1440, 1472, 1596, 1716, 0,  480,  489,  495,  525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 15:1440x480 at 60Hz */
+    { MODEPREFIX,   148500, 1920, 2008, 2052, 2200, 0, 1080, 1084, 1089, 1125, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 16:1920x1080 at 60Hz */
+    { MODEPREFIX,    27000,  720,  732,  796,  864, 0,  576,  581,  586,  625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 17:720x576 at 50Hz */
+    { MODEPREFIX,    27000,  720,  732,  796,  864, 0,  576,  581,  586,  625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 18:720x576 at 50Hz */
+    { MODEPREFIX,    74250, 1280, 1720, 1760, 1980, 0,  720,  725,  730,  750, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 19: 1280x720 at 50Hz */
+    { MODEPREFIX,    74250, 1920, 2448, 2492, 2640, 0, 1080, 1084, 1094, 1125, 0, V_PHSYNC | V_PVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 20:1920x1080i at 50Hz */
+    { MODEPREFIX,    27000, 1440, 1464, 1590, 1728, 0,  576,  580,  586,  625, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 21:1440x576i at 50Hz */
+    { MODEPREFIX,    27000, 1440, 1464, 1590, 1728, 0,  576,  580,  586,  625, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 22:1440x576i at 50Hz */
+    { MODEPREFIX,    27000, 1440, 1464, 1590, 1728, 0,  288,  290,  293,  312, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 23:1440x288 at 50Hz */
+    { MODEPREFIX,    27000, 1440, 1464, 1590, 1728, 0,  288,  290,  293,  312, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 24:1440x288 at 50Hz */
+    { MODEPREFIX,    54000, 2880, 2928, 3180, 3456, 0,  576,  580,  586,  625, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 25:2880x576i at 50Hz */
+    { MODEPREFIX,    54000, 2880, 2928, 3180, 3456, 0,  576,  580,  586,  625, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 26:2880x576i at 50Hz */
+    { MODEPREFIX,    54000, 2880, 2928, 3180, 3456, 0,  288,  290,  293,  312, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 27:2880x288 at 50Hz */
+    { MODEPREFIX,    54000, 2880, 2928, 3180, 3456, 0,  288,  290,  293,  312, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 28:2880x288 at 50Hz */
+    { MODEPREFIX,    54000, 1440, 1464, 1592, 1728, 0,  576,  581,  586,  625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 29:1440x576 at 50Hz */
+    { MODEPREFIX,    54000, 1440, 1464, 1592, 1728, 0,  576,  581,  586,  625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 30:1440x576 at 50Hz */
+    { MODEPREFIX,   148500, 1920, 2448, 2492, 2640, 0, 1080, 1084, 1089, 1125, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 31:1920x1080 at 50Hz */
+    { MODEPREFIX,    74250, 1920, 2558, 2602, 2750, 0, 1080, 1084, 1089, 1125, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 32:1920x1080 at 24Hz */
+    { MODEPREFIX,    74250, 1920, 2448, 2492, 2640, 0, 1080, 1084, 1089, 1125, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 33:1920x1080 at 25Hz */
+    { MODEPREFIX,    74250, 1920, 2008, 2052, 2200, 0, 1080, 1084, 1089, 1125, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 34:1920x1080 at 30Hz */
+    { MODEPREFIX,   108000, 2880, 2944, 3192, 3432, 0,  480,  489,  495,  525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 35:2880x480 at 60Hz */
+    { MODEPREFIX,   108000, 2880, 2944, 3192, 3432, 0,  480,  489,  495,  525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 36:2880x480 at 60Hz */
+    { MODEPREFIX,   108000, 2880, 2928, 3184, 3456, 0,  576,  581,  586,  625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 37:2880x576 at 50Hz */
+    { MODEPREFIX,   108000, 2880, 2928, 3184, 3456, 0,  576,  581,  586,  625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 38:2880x576 at 50Hz */
+    { MODEPREFIX,    72000, 1920, 1952, 2120, 2304, 0, 1080, 1126, 1136, 1250, 0, V_PHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 39:1920x1080i at 50Hz */
+    { MODEPREFIX,   148500, 1920, 2448, 2492, 2640, 0, 1080, 1084, 1094, 1125, 0, V_PHSYNC | V_PVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 40:1920x1080i at 100Hz */
+    { MODEPREFIX,   148500, 1280, 1720, 1760, 1980, 0,  720,  725,  730,  750, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 41:1280x720 at 100Hz */
+    { MODEPREFIX,    54000,  720,  732,  796,  864, 0,  576,  581,  586,  625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 42:720x576 at 100Hz */
+    { MODEPREFIX,    54000,  720,  732,  796,  864, 0,  576,  581,  586,  625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 43:720x576 at 100Hz */
+    { MODEPREFIX,    54000, 1440, 1464, 1590, 1728, 0,  576,  580,  586,  625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 44:1440x576i at 100Hz */
+    { MODEPREFIX,    54000, 1440, 1464, 1590, 1728, 0,  576,  580,  586,  625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 45:1440x576i at 100Hz */
+    { MODEPREFIX,   148500, 1920, 2008, 2052, 2200, 0, 1080, 1084, 1094, 1125, 0, V_PHSYNC | V_PVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 46:1920x1080i at 120Hz */
+    { MODEPREFIX,   148500, 1280, 1390, 1430, 1650, 0,  720,  725,  730,  750, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 47:1280x720 at 120Hz */
+    { MODEPREFIX,    54000,  720,  736,  798,  858, 0,  480,  489,  495,  525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 48:720x480 at 120Hz */
+    { MODEPREFIX,    54000,  720,  736,  798,  858, 0,  480,  489,  495,  525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 49:720x480 at 120Hz */
+    { MODEPREFIX,    54000, 1440, 1478, 1602, 1716, 0,  480,  488,  494,  525, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX },/* VIC 50:1440x480i at 120Hz */
+    { MODEPREFIX,    54000, 1440, 1478, 1602, 1716, 0,  480,  488,  494,  525, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX },/* VIC 51:1440x480i at 120Hz */
+    { MODEPREFIX,   108000,  720,  732,  796,  864, 0,  576,  581,  586,  625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 52:720x576 at 200Hz */
+    { MODEPREFIX,   108000,  720,  732,  796,  864, 0,  576,  581,  586,  625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 53:720x576 at 200Hz */
+    { MODEPREFIX,   108000, 1440, 1464, 1590, 1728, 0,  576,  580,  586,  625, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX },/* VIC 54:1440x576i at 200Hz */
+    { MODEPREFIX,   108000, 1440, 1464, 1590, 1728, 0,  576,  580,  586,  625, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX },/* VIC 55:1440x576i at 200Hz */
+    { MODEPREFIX,   108000,  720,  736,  798,  858, 0,  480,  489,  495,  525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 56:720x480 at 240Hz */
+    { MODEPREFIX,   108000,  720,  736,  798,  858, 0,  480,  489,  495,  525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 57:720x480 at 240Hz */
+    { MODEPREFIX,   108000, 1440, 1478, 1602, 1716, 0,  480,  488,  494,  525, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX },/* VIC 58:1440x480i at 240 */
+    { MODEPREFIX,   108000, 1440, 1478, 1602, 1716, 0,  480,  488,  494,  525, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX },/* VIC 59:1440x480i at 240 */
+    { MODEPREFIX,    59400, 1280, 3040, 3080, 3300, 0,  720,  725,  730,  750, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 60: 1280x720 at 24Hz */
+    { MODEPREFIX,    74250, 3700, 3740, 1430, 3960, 0,  720,  725,  730,  750, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 61: 1280x720 at 25Hz */
+    { MODEPREFIX,    74250, 1280, 3040, 3080, 3300, 0,  720,  725,  730,  750, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 62: 1280x720 at 30Hz */
+    { MODEPREFIX,   297000, 1920, 2008, 2052, 2200, 0, 1080, 1084, 1089, 1125, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 63: 1920x1080 at 120Hz */
+    { MODEPREFIX,   297000, 1920, 2448, 2492, 2640, 0, 1080, 1084, 1094, 1125, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 64:1920x1080 at 100Hz */
+};
+
+/* chose mode line by cea short video descriptor*/
+static void handle_cea_svd(struct cea_video_block *video, void *data)
+{
+    DisplayModePtr Mode;
+    DisplayModePtr *Modes = (DisplayModePtr *) data;
+    int vid;
+
+    vid = video ->video_code & 0x7f;
+    if (vid < CEA_VIDEO_MODES_NUM) {
+	Mode = xf86DuplicateMode(CEAVideoModes + vid);
+	*Modes = xf86ModesAdd(*Modes, Mode);
+    }
+}
+
+static DisplayModePtr
+DDCModesFromCEAExtension(int scrnIndex, xf86MonPtr MonPtr)
+{
+    DisplayModePtr Modes = NULL;
+
+    xf86ForEachVideoBlock(MonPtr,
+                          handle_cea_svd,
+                          &Modes);
+
+    return Modes;
+}
+
+struct det_modes_parameter {
+    xf86MonPtr DDC;
+    ddc_quirk_t quirks;
+    DisplayModePtr  Modes;
+    Bool rb;
+    Bool preferred;
+    int timing_level;
+};
+
+static void handle_detailed_modes(struct detailed_monitor_section *det_mon,
+	                          void *data)
+{
+    DisplayModePtr  Mode;
+    struct det_modes_parameter *p = (struct det_modes_parameter *)data;
+
+    xf86DetTimingApplyQuirks(det_mon,p->quirks,
+                             p->DDC->features.hsize,
+                             p->DDC->features.vsize);
+
+    switch (det_mon->type) {
+    case DT:
+        Mode = DDCModeFromDetailedTiming(p->DDC->scrnIndex,
+                                         &det_mon->section.d_timings,
+                                         p->preferred,
+                                         p->quirks);
+        p->preferred = FALSE;
+        p->Modes = xf86ModesAdd(p->Modes, Mode);
+        break;
+    case DS_STD_TIMINGS:
+        Mode = DDCModesFromStandardTiming(det_mon->section.std_t,
+                                          p->quirks, p->timing_level,p->rb);
+        p->Modes = xf86ModesAdd(p->Modes, Mode);
+        break;
+#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(7,0,0,0,0)
+    case DS_CVT:
+        Mode = DDCModesFromCVT(p->DDC->scrnIndex, det_mon->section.cvt);
+        p->Modes = xf86ModesAdd(p->Modes, Mode);
+        break;
+#endif
+    case DS_EST_III:
+	Mode = DDCModesFromEstIII(det_mon->section.est_iii);
+	p->Modes = xf86ModesAdd(p->Modes, Mode);
+	break;
+    default:
+        break;
+    }
+}
+
 DisplayModePtr
 xf86DDCGetModes(int scrnIndex, xf86MonPtr DDC)
 {
-    int		    i;
     DisplayModePtr  Modes = NULL, Mode;
     ddc_quirk_t	    quirks;
     Bool	    preferred, rb;
     int		    timing_level;
+    struct det_modes_parameter p;
 
     xf86DrvMsg (scrnIndex, X_INFO, "EDID vendor \"%s\", prod id %d\n",
 		DDC->vendor.name, DDC->vendor.prod_id);
@@ -892,35 +1016,14 @@ xf86DDCGetModes(int scrnIndex, xf86MonPtr DDC)
 
     timing_level = MonitorStandardTimingLevel(DDC);
 
-    for (i = 0; i < DET_TIMINGS; i++) {
-	struct detailed_monitor_section *det_mon = &DDC->det_mon[i];
-
-	Mode = NULL;
-        switch (det_mon->type) {
-        case DT:
-            Mode = DDCModeFromDetailedTiming(scrnIndex,
-                                             &det_mon->section.d_timings,
-					     preferred,
-					     quirks);
-	    preferred = FALSE;
-            break;
-        case DS_STD_TIMINGS:
-            Mode = DDCModesFromStandardTiming(det_mon->section.std_t,
-					      quirks, timing_level, rb);
-            break;
-#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(7,0,0,0,0)
-	case DS_CVT:
-	    Mode = DDCModesFromCVT(scrnIndex, det_mon->section.cvt);
-	    break;
-#endif
-	case DS_EST_III:
-	    Mode = DDCModesFromEstIII(det_mon->section.est_iii);
-	    break;
-        default:
-            break;
-        }
-	Modes = xf86ModesAdd(Modes, Mode);
-    }
+    p.quirks = quirks;
+    p.DDC = DDC;
+    p.Modes = Modes;
+    p.rb = rb;
+    p.preferred = preferred;
+    p.timing_level = timing_level;
+    xf86ForEachDetailedBlock(DDC, handle_detailed_modes, &p);
+    Modes = p.Modes;
 
     /* Add established timings */
     Mode = DDCModesFromEstablished(scrnIndex, &DDC->timings1, quirks);
@@ -930,6 +1033,10 @@ xf86DDCGetModes(int scrnIndex, xf86MonPtr DDC)
     Mode = DDCModesFromStandardTiming(DDC->timings2, quirks, timing_level, rb);
     Modes = xf86ModesAdd(Modes, Mode);
 
+    /* Add cea-extension mode timings */
+    Mode = DDCModesFromCEAExtension(scrnIndex,DDC);
+    Modes = xf86ModesAdd(Modes, Mode);
+
     if (quirks & DDC_QUIRK_PREFER_LARGE_60)
 	xf86DDCSetPreferredRefresh(scrnIndex, Modes, 60);
 
@@ -939,6 +1046,63 @@ xf86DDCGetModes(int scrnIndex, xf86MonPtr DDC)
     return Modes;
 }
 
+struct det_mon_parameter {
+    MonPtr Monitor;
+    ddc_quirk_t quirks;
+    Bool have_hsync;
+    Bool have_vrefresh;
+    Bool have_maxpixclock;
+};
+
+static void handle_detailed_monset(struct detailed_monitor_section *det_mon,
+                                   void *data)
+{
+    int clock;
+    struct det_mon_parameter *p = (struct det_mon_parameter *)data;
+    int scrnIndex = ((xf86MonPtr)(p->Monitor->DDC))->scrnIndex;
+
+    switch (det_mon->type) {
+    case DS_RANGES:
+        if (!p->have_hsync) {
+            if (!p->Monitor->nHsync)
+                xf86DrvMsg(scrnIndex, X_INFO,
+                    "Using EDID range info for horizontal sync\n");
+                p->Monitor->hsync[p->Monitor->nHsync].lo =
+                    det_mon->section.ranges.min_h;
+                p->Monitor->hsync[p->Monitor->nHsync].hi =
+                    det_mon->section.ranges.max_h;
+                p->Monitor->nHsync++;
+        } else {
+            xf86DrvMsg(scrnIndex, X_INFO,
+                "Using hsync ranges from config file\n");
+        }
+
+        if (!p->have_vrefresh) {
+            if (!p->Monitor->nVrefresh)
+                xf86DrvMsg(scrnIndex, X_INFO,
+                    "Using EDID range info for vertical refresh\n");
+            p->Monitor->vrefresh[p->Monitor->nVrefresh].lo =
+                det_mon->section.ranges.min_v;
+            p->Monitor->vrefresh[p->Monitor->nVrefresh].hi =
+                det_mon->section.ranges.max_v;
+            p->Monitor->nVrefresh++;
+        } else {
+            xf86DrvMsg(scrnIndex, X_INFO,
+                "Using vrefresh ranges from config file\n");
+        }
+
+        clock = det_mon->section.ranges.max_clock * 1000;
+        if (p->quirks & DDC_QUIRK_DVI_SINGLE_LINK)
+            clock = min(clock, 165000);
+        if (!p->have_maxpixclock && clock > p->Monitor->maxPixClock)
+            p->Monitor->maxPixClock = clock;
+
+        break;
+    default:
+        break;
+    }
+}
+
 /*
  * Fill out MonPtr with xf86MonPtr information.
  */
@@ -946,17 +1110,13 @@ void
 xf86EdidMonitorSet(int scrnIndex, MonPtr Monitor, xf86MonPtr DDC)
 {
     DisplayModePtr Modes = NULL, Mode;
-    int i, clock;
-    Bool have_hsync = FALSE, have_vrefresh = FALSE, have_maxpixclock = FALSE;
-    ddc_quirk_t quirks;
+    struct det_mon_parameter p;
 
     if (!Monitor || !DDC)
         return;
 
     Monitor->DDC = DDC;
 
-    quirks = xf86DDCDetectQuirks(scrnIndex, DDC, FALSE);
-
     if (Monitor->widthmm <= 0 || Monitor->heightmm <= 0) {
 	Monitor->widthmm = 10 * DDC->features.hsize;
 	Monitor->heightmm = 10 * DDC->features.vsize;
@@ -966,54 +1126,13 @@ xf86EdidMonitorSet(int scrnIndex, MonPtr Monitor, xf86MonPtr DDC)
 
     Modes = xf86DDCGetModes(scrnIndex, DDC);
 
-    /* Skip EDID ranges if they were specified in the config file */
-    have_hsync = (Monitor->nHsync != 0);
-    have_vrefresh = (Monitor->nVrefresh != 0);
-    have_maxpixclock = (Monitor->maxPixClock != 0);
-
     /* Go through the detailed monitor sections */
-    for (i = 0; i < DET_TIMINGS; i++) {
-        switch (DDC->det_mon[i].type) {
-        case DS_RANGES:
-	    if (!have_hsync) {
-		if (!Monitor->nHsync)
-		    xf86DrvMsg(scrnIndex, X_INFO,
-			    "Using EDID range info for horizontal sync\n");
-		Monitor->hsync[Monitor->nHsync].lo =
-		    DDC->det_mon[i].section.ranges.min_h;
-		Monitor->hsync[Monitor->nHsync].hi =
-		    DDC->det_mon[i].section.ranges.max_h;
-		Monitor->nHsync++;
-	    } else {
-		xf86DrvMsg(scrnIndex, X_INFO,
-			"Using hsync ranges from config file\n");
-	    }
-
-	    if (!have_vrefresh) {
-		if (!Monitor->nVrefresh)
-		    xf86DrvMsg(scrnIndex, X_INFO,
-			    "Using EDID range info for vertical refresh\n");
-		Monitor->vrefresh[Monitor->nVrefresh].lo =
-		    DDC->det_mon[i].section.ranges.min_v;
-		Monitor->vrefresh[Monitor->nVrefresh].hi =
-		    DDC->det_mon[i].section.ranges.max_v;
-		Monitor->nVrefresh++;
-	    } else {
-		xf86DrvMsg(scrnIndex, X_INFO,
-			"Using vrefresh ranges from config file\n");
-	    }
-
-	    clock = DDC->det_mon[i].section.ranges.max_clock * 1000;
-	    if (quirks & DDC_QUIRK_DVI_SINGLE_LINK)
-		clock = min(clock, 165000);
-	    if (!have_maxpixclock && clock > Monitor->maxPixClock)
-		Monitor->maxPixClock = clock;
-
-            break;
-        default:
-            break;
-        }
-    }
+    p.Monitor = Monitor;
+    p.quirks = xf86DDCDetectQuirks(scrnIndex, Monitor->DDC, FALSE);
+    p.have_hsync = (Monitor->nHsync != 0);
+    p.have_vrefresh = (Monitor->nVrefresh != 0);
+    p.have_maxpixclock = (Monitor->maxPixClock != 0);
+    xf86ForEachDetailedBlock(DDC, handle_detailed_monset, &p);
 
     if (Modes) {
         /* Print Modes */


More information about the xorg-commit mailing list