[PATCH 1/5] handle extenion for detail timing block

ling.ma at intel.com ling.ma at intel.com
Mon Nov 17 00:33:17 PST 2008


From: MaLing<ling.ma at intel.com>

hi All,
I updated extensions for detail timing block.
In this version, I devide it into 5 patchs.
[PATCH 1/5] implement common functions & structures, and handl funcion.
[PATCH 2/5] handl detail timing data in xf86EdidModes.c file. 
[PATCH 3/5] handl detail timing data in xf86Crtc.c file.
[PATCH 4/5] handl detail timing data in xf86Configure.c file.
[PATCH 5/5] handl detail timing data in print_edid.c file.

Any comments are welcome !
Thanks
Ma Ling
---
 hw/xfree86/ddc/edid.h           |   73 ++++++++++++++
 hw/xfree86/ddc/interpret_edid.c |  197 +++++++++++++++++++++++++++++----------
 hw/xfree86/ddc/xf86DDC.h        |   35 +++++++
 hw/xfree86/modes/xf86Modes.h    |    3 -
 4 files changed, 254 insertions(+), 54 deletions(-)

diff --git a/hw/xfree86/ddc/edid.h b/hw/xfree86/ddc/edid.h
index 45caf6e..f518137 100644
--- a/hw/xfree86/ddc/edid.h
+++ b/hw/xfree86/ddc/edid.h
@@ -549,4 +549,77 @@ typedef struct {
 
 extern xf86MonPtr ConfiguredMonitor;
 
+#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 EXT_TAG 0
+#define EXT_REV 1
+
+struct cea_video_blk {
+  Uchar video_code; 
+};
+
+struct cea_audio_blk {
+    Uchar descs[3];
+};
+
+struct hdmi {
+  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_blk {
+  unsigned char ieee_id[3];
+  Uchar  Port_Addr[2];
+  struct hdmi hdmi;
+};
+
+struct cea_speaker_blk 
+{
+  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 Resv_Byte;
+};
+
+struct cea_data_blk {
+  Uchar len:5;
+  Uchar tag:3;
+union{
+    struct cea_video_blk video;
+    struct cea_audio_blk audio;
+    struct cea_vendor_blk vendor;
+    struct cea_speaker_blk speaker;
+  }u;
+};
+
+struct cea_ext_body {
+  Uchar tag;
+  Uchar rev;
+  Uchar dt_offset;
+  Uchar flags;
+  struct cea_data_blk data_collection;
+};
+
 #endif /* _EDID_H_ */
diff --git a/hw/xfree86/ddc/interpret_edid.c b/hw/xfree86/ddc/interpret_edid.c
index c4d8963..e7c6049 100644
--- a/hw/xfree86/ddc/interpret_edid.c
+++ b/hw/xfree86/ddc/interpret_edid.c
@@ -42,7 +42,7 @@ 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 get_dt_md_section(Uchar *, struct edid_version *,
-			      struct detailed_monitor_section *det_mon);
+                              struct detailed_monitor_section *det_mon, int);
 static void copy_string(Uchar *, Uchar *);
 static void get_dst_timing_section(Uchar *, struct std_timings *,
 				   struct edid_version *);
@@ -52,11 +52,27 @@ 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)
+       *(struct monitor_ranges **)ranges = &det->section.ranges;
+}
+
+static void
+find_max_detailed_clock(struct detailed_monitor_section *det, void *ret)
+{
+    int *clock = ret;
+
+    if (det->type == DT) {
+        struct detailed_timings *t = &det->section.d_timings;
+        *clock = max(*clock, t->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
@@ -64,28 +80,116 @@ 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;
-		    }
-		}
-	    }
-	}
+    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;
+        }
+    }
+
+}
+
+static int GetCEADetailTiming(Uchar *blk, xf86MonPtr mon,
+                              struct detailed_monitor_section *det_mon)
+		        
+{
+    int det_mon_num;
+    int dt_offset = ((struct cea_ext_body *)blk)->dt_offset;
+
+    det_mon_num = 0;
+
+    if (dt_offset < CEA_EXT_MIN_DATA_OFFSET)
+        return det_mon_num;
+
+    while (dt_offset < (CEA_EXT_MAX_DATA_OFFSET - DET_TIMING_INFO_LEN) &&
+           det_mon_num < CEA_EXT_DET_TIMING_NUM) { 
+        get_dt_md_section(blk + dt_offset, &mon->ver, 
+                          det_mon + det_mon_num, 1);
+
+        det_mon_num = det_mon_num + 1 ;
+
+        _NEXT_DT_MD_SECTION(dt_offset);
+    }
+
+    return det_mon_num;
+}
+
+
+static void HandleCEADetailedBlock(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 = GetCEADetailTiming(ext, mon, det_mon);
+
+    for (i = 0; i < det_mon_num; i = i + 1)
+         fn(det_mon , 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 = i + 1) {
+        ext = &mon->rawData[EDID1_LEN + i * EDID1_LEN];
+        switch (ext[EXT_TAG]){
+        case CEA_EXT:
+            HandleCEADetailedBlock(ext, mon, fn, data);
+            break;
+        case VTB_EXT:
+        case DI_EXT:
+        case LS_EXT:
+        case MI_EXT:
+	    break;
+        }
+    }
+}
+
+struct det_hv_perameter {
+    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_perameter *p = (struct det_hv_perameter *)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 / (float)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
@@ -95,36 +199,24 @@ 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_perameter p;
+        p.real_hsize = 0;
+        p.real_vsize = 0;
+        p.target_aspect = (float)m->features.hsize /(float)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",
@@ -151,10 +243,13 @@ xf86InterpretEDID(int scrnIndex, Uchar *block)
 				   &m->timings1);
     get_std_timing_section(SECTION(STD_TIMING_SECTION,block),m->timings2,
 			   &m->ver);
