diff options
Diffstat (limited to 'xorg-server/hw/xfree86/ddc')
-rw-r--r-- | xorg-server/hw/xfree86/ddc/edid.h | 97 | ||||
-rw-r--r-- | xorg-server/hw/xfree86/ddc/interpret_edid.c | 375 | ||||
-rw-r--r-- | xorg-server/hw/xfree86/ddc/print_edid.c | 264 | ||||
-rw-r--r-- | xorg-server/hw/xfree86/ddc/xf86DDC.h | 50 |
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 |