Add EDID quirk support for broken EDID data.
For EDID with known errors, add a quirk mechanism to automatically compensate. The first quirk is for a Belinea 1440x900 monitor which incorrectly specifies sync polarities in the detailed mode.
This commit is contained in:
parent
d9b27667e6
commit
fab9a6b621
|
|
@ -40,6 +40,44 @@
|
|||
|
||||
#if XORG_VERSION_CURRENT <= XORG_VERSION_NUMERIC(7,2,99,2,0)
|
||||
|
||||
/*
|
||||
* Quirks to work around broken EDID data from various monitors.
|
||||
*/
|
||||
|
||||
typedef enum {
|
||||
DDC_QUIRK_NONE = 0,
|
||||
/*
|
||||
* Detailed timing sync polarity values are inverted
|
||||
*/
|
||||
DDC_QUIRK_DT_SYNC_INVERT = 1 << 0,
|
||||
} ddc_quirk_t;
|
||||
|
||||
static Bool dt_sync_invert (int scrnIndex, xf86MonPtr DDC)
|
||||
{
|
||||
/* Belinea 1924S1W */
|
||||
if (memcmp (DDC->vendor.name, "MAX", 4) == 0 &&
|
||||
DDC->vendor.prod_id == 1932)
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
Bool (*detect) (int scrnIndex, xf86MonPtr DDC);
|
||||
ddc_quirk_t quirk;
|
||||
char *description;
|
||||
} ddc_quirk_map_t;
|
||||
|
||||
static const ddc_quirk_map_t ddc_quirks[] = {
|
||||
{
|
||||
dt_sync_invert, DDC_QUIRK_DT_SYNC_INVERT,
|
||||
"Detailed timing data contains inverted sync polarity"
|
||||
},
|
||||
{
|
||||
NULL, DDC_QUIRK_NONE,
|
||||
"No known quirks"
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
* TODO:
|
||||
* - for those with access to the VESA DMT standard; review please.
|
||||
|
|
@ -68,7 +106,8 @@ DisplayModeRec DDCEstablishedModes[17] = {
|
|||
};
|
||||
|
||||
static DisplayModePtr
|
||||
DDCModesFromEstablished(int scrnIndex, struct established_timings *timing)
|
||||
DDCModesFromEstablished(int scrnIndex, struct established_timings *timing,
|
||||
ddc_quirk_t quirks)
|
||||
{
|
||||
DisplayModePtr Modes = NULL, Mode = NULL;
|
||||
CARD32 bits = (timing->t1) | (timing->t2 << 8) |
|
||||
|
|
@ -89,7 +128,8 @@ DDCModesFromEstablished(int scrnIndex, struct established_timings *timing)
|
|||
*
|
||||
*/
|
||||
static DisplayModePtr
|
||||
DDCModesFromStandardTiming(int scrnIndex, struct std_timings *timing)
|
||||
DDCModesFromStandardTiming(int scrnIndex, struct std_timings *timing,
|
||||
ddc_quirk_t quirks)
|
||||
{
|
||||
DisplayModePtr Modes = NULL, Mode = NULL;
|
||||
int i;
|
||||
|
|
@ -111,9 +151,10 @@ DDCModesFromStandardTiming(int scrnIndex, struct std_timings *timing)
|
|||
*/
|
||||
static DisplayModePtr
|
||||
DDCModeFromDetailedTiming(int scrnIndex, struct detailed_timings *timing,
|
||||
int preferred)
|
||||
int preferred, ddc_quirk_t quirks)
|
||||
{
|
||||
DisplayModePtr Mode;
|
||||
unsigned int misc;
|
||||
|
||||
/* We don't do stereo */
|
||||
if (timing->stereo) {
|
||||
|
|
@ -155,12 +196,16 @@ DDCModeFromDetailedTiming(int scrnIndex, struct detailed_timings *timing,
|
|||
if (timing->interlaced)
|
||||
Mode->Flags |= V_INTERLACE;
|
||||
|
||||
if (timing->misc & 0x02)
|
||||
misc = timing->misc;
|
||||
if (quirks & DDC_QUIRK_DT_SYNC_INVERT)
|
||||
misc ^= 0x3;
|
||||
|
||||
if (misc & 0x02)
|
||||
Mode->Flags |= V_PHSYNC;
|
||||
else
|
||||
Mode->Flags |= V_NHSYNC;
|
||||
|
||||
if (timing->misc & 0x01)
|
||||
if (misc & 0x01)
|
||||
Mode->Flags |= V_PVSYNC;
|
||||
else
|
||||
Mode->Flags |= V_NVSYNC;
|
||||
|
|
@ -172,18 +217,23 @@ DisplayModePtr
|
|||
xf86DDCGetModes(int scrnIndex, xf86MonPtr DDC)
|
||||
{
|
||||
int preferred, i;
|
||||
DisplayModePtr Modes = NULL, Mode;
|
||||
DisplayModePtr Modes = NULL, Mode;
|
||||
ddc_quirk_t quirks;
|
||||
|
||||
xf86DrvMsg (scrnIndex, X_INFO, "EDID vendor \"%s\", prod id %d\n",
|
||||
DDC->vendor.name, DDC->vendor.prod_id);
|
||||
quirks = DDC_QUIRK_NONE;
|
||||
for (i = 0; ddc_quirks[i].detect; i++)
|
||||
if (ddc_quirks[i].detect (scrnIndex, DDC))
|
||||
{
|
||||
xf86DrvMsg (scrnIndex, X_INFO, " EDID quirk: %s\n",
|
||||
ddc_quirks[i].description);
|
||||
quirks |= ddc_quirks[i].quirk;
|
||||
}
|
||||
|
||||
|
||||
preferred = PREFERRED_TIMING_MODE(DDC->features.msc);
|
||||
|
||||
/* Add established timings */
|
||||
Mode = DDCModesFromEstablished(scrnIndex, &DDC->timings1);
|
||||
Modes = xf86ModesAdd(Modes, Mode);
|
||||
|
||||
/* Add standard timings */
|
||||
Mode = DDCModesFromStandardTiming(scrnIndex, DDC->timings2);
|
||||
Modes = xf86ModesAdd(Modes, Mode);
|
||||
|
||||
for (i = 0; i < DET_TIMINGS; i++) {
|
||||
struct detailed_monitor_section *det_mon = &DDC->det_mon[i];
|
||||
|
||||
|
|
@ -191,13 +241,15 @@ xf86DDCGetModes(int scrnIndex, xf86MonPtr DDC)
|
|||
case DT:
|
||||
Mode = DDCModeFromDetailedTiming(scrnIndex,
|
||||
&det_mon->section.d_timings,
|
||||
preferred);
|
||||
preferred,
|
||||
quirks);
|
||||
preferred = 0;
|
||||
Modes = xf86ModesAdd(Modes, Mode);
|
||||
break;
|
||||
case DS_STD_TIMINGS:
|
||||
Mode = DDCModesFromStandardTiming(scrnIndex,
|
||||
det_mon->section.std_t);
|
||||
det_mon->section.std_t,
|
||||
quirks);
|
||||
Modes = xf86ModesAdd(Modes, Mode);
|
||||
break;
|
||||
default:
|
||||
|
|
@ -205,6 +257,14 @@ xf86DDCGetModes(int scrnIndex, xf86MonPtr DDC)
|
|||
}
|
||||
}
|
||||
|
||||
/* Add established timings */
|
||||
Mode = DDCModesFromEstablished(scrnIndex, &DDC->timings1, quirks);
|
||||
Modes = xf86ModesAdd(Modes, Mode);
|
||||
|
||||
/* Add standard timings */
|
||||
Mode = DDCModesFromStandardTiming(scrnIndex, DDC->timings2, quirks);
|
||||
Modes = xf86ModesAdd(Modes, Mode);
|
||||
|
||||
return Modes;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue