--- hw/xfree86/ddc/edid.h | 101 ++++++++++++++++++++++++- hw/xfree86/ddc/interpret_edid.c | 102 ++++++++++++++++++++++++- hw/xfree86/ddc/print_edid.c | 9 +- hw/xfree86/ddc/xf86DDC.c | 41 +++++++--- hw/xfree86/ddc/xf86DDC.h | 4 + hw/xfree86/modes/xf86Crtc.c | 2 hw/xfree86/modes/xf86EdidModes.c | 114 +++++++++++++++++++++++++++-- 7 files changed, 342 insertions(+), 31 deletions(-) --- xserver.orig/hw/xfree86/ddc/edid.h +++ xserver/hw/xfree86/ddc/edid.h @@ -20,7 +20,7 @@ #define STD_TIMINGS 8 #define DET_TIMINGS 4 - +#define EDID_DET_NAME_LEN 13 #ifdef _PARSE_EDID_ /* header: 0x00 0xFF 0xFF 0xFF 0xFF 0xFF 0xFF 0x00 */ @@ -519,9 +519,9 @@ struct detailed_monitor_section { int type; union { struct detailed_timings d_timings; /* 56 */ - Uchar serial[13]; - Uchar ascii_data[13]; - Uchar name[13]; + Uchar serial[EDID_DET_NAME_LEN]; + Uchar ascii_data[EDID_DET_NAME_LEN]; + Uchar name[EDID_DET_NAME_LEN]; struct monitor_ranges ranges; /* 56 */ struct std_timings std_t[5]; /* 80 */ struct whitePoints wp[2]; /* 32 */ @@ -533,6 +533,96 @@ struct detailed_monitor_section { /* flags */ #define EDID_COMPLETE_RAWDATA 0x1 +#define EDID_CEA_EXTENSION_FLG 0x2 + +#define CEA_EXT 2 +#define CEA_EXT_MIN_DATA_OFFSET 4 +#define CEA_EXT_MAX_DATA_OFFSET 127 + +#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_OFFSET(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) + +#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_blk { + Uchar video_code; /* point to raw EDID data block */ +}__attribute__ ((packed)); + + +struct cea_audio_blk { + Uchar descs[3]; +}__attribute__ ((packed)); +struct hdmi { + Uchar Support_flags; + Uchar Max_TMDS_Clock; + Uchar Latency_Present; + Uchar Video_Latency; + Uchar Audio_Latency; + Uchar Interlaced_Video_Latency; + Uchar Interlaced_Audio_Latency; + +}__attribute__ ((packed)); +struct cea_vendor_blk { + unsigned char ieee_id[3]; + Uchar Port_Addr[2]; + struct hdmi hdmi; +}__attribute__ ((packed)); + +struct cea_speaker_blk +{ + 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 Resv_Byte; +}__attribute__ ((packed)); + +struct cea_data_blk { + Uchar len:5; + Uchar tag:3; +union{ + struct cea_video_blk video; + struct cea_audio_blk audio; + struct cea_vendor_blk vendor; + struct cea_speaker_blk speaker; + }u; +}__attribute__ ((packed)); +struct cea_ext { + Uchar tag; + Uchar rev; + Uchar dt_offset; + Uchar flags; + struct cea_data_blk data_collection; +}__attribute__ ((packed)); +struct extension_block { + union{ + struct cea_ext cea; + }u; +}__attribute__ ((packed)); +struct extension_type { + int body_type; + int data_type; +}__attribute__ ((packed)); typedef struct { int scrnIndex; @@ -541,7 +631,8 @@ typedef struct { struct disp_features features; struct established_timings timings1; struct std_timings timings2[8]; - struct detailed_monitor_section det_mon[4]; + struct detailed_monitor_section det_mon[10]; + int det_mon_num; unsigned long flags; int no_sections; Uchar *rawData; --- xserver.orig/hw/xfree86/ddc/interpret_edid.c +++ xserver/hw/xfree86/ddc/interpret_edid.c @@ -42,7 +42,7 @@ static void get_established_timing_secti static void get_std_timing_section(Uchar*, struct std_timings *, struct edid_version *); static void get_dt_md_section(Uchar *, struct edid_version *, - struct detailed_monitor_section *det_mon); + struct detailed_monitor_section *det_mon,int det_mon_num); static void copy_string(Uchar *, Uchar *); static void get_dst_timing_section(Uchar *, struct std_timings *, struct edid_version *); @@ -64,10 +64,10 @@ 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++) { + for (i = 0; i < m->det_mon_num; i++) { if (m->det_mon[i].type == DS_RANGES) { ranges = &m->det_mon[i].section.ranges; - for (j = 0; j < 4; j++) { + for (j = 0; j < m->det_mon_num; 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 */ @@ -99,7 +99,7 @@ handle_edid_quirks(xf86MonPtr m) float target_aspect, timing_aspect; target_aspect = (float)m->features.hsize / (float)m->features.vsize; - for (i = 0; i < 4; i++) { + for (i = 0; i < m->det_mon_num; i++) { if (m->det_mon[i].type == DT) { struct detailed_timings *timing; timing = &m->det_mon[i].section.d_timings; @@ -132,6 +132,79 @@ handle_edid_quirks(xf86MonPtr m) } } +Uchar * xf86DDCGetCEA(xf86MonPtr MonPtr, struct extension_type *type) +{ + struct extension_block *blk; + struct cea_ext *cea_blk; + struct cea_data_blk *data_collection; + Uchar *ret; + int data_len ; + int data_type; + int i; + + ret = NULL; + blk = (struct extension_block *) (MonPtr->rawData + EDID1_LEN) ; + + for (i = 0; i < MonPtr->no_sections; i++) { + + if (CEA_EXT == blk ->u.cea.tag) { + ret = (Uchar *)&blk->u.cea; + if (CEA_EXT == type->body_type && 0 == type->data_type) { + goto end; + } + break; + } + blk =(struct extension_block *) ((Uchar * )blk + EDID1_LEN); + } + + if (NULL == ret) + goto end; + + cea_blk = (struct cea_ext *)ret; + + ret = NULL; + + if (CEA_EXT_MIN_DATA_OFFSET >= cea_blk->dt_offset) + goto end; + + data_collection = &cea_blk->data_collection ; + data_len = 0; + while (data_len < cea_blk->dt_offset) { + if (type->data_type == data_collection->tag) { + ret = (unsigned char *)data_collection; + goto end; + } + data_len = data_len + data_collection->len + 1; + data_collection = (unsigned char *)data_collection + data_len ; + } + + +end: + return ret; +} + +static void get_cea_detail_timing(xf86MonPtr m, Uchar *blk ) +{ + int dt_offset = ((struct cea_ext *)blk)->dt_offset; + + if (CEA_EXT_MIN_DATA_OFFSET < dt_offset) { + goto end; + } + + while (dt_offset < (CEA_EXT_MAX_DATA_OFFSET - DET_TIMING_INFO_LEN )) { + + get_dt_md_section(blk + dt_offset, &m->ver, + m->det_mon + m->det_mon_num, 1); + + m->det_mon_num = m->det_mon_num + 1 ; + + _NEXT_DT_MD_SECTION(dt_offset); + } + +end: + return; +} + xf86MonPtr xf86InterpretEDID(int scrnIndex, Uchar *block) { @@ -151,9 +224,24 @@ xf86InterpretEDID(int scrnIndex, Uchar * &m->timings1); get_std_timing_section(SECTION(STD_TIMING_SECTION,block),m->timings2, &m->ver); - get_dt_md_section(SECTION(DET_TIMING_SECTION,block),&m->ver, m->det_mon); + get_dt_md_section(SECTION(DET_TIMING_SECTION,block),&m->ver, m->det_mon,4); + m->det_mon_num = 4; m->no_sections = (int)*(char *)SECTION(NO_EDID,block); + + if (0 != m->no_sections) { + unsigned char *blk; + struct extension_type type; + + type.body_type = CEA_EXT; + type.data_type = 0; + blk = xf86DDCGetCEA(m, &type) ; + if (NULL != blk) { + get_cea_detail_timing(m, blk); + m->flags = EDID_CEA_EXTENSION_FLG; + } + } + handle_edid_quirks(m); return (m); @@ -286,11 +374,11 @@ get_std_timing_section(Uchar *c, struct static void get_dt_md_section(Uchar *c, struct edid_version *ver, - struct detailed_monitor_section *det_mon) + struct detailed_monitor_section *det_mon,int det_mon_num) { int i; - for (i=0;iversion == 1 && ver->revision >= 1 && IS_MONITOR_DESC) { switch (MONITOR_DESC_TYPE) { --- xserver.orig/hw/xfree86/ddc/print_edid.c +++ xserver/hw/xfree86/ddc/print_edid.c @@ -335,11 +335,12 @@ print_detailed_timings(int scrnIndex, st static void print_detailed_monitor_section(int scrnIndex, - struct detailed_monitor_section *m) + struct detailed_monitor_section *m, + int det_mon_num) { int i,j; - for (i=0;iscrnIndex, &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); + print_detailed_monitor_section(m->scrnIndex, m->det_mon, m->det_mon_num); print_number_sections(m->scrnIndex, m->no_sections); /* extension block section stuff */ - xf86DrvMsg(m->scrnIndex, X_INFO, "EDID (in hex):\n"); + xf86DrvMsg(m->scrnIndex, X_INFO, "EDID (in hex): flags is <%d>\n",m->no_sections); n = 128; if (m->flags & EDID_COMPLETE_RAWDATA) --- xserver.orig/hw/xfree86/ddc/xf86DDC.c +++ xserver/hw/xfree86/ddc/xf86DDC.c @@ -213,6 +213,7 @@ xf86DoEEDID(int scrnIndex, I2CBusPtr pBu unsigned char *EDID_block = NULL; xf86MonPtr tmp = NULL; I2CDevPtr dev = NULL; + int i,n; /* Default DDC and DDC2 to enabled. */ Bool noddc = FALSE, noddc2 = FALSE; OptionInfoPtr options; @@ -237,21 +238,41 @@ xf86DoEEDID(int scrnIndex, I2CBusPtr pBu if (!EDID_block) return NULL; - if (DDC2Read(dev, 0, EDID_block)) { - int i, n = EDID_block[0x7e]; - - if (complete && n) { - EDID_block = xrealloc(EDID_block, EDID1_LEN * (1+n)); - - for (i = 0; i < n; i++) - DDC2Read(dev, i+1, EDID_block + (EDID1_LEN * (1+i))); + if(FALSE == DDC2Read(dev, 0, EDID_block)){ + xfree(EDID_block); + return NULL; + } + + + n = EDID_block[0x7e]; + + if (complete && n) { + int ret; + + EDID_block = xrealloc(EDID_block, EDID1_LEN * (1+n)); + + if (!EDID_block) + return NULL; + + for (i = 0; i < n; i++){ + ret = DDC2Read(dev, i+1, EDID_block + (EDID1_LEN * (1+i))); + if(FALSE == ret){ + xfree(EDID_block); + return NULL; + } } tmp = xf86InterpretEEDID(scrnIndex, EDID_block); - } - if (tmp && complete) + if(NULL == tmp){ + xfree(EDID_block); + return NULL; + } + } + + if (tmp && complete){ tmp->flags |= EDID_COMPLETE_RAWDATA; + } return tmp; } --- xserver.orig/hw/xfree86/ddc/xf86DDC.h +++ xserver/hw/xfree86/ddc/xf86DDC.h @@ -44,6 +44,10 @@ extern xf86MonPtr xf86PrintEDID( extern xf86MonPtr xf86InterpretEDID( int screenIndex, Uchar *block ); +extern unsigned char * xf86DDCGetCEA( + xf86MonPtr MonPtr, + struct extension_type *type +); extern xf86MonPtr xf86InterpretEEDID( int screenIndex, Uchar *block --- xserver.orig/hw/xfree86/modes/xf86Crtc.c +++ xserver/hw/xfree86/modes/xf86Crtc.c @@ -2683,7 +2683,7 @@ xf86OutputSetEDID (xf86OutputPtr output, if (edid_mon) { /* Pull out a phyiscal size from a detailed timing if available. */ - for (i = 0; i < 4; i++) { + for (i = 0; i < edid_mon->det_mon_num; i++) { if (edid_mon->det_mon[i].type == DT && edid_mon->det_mon[i].section.d_timings.h_size != 0 && edid_mon->det_mon[i].section.d_timings.v_size != 0) --- xserver.orig/hw/xfree86/modes/xf86EdidModes.c +++ xserver/hw/xfree86/modes/xf86EdidModes.c @@ -51,7 +51,7 @@ xf86MonitorSupportsReducedBlanking(xf86M /* EDID 1.4 explicitly defines RB support */ if (DDC->ver.revision >= 4) { int i; - for (i = 0; i < DET_TIMINGS; i++) { + for (i = 0; i < DDC->det_mon_num; 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) @@ -498,6 +498,107 @@ DDCModesFromStandardTiming(struct std_ti return Modes; } +#define CEA_VIDEO_MODES_NUM 64 +static const DisplayModeRec CEAVideoModes[CEA_VIDEO_MODES_NUM] = { + { MODEPREFIX, 25175, 640, 656, 752, 800, 0, 480, 490, 492, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 1:640x480@60Hz */ + { MODEPREFIX, 27000, 720, 736, 798, 858, 0, 480, 489, 495, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 2:720x480@60Hz */ + { MODEPREFIX, 27000, 720, 736, 798, 858, 0, 480, 489, 495, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 3:720x480@60Hz */ + { MODEPREFIX, 74250, 1280, 1390, 1430, 1650, 0, 720, 725, 730, 750, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 4: 1280x720@60Hz */ + { MODEPREFIX, 74250, 1920, 2008, 2052, 2200, 0, 1080, 1084, 1094, 1125, 0, V_PHSYNC | V_PVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 5:1920x1080i@60Hz */ + { MODEPREFIX, 27000, 1440, 1478, 1602, 1716, 0, 480, 488, 494, 525, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 6:1440x480i@60Hz */ + { MODEPREFIX, 27000, 1440, 1478, 1602, 1716, 0, 480, 488, 494, 525, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 7:1440x480i@60Hz */ + { MODEPREFIX, 27000, 1440, 1478, 1602, 1716, 0, 240, 244, 247, 262, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 8:1440x240@60Hz */ + { MODEPREFIX, 27000, 1440, 1478, 1602, 1716, 0, 240, 244, 247, 262, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 9:1440x240@60Hz */ + { MODEPREFIX, 54000, 2880, 2956, 3204, 3432, 0, 480, 488, 494, 525, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 10:2880x480i@60Hz */ + { MODEPREFIX, 54000, 2880, 2956, 3204, 3432, 0, 480, 488, 494, 525, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 11:2880x480i@60Hz */ + { MODEPREFIX, 54000, 2880, 2956, 3204, 3432, 0, 240, 244, 247, 262, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 12:2880x240@60Hz */ + { MODEPREFIX, 54000, 2880, 2956, 3204, 3432, 0, 240, 244, 247, 262, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 13:2880x240@60Hz */ + { MODEPREFIX, 54000, 1440, 1472, 1596, 1716, 0, 480, 489, 495, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 14:1440x480@60Hz */ + { MODEPREFIX, 54000, 1440, 1472, 1596, 1716, 0, 480, 489, 495, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 15:1440x480@60Hz */ + { MODEPREFIX, 148500, 1920, 2008, 2052, 2200, 0, 1080, 1084, 1089, 1125, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 16:1920x1080@60Hz */ + { MODEPREFIX, 27000, 720, 732, 796, 864, 0, 576, 581, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 17:720x576@50Hz */ + { MODEPREFIX, 27000, 720, 732, 796, 864, 0, 576, 581, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 18:720x576@50Hz */ + { MODEPREFIX, 74250, 1280, 1720, 1760, 1980, 0, 720, 725, 730, 750, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 19: 1280x720@50Hz */ + { MODEPREFIX, 74250, 1920, 2448, 2492, 2640, 0, 1080, 1084, 1094, 1125, 0, V_PHSYNC | V_PVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 20:1920x1080i@50Hz */ + { MODEPREFIX, 27000, 1440, 1464, 1590, 1728, 0, 576, 580, 586, 625, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 21:1440x576i@50Hz */ + { MODEPREFIX, 27000, 1440, 1464, 1590, 1728, 0, 576, 580, 586, 625, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 22:1440x576i@50Hz */ + { MODEPREFIX, 27000, 1440, 1464, 1590, 1728, 0, 288, 290, 293, 312, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 23:1440x288@50Hz */ + { MODEPREFIX, 27000, 1440, 1464, 1590, 1728, 0, 288, 290, 293, 312, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 24:1440x288@50Hz */ + { MODEPREFIX, 54000, 2880, 2928, 3180, 3456, 0, 576, 580, 586, 625, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 25:2880x576i@50Hz */ + { MODEPREFIX, 54000, 2880, 2928, 3180, 3456, 0, 576, 580, 586, 625, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 26:2880x576i@50Hz */ + { MODEPREFIX, 54000, 2880, 2928, 3180, 3456, 0, 288, 290, 293, 312, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 27:2880x288@50Hz */ + { MODEPREFIX, 54000, 2880, 2928, 3180, 3456, 0, 288, 290, 293, 312, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 28:2880x288@50Hz */ + { MODEPREFIX, 54000, 1440, 1464, 1592, 1728, 0, 576, 581, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 29:1440x576@50Hz */ + { MODEPREFIX, 54000, 1440, 1464, 1592, 1728, 0, 576, 581, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 30:1440x576@50Hz */ + { MODEPREFIX, 148500, 1920, 2448, 2492, 2640, 0, 1080, 1084, 1089, 1125, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 31:1920x1080@50Hz */ + { MODEPREFIX, 74250, 1920, 2558, 2602, 2750, 0, 1080, 1084, 1089, 1125, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 32:1920x1080@24Hz */ + { MODEPREFIX, 74250, 1920, 2448, 2492, 2640, 0, 1080, 1084, 1089, 1125, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 33:1920x1080@25Hz */ + { MODEPREFIX, 74250, 1920, 2008, 2052, 2200, 0, 1080, 1084, 1089, 1125, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 34:1920x1080@30Hz */ + { MODEPREFIX, 108000, 2880, 2944, 3192, 3432, 0, 480, 489, 495, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 35:2880x480@60Hz */ + { MODEPREFIX, 108000, 2880, 2944, 3192, 3432, 0, 480, 489, 495, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 36:2880x480@60Hz */ + { MODEPREFIX, 108000, 2880, 2928, 3184, 3456, 0, 576, 581, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 37:2880x576@50Hz */ + { MODEPREFIX, 108000, 2880, 2928, 3184, 3456, 0, 576, 581, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 38:2880x576@50Hz */ + { MODEPREFIX, 72000, 1920, 1952, 2120, 2304, 0, 1080, 1126, 1136, 1250, 0, V_PHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 39:1920x1080i@50Hz */ + { MODEPREFIX, 148500, 1920, 2448, 2492, 2640, 0, 1080, 1084, 1094, 1125, 0, V_PHSYNC | V_PVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 40:1920x1080i@100Hz */ + { MODEPREFIX, 148500, 1280, 1720, 1760, 1980, 0, 720, 725, 730, 750, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 41:1280x720@100Hz */ + { MODEPREFIX, 54000, 720, 732, 796, 864, 0, 576, 581, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 42:720x576@100Hz */ + { MODEPREFIX, 54000, 720, 732, 796, 864, 0, 576, 581, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 43:720x576@100Hz */ + { MODEPREFIX, 54000, 1440, 1464, 1590, 1728, 0, 576, 580, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 44:1440x576i@100Hz */ + { MODEPREFIX, 54000, 1440, 1464, 1590, 1728, 0, 576, 580, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 45:1440x576i@100Hz */ + { MODEPREFIX, 148500, 1920, 2008, 2052, 2200, 0, 1080, 1084, 1094, 1125, 0, V_PHSYNC | V_PVSYNC | V_INTERLACE, MODESUFFIX }, /* VIC 46:1920x1080i@120Hz */ + { MODEPREFIX, 148500, 1280, 1390, 1430, 1650, 0, 720, 725, 730, 750, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 47:1280x720@120Hz */ + { MODEPREFIX, 54000, 720, 736, 798, 858, 0, 480, 489, 495, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 48:720x480@120Hz */ + { MODEPREFIX, 54000, 720, 736, 798, 858, 0, 480, 489, 495, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 49:720x480@120Hz */ + { MODEPREFIX, 54000, 1440, 1478, 1602, 1716, 0, 480, 488, 494, 525, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX },/* VIC 50:1440x480i@120Hz */ + { MODEPREFIX, 54000, 1440, 1478, 1602, 1716, 0, 480, 488, 494, 525, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX },/* VIC 51:1440x480i@120Hz */ + { MODEPREFIX, 108000, 720, 732, 796, 864, 0, 576, 581, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 52:720x576@200Hz */ + { MODEPREFIX, 108000, 720, 732, 796, 864, 0, 576, 581, 586, 625, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 53:720x576@200Hz */ + { MODEPREFIX, 108000, 1440, 1464, 1590, 1728, 0, 576, 580, 586, 625, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX },/* VIC 54:1440x576i@200Hz */ + { MODEPREFIX, 108000, 1440, 1464, 1590, 1728, 0, 576, 580, 586, 625, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX },/* VIC 55:1440x576i@200Hz */ + { MODEPREFIX, 108000, 720, 736, 798, 858, 0, 480, 489, 495, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 56:720x480@240Hz */ + { MODEPREFIX, 108000, 720, 736, 798, 858, 0, 480, 489, 495, 525, 0, V_NHSYNC | V_NVSYNC, MODESUFFIX }, /* VIC 57:720x480@240Hz */ + { MODEPREFIX, 108000, 1440, 1478, 1602, 1716, 0, 480, 488, 494, 525, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX },/* VIC 58:1440x480i@240 */ + { MODEPREFIX, 108000, 1440, 1478, 1602, 1716, 0, 480, 488, 494, 525, 0, V_NHSYNC | V_NVSYNC | V_INTERLACE, MODESUFFIX },/* VIC 59:1440x480i@240 */ + { MODEPREFIX, 59400, 1280, 3040, 3080, 3300, 0, 720, 725, 730, 750, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 60: 1280x720@24Hz */ + { MODEPREFIX, 74250, 3700, 3740, 1430, 3960, 0, 720, 725, 730, 750, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 61: 1280x720@25Hz */ + { MODEPREFIX, 74250, 1280, 3040, 3080, 3300, 0, 720, 725, 730, 750, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 62: 1280x720@30Hz */ + { MODEPREFIX, 297000, 1920, 2008, 2052, 2200, 0, 1080, 1084, 1089, 1125, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 63: 1920x1080@120Hz */ + { MODEPREFIX, 297000, 1920, 2448, 2492, 2640, 0, 1080, 1084, 1094, 1125, 0, V_PHSYNC | V_PVSYNC, MODESUFFIX }, /* VIC 64:1920x1080@100Hz */ +}; + +static DisplayModePtr +DDCModesFromCeaExtension(int idx, xf86MonPtr MonPtr) +{ + DisplayModePtr Modes = NULL, Mode = NULL; + struct extension_type type; + struct cea_data_blk *data_collection; + struct cea_video_blk *video; + int num ; + int vid; + + type.body_type = CEA_EXT ; + type.data_type = CEA_VIDEO_BLK; + + data_collection = (struct cea_data_blk *)xf86DDCGetCEA(MonPtr, &type); + if (NULL == data_collection) + goto end; + + video = &data_collection->u.video; + num = 0; + + while (num < (data_collection->len/sizeof(struct cea_video_blk))) { + vid = video[num].video_code & 0x7f; + + if(vid < CEA_VIDEO_MODES_NUM){ + Mode = xf86DuplicateMode(CEAVideoModes + vid ); + Modes = xf86ModesAdd(Modes, Mode); + } + num = num + 1; + } + +end: + return Modes; +} /* * @@ -699,7 +800,7 @@ xf86DDCApplyQuirks(int scrnIndex, xf86Mo ddc_quirk_t quirks = xf86DDCDetectQuirks (scrnIndex, DDC, FALSE); int i; - for (i = 0; i < DET_TIMINGS; i++) { + for (i = 0; i < DDC->det_mon_num; i++) { struct detailed_monitor_section *det_mon = &DDC->det_mon[i]; if (det_mon->type != DT) @@ -785,7 +886,7 @@ xf86DDCGetModes(int scrnIndex, xf86MonPt timing_level = MonitorStandardTimingLevel(DDC); - for (i = 0; i < DET_TIMINGS; i++) { + for (i = 0; i < DDC->det_mon_num; i++) { struct detailed_monitor_section *det_mon = &DDC->det_mon[i]; switch (det_mon->type) { @@ -821,6 +922,11 @@ xf86DDCGetModes(int scrnIndex, xf86MonPt Mode = DDCModesFromStandardTiming(DDC->timings2, quirks, timing_level, rb); Modes = xf86ModesAdd(Modes, Mode); + if(EDID_CEA_EXTENSION_FLG & DDC->flags){ + Mode = DDCModesFromCeaExtension(scrnIndex,DDC); + Modes = xf86ModesAdd(Modes, Mode); + } + if (quirks & DDC_QUIRK_PREFER_LARGE_60) xf86DDCSetPreferredRefresh(scrnIndex, Modes, 60); @@ -863,7 +969,7 @@ xf86DDCMonitorSet(int scrnIndex, MonPtr have_maxpixclock = (Monitor->maxPixClock != 0); /* Go through the detailed monitor sections */ - for (i = 0; i < DET_TIMINGS; i++) { + for (i = 0; i < DDC->det_mon_num; i++) { switch (DDC->det_mon[i].type) { case DS_RANGES: if (!have_hsync) {