aboutsummaryrefslogtreecommitdiff
path: root/xorg-server/hw/xfree86/ddc
diff options
context:
space:
mode:
Diffstat (limited to 'xorg-server/hw/xfree86/ddc')
-rw-r--r--xorg-server/hw/xfree86/ddc/edid.h97
-rw-r--r--xorg-server/hw/xfree86/ddc/interpret_edid.c375
-rw-r--r--xorg-server/hw/xfree86/ddc/print_edid.c264
-rw-r--r--xorg-server/hw/xfree86/ddc/xf86DDC.h50
4 files changed, 562 insertions, 224 deletions
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 *);
@@ -53,11 +55,25 @@ 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