-    get_dt_md_section(SECTION(DET_TIMING_SECTION,block),&m->ver, m->det_mon);
+    get_dt_md_section(SECTION(DET_TIMING_SECTION,block), &m->ver, 
+                      m->det_mon, DET_TIMINGS);
+
     m->no_sections = (int)*(char *)SECTION(NO_EDID,block);
 
     handle_edid_quirks(m);
+    encode_aspect_ratio(m);
 
     return (m);
 
@@ -286,11 +381,11 @@ get_std_timing_section(Uchar *c, struct std_timings *r,
 
 static void
 get_dt_md_section(Uchar *c, struct edid_version *ver, 
-		  struct detailed_monitor_section *det_mon)
+                  struct detailed_monitor_section *det_mon, int det_mon_num)
 {
   int i;
  
-  for (i=0;i<DET_TIMINGS;i++) {  
+  for (i=0;i<det_mon_num;i++) {  
     if (ver->version == 1 && ver->revision >= 1 && IS_MONITOR_DESC) {
 
       switch (MONITOR_DESC_TYPE) {
diff --git a/hw/xfree86/ddc/xf86DDC.h b/hw/xfree86/ddc/xf86DDC.h
index 3172b55..62b7c04 100644
--- a/hw/xfree86/ddc/xf86DDC.h
+++ b/hw/xfree86/ddc/xf86DDC.h
@@ -57,9 +57,44 @@ extern Bool xf86SetDDCproperties(
     xf86MonPtr DDC
 );
 
+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);
 #endif
diff --git a/hw/xfree86/modes/xf86Modes.h b/hw/xfree86/modes/xf86Modes.h
index af5987b..0533a32 100644
--- a/hw/xfree86/modes/xf86Modes.h
+++ b/hw/xfree86/modes/xf86Modes.h
@@ -107,7 +107,4 @@ xf86GetMonitorModes (ScrnInfoPtr pScrn, XF86ConfMonitorPtr conf_monitor);
 DisplayModePtr
 xf86GetDefaultModes (Bool interlaceAllowed, Bool doubleScanAllowed);
 
-void
-xf86DDCApplyQuirks(int scrnIndex, xf86MonPtr DDC);
-
 #endif /* _XF86MODES_H_ */
-- 
1.5.4.4




More information about the xorg mailing list