From 578938f1cdd5a06dd6fa28167d575ec980322a5d Mon Sep 17 00:00:00 2001
From: marha <marha@users.sourceforge.net>
Date: Mon, 16 Nov 2009 13:46:01 +0000
Subject: Update to git master branch of xserver.

---
 xorg-server/hw/xfree86/ddc/edid.h           |  97 +++++++
 xorg-server/hw/xfree86/ddc/interpret_edid.c | 375 ++++++++++++++++++++--------
 xorg-server/hw/xfree86/ddc/print_edid.c     | 264 +++++++++++---------
 xorg-server/hw/xfree86/ddc/xf86DDC.h        |  50 ++++
 4 files changed, 562 insertions(+), 224 deletions(-)

(limited to 'xorg-server/hw/xfree86/ddc')

diff --git a/xorg-server/hw/xfree86/ddc/edid.h b/xorg-server/hw/xfree86/ddc/edid.h
index 3feb9796f..cc4bd02ea 100644
--- a/xorg-server/hw/xfree86/ddc/edid.h
+++ b/xorg-server/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/xorg-server/hw/xfree86/ddc/interpret_edid.c b/xorg-server/hw/xfree86/ddc/interpret_edid.c
index 12a52545e..f3e593aec 100644
--- a/xorg-server/hw/xfree86/ddc/interpret_edid.c
+++ b/xorg-server/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 *);
@@ -52,12 +54,26 @@ static void get_whitepoint_section(Uchar *, struct whitePoints *);
 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/xorg-server/hw/xfree86/ddc/print_edid.c b/xorg-server/hw/xfree86/ddc/print_edid.c
index ff0b39cc1..1faae1e33 100644
--- a/xorg-server/hw/xfree86/ddc/print_edid.c
+++ b/xorg-server/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/xorg-server/hw/xfree86/ddc/xf86DDC.h b/xorg-server/hw/xfree86/ddc/xf86DDC.h
index 64869da10..af3ba06a5 100644
--- a/xorg-server/hw/xfree86/ddc/xf86DDC.h
+++ b/xorg-server/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
-- 
cgit v1.2.3