[PATCH 4/9] handle detailed timing operation in xf86EdidModes.c
Ma Ling
ling.ma at intel.com
Wed Feb 11 01:15:40 PST 2009
handle detailed timing quirks and insert detailed timing modes into mode list
---
hw/xfree86/ddc/xf86DDC.h | 39 +++++
hw/xfree86/modes/xf86EdidModes.c | 284 ++++++++++++++++++++------------------
2 files changed, 190 insertions(+), 133 deletions(-)
diff --git a/hw/xfree86/ddc/xf86DDC.h b/hw/xfree86/ddc/xf86DDC.h
index b865e1a..0f4f65f 100644
--- a/hw/xfree86/ddc/xf86DDC.h
+++ b/hw/xfree86/ddc/xf86DDC.h
@@ -62,9 +62,48 @@ extern _X_EXPORT DisplayModePtr xf86DDCGetModes(int scrnIndex, xf86MonPtr DDC);
extern _X_EXPORT Bool
xf86MonitorIsHDMI(xf86MonPtr mon);
+/*
+ * 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);
+
#endif
diff --git a/hw/xfree86/modes/xf86EdidModes.c b/hw/xfree86/modes/xf86EdidModes.c
index 1413e87..97c40bf 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 */
@@ -667,7 +642,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;
@@ -687,6 +662,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.
*
@@ -700,21 +694,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);
}
}
@@ -759,14 +741,58 @@ xf86DDCSetPreferredRefresh(int scrnIndex, DisplayModePtr modes,
best->type |= M_T_PREFERRED;
}
+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
+ 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);
@@ -785,33 +811,13 @@ 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];
-
- switch (det_mon->type) {
- case DT:
- Mode = DDCModeFromDetailedTiming(scrnIndex,
- &det_mon->section.d_timings,
- preferred,
- quirks);
- preferred = FALSE;
- Modes = xf86ModesAdd(Modes, Mode);
- break;
- case DS_STD_TIMINGS:
- Mode = DDCModesFromStandardTiming(det_mon->section.std_t,
- quirks, timing_level, rb);
- Modes = xf86ModesAdd(Modes, Mode);
- break;
-#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(7,0,0,0,0)
- case DS_CVT:
- Mode = DDCModesFromCVT(scrnIndex, det_mon->section.cvt);
- Modes = xf86ModesAdd(Modes, Mode);
- break;
-#endif
- default:
- break;
- }
- }
+ 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);
/* Add established timings */
Mode = DDCModesFromEstablished(scrnIndex, &DDC->timings1, quirks);
@@ -830,6 +836,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.
*/
@@ -837,17 +900,13 @@ void
xf86DDCMonitorSet(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;
@@ -857,54 +916,13 @@ xf86DDCMonitorSet(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 */
--
1.5.4.4
More information about the xorg
mailing list