diff --git a/hw/xfree86/ddc/edid.h b/hw/xfree86/ddc/edid.h index 2e3e7df4f..6708eaaa5 100644 --- a/hw/xfree86/ddc/edid.h +++ b/hw/xfree86/ddc/edid.h @@ -449,17 +449,33 @@ struct whitePoints{ float white_gamma; }; +struct cvt_timings { + int width; + int height; + int rate; + int rates; +}; + +/* + * Be careful when adding new sections; this structure can't grow, it's + * embedded in the middle of xf86Monitor which is ABI. Sizes below are + * in bytes, for ILP32 systems. If all else fails just copy the section + * literally like serial and friends. + */ struct detailed_monitor_section { int type; union { - struct detailed_timings d_timings; + struct detailed_timings d_timings; /* 56 */ Uchar serial[13]; Uchar ascii_data[13]; Uchar name[13]; - struct monitor_ranges ranges; - struct std_timings std_t[5]; - struct whitePoints wp[2]; - } section; + struct monitor_ranges ranges; /* 40 */ + struct std_timings std_t[5]; /* 80 */ + struct whitePoints wp[2]; /* 32 */ + /* color management data */ + struct cvt_timings cvt[4]; /* 64 */ + /* established timings III */ + } section; /* max: 80 */ }; typedef struct { diff --git a/hw/xfree86/ddc/interpret_edid.c b/hw/xfree86/ddc/interpret_edid.c index ecec2b039..982a502fd 100644 --- a/hw/xfree86/ddc/interpret_edid.c +++ b/hw/xfree86/ddc/interpret_edid.c @@ -174,6 +174,34 @@ get_established_timing_section(Uchar *c, struct established_timings *r) r->t_manu = T_MANU; } +static void +get_cvt_timing_section(Uchar *c, struct cvt_timings *r) +{ + int i; + + for (i = 0; i < 4; i++) { + if (c[0] && c[1] && c[2]) { + r[i].height = (c[0] + ((c[1] & 0xF0) << 8) + 1) * 2; + switch (c[1] & 0xc0) { + case 0x00: r[i].width = r[i].height * 4 / 3; break; + case 0x40: r[i].width = r[i].height * 16 / 9; break; + case 0x80: r[i].width = r[i].height * 16 / 10; break; + case 0xc0: r[i].width = r[i].height * 15 / 9; break; + } + switch (c[2] & 0x60) { + case 0x00: r[i].rate = 50; break; + case 0x20: r[i].rate = 60; break; + case 0x40: r[i].rate = 75; break; + case 0x60: r[i].rate = 85; break; + } + r[i].rates = c[2] & 0x1f; + } else { + return; + } + c += 3; + } +} + static void get_std_timing_section(Uchar *c, struct std_timings *r, struct edid_version *v) @@ -232,6 +260,7 @@ get_dt_md_section(Uchar *c, struct edid_version *ver, 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; diff --git a/hw/xfree86/ddc/print_edid.c b/hw/xfree86/ddc/print_edid.c index 17e21aca8..5aebc6e74 100644 --- a/hw/xfree86/ddc/print_edid.c +++ b/hw/xfree86/ddc/print_edid.c @@ -235,6 +235,24 @@ print_std_timings(int scrnIndex, struct std_timings *t) } } } + +static void +print_cvt_timings(int si, struct cvt_timings *t) +{ + int i; + + for (i = 0; i < 4; i++) { + if (t[i].height) { + xf86DrvMsg(si, X_INFO, "%dx%d @ %s%s%s%s%s Hz\n", + t[i].width, t[i].height, + t[i].rates & 0x10 ? "50," : "", + t[i].rates & 0x08 ? "60," : "", + t[i].rates & 0x04 ? "75," : "", + t[i].rates & 0x02 ? "85," : "", + t[i].rates & 0x01 ? "60RB" : ""); + } else break; + } +} static void print_detailed_monitor_section(int scrnIndex, @@ -296,7 +314,8 @@ print_detailed_monitor_section(int scrnIndex, break; case DS_CVT: xf86DrvMsg(scrnIndex, X_INFO, - "CVT 3-byte-code modes: (not decoded)\n"); + "CVT 3-byte-code modes:\n"); + print_cvt_timings(scrnIndex, m[i].section.cvt); break; case DS_EST_III: xf86DrvMsg(scrnIndex, X_INFO, diff --git a/hw/xfree86/modes/xf86EdidModes.c b/hw/xfree86/modes/xf86EdidModes.c index a125d8c82..d8c61617e 100644 --- a/hw/xfree86/modes/xf86EdidModes.c +++ b/hw/xfree86/modes/xf86EdidModes.c @@ -354,6 +354,36 @@ DDCModeFromDetailedTiming(int scrnIndex, struct detailed_timings *timing, return Mode; } +static DisplayModePtr +DDCModesFromCVT(int scrnIndex, struct cvt_timings *t) +{ + DisplayModePtr modes = NULL; + int i; + + for (i = 0; i < 4; i++) { + if (t[i].height) { + if (t[i].rates & 0x10) + modes = xf86ModesAdd(modes, + xf86CVTMode(t[i].width, t[i].height, 50, 0, 0)); + if (t[i].rates & 0x08) + modes = xf86ModesAdd(modes, + xf86CVTMode(t[i].width, t[i].height, 60, 0, 0)); + if (t[i].rates & 0x04) + modes = xf86ModesAdd(modes, + xf86CVTMode(t[i].width, t[i].height, 75, 0, 0)); + if (t[i].rates & 0x02) + modes = xf86ModesAdd(modes, + xf86CVTMode(t[i].width, t[i].height, 85, 0, 0)); + if (t[i].rates & 0x01) + modes = xf86ModesAdd(modes, + xf86CVTMode(t[i].width, t[i].height, 60, 1, 0)); + } else break; + } + + return modes; +} + + /* * */ @@ -527,6 +557,10 @@ xf86DDCGetModes(int scrnIndex, xf86MonPtr DDC) quirks); Modes = xf86ModesAdd(Modes, Mode); break; + case DS_CVT: + Mode = DDCModesFromCVT(scrnIndex, det_mon->section.cvt); + Modes = xf86ModesAdd(Modes, Mode); + break; default: break; }