EDID: CEA extension support
Reviewed-by: Adam Jackson <ajax@redhat.com>
This commit is contained in:
parent
fab74d1081
commit
fc2ec95664
|
@ -544,6 +544,36 @@ configureMonitorSection (int screennum)
|
|||
return ptr;
|
||||
}
|
||||
|
||||
/* Initialize Configure Monitor from Detailed Timing Block */
|
||||
static void handle_detailed_input(struct detailed_monitor_section *det_mon,
|
||||
void *data)
|
||||
{
|
||||
XF86ConfMonitorPtr ptr = (XF86ConfMonitorPtr) data;
|
||||
|
||||
switch (det_mon->type) {
|
||||
case DS_NAME:
|
||||
ptr->mon_modelname = realloc(ptr->mon_modelname,
|
||||
strlen((char*)(det_mon->section.name)) +
|
||||
1);
|
||||
strcpy(ptr->mon_modelname,
|
||||
(char*)(det_mon->section.name));
|
||||
break;
|
||||
case DS_RANGES:
|
||||
ptr->mon_hsync[ptr->mon_n_hsync].lo =
|
||||
det_mon->section.ranges.min_h;
|
||||
ptr->mon_hsync[ptr->mon_n_hsync].hi =
|
||||
det_mon->section.ranges.max_h;
|
||||
ptr->mon_n_vrefresh = 1;
|
||||
ptr->mon_vrefresh[ptr->mon_n_hsync].lo =
|
||||
det_mon->section.ranges.min_v;
|
||||
ptr->mon_vrefresh[ptr->mon_n_hsync].hi =
|
||||
det_mon->section.ranges.max_v;
|
||||
ptr->mon_n_hsync++;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static XF86ConfMonitorPtr
|
||||
configureDDCMonitorSection (int screennum)
|
||||
{
|
||||
|
@ -590,30 +620,8 @@ configureDDCMonitorSection (int screennum)
|
|||
}
|
||||
#endif /* def CONFIGURE_DISPLAYSIZE */
|
||||
|
||||
for (i=0;i<4;i++) {
|
||||
switch (ConfiguredMonitor->det_mon[i].type) {
|
||||
case DS_NAME:
|
||||
ptr->mon_modelname = realloc(ptr->mon_modelname,
|
||||
strlen((char*)(ConfiguredMonitor->det_mon[i].section.name))
|
||||
+ 1);
|
||||
strcpy(ptr->mon_modelname,
|
||||
(char*)(ConfiguredMonitor->det_mon[i].section.name));
|
||||
break;
|
||||
case DS_RANGES:
|
||||
ptr->mon_hsync[ptr->mon_n_hsync].lo =
|
||||
ConfiguredMonitor->det_mon[i].section.ranges.min_h;
|
||||
ptr->mon_hsync[ptr->mon_n_hsync].hi =
|
||||
ConfiguredMonitor->det_mon[i].section.ranges.max_h;
|
||||
ptr->mon_n_vrefresh = 1;
|
||||
ptr->mon_vrefresh[ptr->mon_n_hsync].lo =
|
||||
ConfiguredMonitor->det_mon[i].section.ranges.min_v;
|
||||
ptr->mon_vrefresh[ptr->mon_n_hsync].hi =
|
||||
ConfiguredMonitor->det_mon[i].section.ranges.max_v;
|
||||
ptr->mon_n_hsync++;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
xf86ForEachDetailedBlock(ConfiguredMonitor, handle_detailed_input,
|
||||
ptr);
|
||||
|
||||
if (ConfiguredMonitor->features.dpms) {
|
||||
ptr->mon_option_lst = xf86addNewOption(ptr->mon_option_lst, xstrdup("DPMS"), NULL);
|
||||
|
|
|
@ -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_ */
|
||||
|
|
|
@ -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 *);
|
||||
|
@ -52,12 +54,26 @@ static void get_whitepoint_section(Uchar *, struct whitePoints *);
|
|||
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;
|
||||
struct det_hv_parameter p;
|
||||
p.real_hsize = 0;
|
||||
p.real_vsize = 0;
|
||||
p.target_aspect = (float)m->features.hsize /m->features.vsize;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
xf86ForEachDetailedBlock(m, handle_detailed_hvsize, &p);
|
||||
|
||||
if (!real_hsize || !real_vsize) {
|
||||
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,
|
||||
fetch_detailed_block(Uchar *c, struct edid_version *ver,
|
||||
struct detailed_monitor_section *det_mon)
|
||||
{
|
||||
if (ver->version == 1 && ver->revision >= 1 && IS_MONITOR_DESC) {
|
||||
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->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++) {
|
||||
if (ver->version == 1 && ver->revision >= 1 && IS_MONITOR_DESC) {
|
||||
int i;
|
||||
|
||||
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];
|
||||
}
|
||||
} else {
|
||||
det_mon[i].type = DT;
|
||||
get_detailed_timing_section(c,&det_mon[i].section.d_timings);
|
||||
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
|
||||
|
|
|
@ -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;
|
||||
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);
|
||||
}
|
||||
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,
|
||||
"#%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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1523,6 +1523,42 @@ GuessRangeFromModes(MonPtr mon, DisplayModePtr mode)
|
|||
mon->vrefresh[0].lo = 58.0;
|
||||
}
|
||||
|
||||
struct det_monrec_parameter {
|
||||
MonRec *mon_rec;
|
||||
int *max_clock;
|
||||
Bool set_hsync;
|
||||
Bool set_vrefresh;
|
||||
enum { sync_config, sync_edid, sync_default } *sync_source;
|
||||
};
|
||||
|
||||
static void handle_detailed_monrec(struct detailed_monitor_section *det_mon,
|
||||
void *data)
|
||||
{
|
||||
enum { sync_config, sync_edid, sync_default };
|
||||
struct det_monrec_parameter *p;
|
||||
p = (struct det_monrec_parameter *)data;
|
||||
|
||||
if (det_mon->type == DS_RANGES) {
|
||||
struct monitor_ranges *ranges = &det_mon->section.ranges;
|
||||
if (p->set_hsync && ranges->max_h) {
|
||||
p->mon_rec->hsync[p->mon_rec->nHsync].lo = ranges->min_h;
|
||||
p->mon_rec->hsync[p->mon_rec->nHsync].hi = ranges->max_h;
|
||||
p->mon_rec->nHsync++;
|
||||
if (*p->sync_source == sync_default)
|
||||
*p->sync_source = sync_edid;
|
||||
}
|
||||
if (p->set_vrefresh && ranges->max_v) {
|
||||
p->mon_rec->vrefresh[p->mon_rec->nVrefresh].lo = ranges->min_v;
|
||||
p->mon_rec->vrefresh[p->mon_rec->nVrefresh].hi = ranges->max_v;
|
||||
p->mon_rec->nVrefresh++;
|
||||
if (*p->sync_source == sync_default)
|
||||
*p->sync_source = sync_edid;
|
||||
}
|
||||
if (ranges->max_clock * 1000 > *p->max_clock)
|
||||
*p->max_clock = ranges->max_clock * 1000;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
xf86ProbeOutputModes (ScrnInfoPtr scrn, int maxX, int maxY)
|
||||
{
|
||||
|
@ -1601,42 +1637,24 @@ xf86ProbeOutputModes (ScrnInfoPtr scrn, int maxX, int maxY)
|
|||
|
||||
edid_monitor = output->MonInfo;
|
||||
|
||||
if (edid_monitor)
|
||||
{
|
||||
int i;
|
||||
Bool set_hsync = mon_rec.nHsync == 0;
|
||||
Bool set_vrefresh = mon_rec.nVrefresh == 0;
|
||||
struct disp_features *features = &edid_monitor->features;
|
||||
if (edid_monitor)
|
||||
{
|
||||
struct det_monrec_parameter p;
|
||||
struct disp_features *features = &edid_monitor->features;
|
||||
|
||||
/* if display is not continuous-frequency, don't add default modes */
|
||||
if (!GTF_SUPPORTED(features->msc))
|
||||
add_default_modes = FALSE;
|
||||
|
||||
for (i = 0; i < sizeof (edid_monitor->det_mon) / sizeof (edid_monitor->det_mon[0]); i++)
|
||||
{
|
||||
if (edid_monitor->det_mon[i].type == DS_RANGES)
|
||||
{
|
||||
struct monitor_ranges *ranges = &edid_monitor->det_mon[i].section.ranges;
|
||||
if (set_hsync && ranges->max_h)
|
||||
{
|
||||
mon_rec.hsync[mon_rec.nHsync].lo = ranges->min_h;
|
||||
mon_rec.hsync[mon_rec.nHsync].hi = ranges->max_h;
|
||||
mon_rec.nHsync++;
|
||||
if (sync_source == sync_default)
|
||||
sync_source = sync_edid;
|
||||
}
|
||||
if (set_vrefresh && ranges->max_v)
|
||||
{
|
||||
mon_rec.vrefresh[mon_rec.nVrefresh].lo = ranges->min_v;
|
||||
mon_rec.vrefresh[mon_rec.nVrefresh].hi = ranges->max_v;
|
||||
mon_rec.nVrefresh++;
|
||||
if (sync_source == sync_default)
|
||||
sync_source = sync_edid;
|
||||
}
|
||||
if (ranges->max_clock * 1000 > max_clock)
|
||||
max_clock = ranges->max_clock * 1000;
|
||||
}
|
||||
}
|
||||
p.mon_rec = &mon_rec;
|
||||
p.max_clock = &max_clock;
|
||||
p.set_hsync = mon_rec.nHsync == 0;
|
||||
p.set_vrefresh = mon_rec.nVrefresh == 0;
|
||||
p.sync_source = &sync_source;
|
||||
|
||||
xf86ForEachDetailedBlock(edid_monitor,
|
||||
handle_detailed_monrec,
|
||||
&p);
|
||||
}
|
||||
|
||||
if (xf86GetOptValFreq (output->options, OPTION_MIN_CLOCK,
|
||||
|
@ -2900,6 +2918,35 @@ xf86OutputSetEDIDProperty (xf86OutputPtr output, void *data, int data_len)
|
|||
|
||||
#endif
|
||||
|
||||
/* Pull out a phyiscal size from a detailed timing if available. */
|
||||
struct det_phySize_parameter {
|
||||
xf86OutputPtr output;
|
||||
ddc_quirk_t quirks;
|
||||
Bool ret;
|
||||
};
|
||||
|
||||
static void handle_detailed_physical_size(struct detailed_monitor_section
|
||||
*det_mon, void *data)
|
||||
{
|
||||
struct det_phySize_parameter *p;
|
||||
p = (struct det_phySize_parameter *)data;
|
||||
|
||||
if (p->ret == TRUE )
|
||||
return ;
|
||||
|
||||
xf86DetTimingApplyQuirks(det_mon, p->quirks,
|
||||
p->output->MonInfo->features.hsize,
|
||||
p->output->MonInfo->features.vsize);
|
||||
if (det_mon->type == DT &&
|
||||
det_mon->section.d_timings.h_size != 0 &&
|
||||
det_mon->section.d_timings.v_size != 0) {
|
||||
|
||||
p->output->mm_width = det_mon->section.d_timings.h_size;
|
||||
p->output->mm_height = det_mon->section.d_timings.v_size;
|
||||
p->ret = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the EDID information for the specified output
|
||||
*/
|
||||
|
@ -2908,7 +2955,6 @@ xf86OutputSetEDID (xf86OutputPtr output, xf86MonPtr edid_mon)
|
|||
{
|
||||
ScrnInfoPtr scrn = output->scrn;
|
||||
xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
|
||||
int i;
|
||||
#ifdef RANDR_12_INTERFACE
|
||||
int size;
|
||||
#endif
|
||||
|
@ -2943,20 +2989,15 @@ xf86OutputSetEDID (xf86OutputPtr output, xf86MonPtr edid_mon)
|
|||
xf86OutputSetEDIDProperty (output, edid_mon ? edid_mon->rawData : NULL, size);
|
||||
#endif
|
||||
|
||||
if (edid_mon)
|
||||
{
|
||||
/* Pull out a phyiscal size from a detailed timing if available. */
|
||||
for (i = 0; i < 4; 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)
|
||||
{
|
||||
output->mm_width = edid_mon->det_mon[i].section.d_timings.h_size;
|
||||
output->mm_height = edid_mon->det_mon[i].section.d_timings.v_size;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (edid_mon) {
|
||||
|
||||
struct det_phySize_parameter p;
|
||||
p.output = output;
|
||||
p.quirks = xf86DDCDetectQuirks(scrn->scrnIndex,edid_mon, FALSE);
|
||||
p.ret = FALSE;
|
||||
xf86ForEachDetailedBlock(edid_mon,
|
||||
handle_detailed_physical_size, &p);
|
||||
|
||||
/* if no mm size is available from a detailed timing, check the max size field */
|
||||
if ((!output->mm_width || !output->mm_height) &&
|
||||
(edid_mon->features.hsize && edid_mon->features.vsize))
|
||||
|
|
|
@ -45,20 +45,23 @@
|
|||
#include <string.h>
|
||||
#include <math.h>
|
||||
|
||||
static void handle_detailed_rblank(struct detailed_monitor_section *det_mon,
|
||||
void *data)
|
||||
{
|
||||
if (det_mon->type == DS_RANGES)
|
||||
if (det_mon->section.ranges.supported_blanking & CVT_REDUCED)
|
||||
*(Bool*)data = TRUE;
|
||||
}
|
||||
|
||||
static Bool
|
||||
xf86MonitorSupportsReducedBlanking(xf86MonPtr DDC)
|
||||
{
|
||||
/* EDID 1.4 explicitly defines RB support */
|
||||
if (DDC->ver.revision >= 4) {
|
||||
int i;
|
||||
for (i = 0; i < DET_TIMINGS; 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)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
Bool ret = FALSE;
|
||||
|
||||
xf86ForEachDetailedBlock(DDC, handle_detailed_rblank, &ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* For anything older, assume digital means RB support. Boo. */
|
||||
|
@ -68,34 +71,6 @@ xf86MonitorSupportsReducedBlanking(xf86MonPtr DDC)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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;
|
||||
|
||||
static Bool quirk_prefer_large_60 (int scrnIndex, xf86MonPtr DDC)
|
||||
{
|
||||
/* Belinea 10 15 55 */
|
||||
|
@ -774,7 +749,7 @@ DDCGuessRangesFromModes(int scrnIndex, MonPtr Monitor, DisplayModePtr Modes)
|
|||
}
|
||||
}
|
||||
|
||||
static ddc_quirk_t
|
||||
ddc_quirk_t
|
||||
xf86DDCDetectQuirks(int scrnIndex, xf86MonPtr DDC, Bool verbose)
|
||||
{
|
||||
ddc_quirk_t quirks;
|
||||
|
@ -794,6 +769,25 @@ xf86DDCDetectQuirks(int scrnIndex, xf86MonPtr DDC, Bool verbose)
|
|||
return quirks;
|
||||
}
|
||||
|
||||
void xf86DetTimingApplyQuirks(struct detailed_monitor_section *det_mon,
|
||||
ddc_quirk_t quirks,
|
||||
int hsize, int vsize)
|
||||
{
|
||||
if (det_mon->type != DT)
|
||||
return;
|
||||
|
||||
if (quirks & DDC_QUIRK_DETAILED_H_IN_CM)
|
||||
det_mon->section.d_timings.h_size *= 10;
|
||||
|
||||
if (quirks & DDC_QUIRK_DETAILED_V_IN_CM)
|
||||
det_mon->section.d_timings.v_size *= 10;
|
||||
|
||||
if (quirks & DDC_QUIRK_DETAILED_USE_MAXIMUM_SIZE) {
|
||||
det_mon->section.d_timings.h_size = 10 * hsize;
|
||||
det_mon->section.d_timings.v_size = 10 * vsize;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies monitor-specific quirks to the decoded EDID information.
|
||||
*
|
||||
|
@ -807,21 +801,9 @@ xf86DDCApplyQuirks(int scrnIndex, xf86MonPtr DDC)
|
|||
int i;
|
||||
|
||||
for (i = 0; i < DET_TIMINGS; i++) {
|
||||
struct detailed_monitor_section *det_mon = &DDC->det_mon[i];
|
||||
|
||||
if (det_mon->type != DT)
|
||||
continue;
|
||||
|
||||
if (quirks & DDC_QUIRK_DETAILED_H_IN_CM)
|
||||
det_mon->section.d_timings.h_size *= 10;
|
||||
|
||||
if (quirks & DDC_QUIRK_DETAILED_V_IN_CM)
|
||||
det_mon->section.d_timings.v_size *= 10;
|
||||
|
||||
if (quirks & DDC_QUIRK_DETAILED_USE_MAXIMUM_SIZE) {
|
||||
det_mon->section.d_timings.h_size = 10 * DDC->features.hsize;
|
||||
det_mon->section.d_timings.v_size = 10 * DDC->features.vsize;
|
||||
}
|
||||
xf86DetTimingApplyQuirks(DDC->det_mon + i, quirks,
|
||||
DDC->features.hsize,
|
||||
DDC->features.vsize);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -866,14 +848,156 @@ xf86DDCSetPreferredRefresh(int scrnIndex, DisplayModePtr modes,
|
|||
best->type |= M_T_PREFERRED;
|
||||
}
|
||||
|
||||
#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 */
|
||||
};
|
||||
|
||||
/* chose mode line by cea short video descriptor*/
|
||||
static void handle_cea_svd(struct cea_video_block *video, void *data)
|
||||
{
|
||||
DisplayModePtr Mode;
|
||||
DisplayModePtr *Modes = (DisplayModePtr *) data;
|
||||
int vid;
|
||||
|
||||
vid = video ->video_code & 0x7f;
|
||||
if (vid < CEA_VIDEO_MODES_NUM) {
|
||||
Mode = xf86DuplicateMode(CEAVideoModes + vid);
|
||||
*Modes = xf86ModesAdd(*Modes, Mode);
|
||||
}
|
||||
}
|
||||
|
||||
static DisplayModePtr
|
||||
DDCModesFromCEAExtension(int scrnIndex, xf86MonPtr MonPtr)
|
||||
{
|
||||
DisplayModePtr Modes = NULL;
|
||||
|
||||
xf86ForEachVideoBlock(MonPtr,
|
||||
handle_cea_svd,
|
||||
&Modes);
|
||||
|
||||
return Modes;
|
||||
}
|
||||
|
||||
struct det_modes_parameter {
|
||||
xf86MonPtr DDC;
|
||||
ddc_quirk_t quirks;
|
||||
DisplayModePtr Modes;
|
||||
Bool rb;
|
||||
Bool preferred;
|
||||
int timing_level;
|
||||
};
|
||||
|
||||
static void handle_detailed_modes(struct detailed_monitor_section *det_mon,
|
||||
void *data)
|
||||
{
|
||||
DisplayModePtr Mode;
|
||||
struct det_modes_parameter *p = (struct det_modes_parameter *)data;
|
||||
|
||||
xf86DetTimingApplyQuirks(det_mon,p->quirks,
|
||||
p->DDC->features.hsize,
|
||||
p->DDC->features.vsize);
|
||||
|
||||
switch (det_mon->type) {
|
||||
case DT:
|
||||
Mode = DDCModeFromDetailedTiming(p->DDC->scrnIndex,
|
||||
&det_mon->section.d_timings,
|
||||
p->preferred,
|
||||
p->quirks);
|
||||
p->preferred = FALSE;
|
||||
p->Modes = xf86ModesAdd(p->Modes, Mode);
|
||||
break;
|
||||
case DS_STD_TIMINGS:
|
||||
Mode = DDCModesFromStandardTiming(det_mon->section.std_t,
|
||||
p->quirks, p->timing_level,p->rb);
|
||||
p->Modes = xf86ModesAdd(p->Modes, Mode);
|
||||
break;
|
||||
#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(7,0,0,0,0)
|
||||
case DS_CVT:
|
||||
Mode = DDCModesFromCVT(p->DDC->scrnIndex, det_mon->section.cvt);
|
||||
p->Modes = xf86ModesAdd(p->Modes, Mode);
|
||||
break;
|
||||
#endif
|
||||
case DS_EST_III:
|
||||
Mode = DDCModesFromEstIII(det_mon->section.est_iii);
|
||||
p->Modes = xf86ModesAdd(p->Modes, Mode);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DisplayModePtr
|
||||
xf86DDCGetModes(int scrnIndex, xf86MonPtr DDC)
|
||||
{
|
||||
int i;
|
||||
DisplayModePtr Modes = NULL, Mode;
|
||||
ddc_quirk_t quirks;
|
||||
Bool preferred, rb;
|
||||
int timing_level;
|
||||
struct det_modes_parameter p;
|
||||
|
||||
xf86DrvMsg (scrnIndex, X_INFO, "EDID vendor \"%s\", prod id %d\n",
|
||||
DDC->vendor.name, DDC->vendor.prod_id);
|
||||
|
@ -892,35 +1016,14 @@ xf86DDCGetModes(int scrnIndex, xf86MonPtr DDC)
|
|||
|
||||
timing_level = MonitorStandardTimingLevel(DDC);
|
||||
|
||||
for (i = 0; i < DET_TIMINGS; i++) {
|
||||
struct detailed_monitor_section *det_mon = &DDC->det_mon[i];
|
||||
|
||||
Mode = NULL;
|
||||
switch (det_mon->type) {
|
||||
case DT:
|
||||
Mode = DDCModeFromDetailedTiming(scrnIndex,
|
||||
&det_mon->section.d_timings,
|
||||
preferred,
|
||||
quirks);
|
||||
preferred = FALSE;
|
||||
break;
|
||||
case DS_STD_TIMINGS:
|
||||
Mode = DDCModesFromStandardTiming(det_mon->section.std_t,
|
||||
quirks, timing_level, rb);
|
||||
break;
|
||||
#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(7,0,0,0,0)
|
||||
case DS_CVT:
|
||||
Mode = DDCModesFromCVT(scrnIndex, det_mon->section.cvt);
|
||||
break;
|
||||
#endif
|
||||
case DS_EST_III:
|
||||
Mode = DDCModesFromEstIII(det_mon->section.est_iii);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
Modes = xf86ModesAdd(Modes, Mode);
|
||||
}
|
||||
p.quirks = quirks;
|
||||
p.DDC = DDC;
|
||||
p.Modes = Modes;
|
||||
p.rb = rb;
|
||||
p.preferred = preferred;
|
||||
p.timing_level = timing_level;
|
||||
xf86ForEachDetailedBlock(DDC, handle_detailed_modes, &p);
|
||||
Modes = p.Modes;
|
||||
|
||||
/* Add established timings */
|
||||
Mode = DDCModesFromEstablished(scrnIndex, &DDC->timings1, quirks);
|
||||
|
@ -930,6 +1033,10 @@ xf86DDCGetModes(int scrnIndex, xf86MonPtr DDC)
|
|||
Mode = DDCModesFromStandardTiming(DDC->timings2, quirks, timing_level, rb);
|
||||
Modes = xf86ModesAdd(Modes, Mode);
|
||||
|
||||
/* Add cea-extension mode timings */
|
||||
Mode = DDCModesFromCEAExtension(scrnIndex,DDC);
|
||||
Modes = xf86ModesAdd(Modes, Mode);
|
||||
|
||||
if (quirks & DDC_QUIRK_PREFER_LARGE_60)
|
||||
xf86DDCSetPreferredRefresh(scrnIndex, Modes, 60);
|
||||
|
||||
|
@ -939,6 +1046,63 @@ xf86DDCGetModes(int scrnIndex, xf86MonPtr DDC)
|
|||
return Modes;
|
||||
}
|
||||
|
||||
struct det_mon_parameter {
|
||||
MonPtr Monitor;
|
||||
ddc_quirk_t quirks;
|
||||
Bool have_hsync;
|
||||
Bool have_vrefresh;
|
||||
Bool have_maxpixclock;
|
||||
};
|
||||
|
||||
static void handle_detailed_monset(struct detailed_monitor_section *det_mon,
|
||||
void *data)
|
||||
{
|
||||
int clock;
|
||||
struct det_mon_parameter *p = (struct det_mon_parameter *)data;
|
||||
int scrnIndex = ((xf86MonPtr)(p->Monitor->DDC))->scrnIndex;
|
||||
|
||||
switch (det_mon->type) {
|
||||
case DS_RANGES:
|
||||
if (!p->have_hsync) {
|
||||
if (!p->Monitor->nHsync)
|
||||
xf86DrvMsg(scrnIndex, X_INFO,
|
||||
"Using EDID range info for horizontal sync\n");
|
||||
p->Monitor->hsync[p->Monitor->nHsync].lo =
|
||||
det_mon->section.ranges.min_h;
|
||||
p->Monitor->hsync[p->Monitor->nHsync].hi =
|
||||
det_mon->section.ranges.max_h;
|
||||
p->Monitor->nHsync++;
|
||||
} else {
|
||||
xf86DrvMsg(scrnIndex, X_INFO,
|
||||
"Using hsync ranges from config file\n");
|
||||
}
|
||||
|
||||
if (!p->have_vrefresh) {
|
||||
if (!p->Monitor->nVrefresh)
|
||||
xf86DrvMsg(scrnIndex, X_INFO,
|
||||
"Using EDID range info for vertical refresh\n");
|
||||
p->Monitor->vrefresh[p->Monitor->nVrefresh].lo =
|
||||
det_mon->section.ranges.min_v;
|
||||
p->Monitor->vrefresh[p->Monitor->nVrefresh].hi =
|
||||
det_mon->section.ranges.max_v;
|
||||
p->Monitor->nVrefresh++;
|
||||
} else {
|
||||
xf86DrvMsg(scrnIndex, X_INFO,
|
||||
"Using vrefresh ranges from config file\n");
|
||||
}
|
||||
|
||||
clock = det_mon->section.ranges.max_clock * 1000;
|
||||
if (p->quirks & DDC_QUIRK_DVI_SINGLE_LINK)
|
||||
clock = min(clock, 165000);
|
||||
if (!p->have_maxpixclock && clock > p->Monitor->maxPixClock)
|
||||
p->Monitor->maxPixClock = clock;
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Fill out MonPtr with xf86MonPtr information.
|
||||
*/
|
||||
|
@ -946,17 +1110,13 @@ void
|
|||
xf86EdidMonitorSet(int scrnIndex, MonPtr Monitor, xf86MonPtr DDC)
|
||||
{
|
||||
DisplayModePtr Modes = NULL, Mode;
|
||||
int i, clock;
|
||||
Bool have_hsync = FALSE, have_vrefresh = FALSE, have_maxpixclock = FALSE;
|
||||
ddc_quirk_t quirks;
|
||||
struct det_mon_parameter p;
|
||||
|
||||
if (!Monitor || !DDC)
|
||||
return;
|
||||
|
||||
Monitor->DDC = DDC;
|
||||
|
||||
quirks = xf86DDCDetectQuirks(scrnIndex, DDC, FALSE);
|
||||
|
||||
if (Monitor->widthmm <= 0 || Monitor->heightmm <= 0) {
|
||||
Monitor->widthmm = 10 * DDC->features.hsize;
|
||||
Monitor->heightmm = 10 * DDC->features.vsize;
|
||||
|
@ -966,54 +1126,13 @@ xf86EdidMonitorSet(int scrnIndex, MonPtr Monitor, xf86MonPtr DDC)
|
|||
|
||||
Modes = xf86DDCGetModes(scrnIndex, DDC);
|
||||
|
||||
/* Skip EDID ranges if they were specified in the config file */
|
||||
have_hsync = (Monitor->nHsync != 0);
|
||||
have_vrefresh = (Monitor->nVrefresh != 0);
|
||||
have_maxpixclock = (Monitor->maxPixClock != 0);
|
||||
|
||||
/* Go through the detailed monitor sections */
|
||||
for (i = 0; i < DET_TIMINGS; i++) {
|
||||
switch (DDC->det_mon[i].type) {
|
||||
case DS_RANGES:
|
||||
if (!have_hsync) {
|
||||
if (!Monitor->nHsync)
|
||||
xf86DrvMsg(scrnIndex, X_INFO,
|
||||
"Using EDID range info for horizontal sync\n");
|
||||
Monitor->hsync[Monitor->nHsync].lo =
|
||||
DDC->det_mon[i].section.ranges.min_h;
|
||||
Monitor->hsync[Monitor->nHsync].hi =
|
||||
DDC->det_mon[i].section.ranges.max_h;
|
||||
Monitor->nHsync++;
|
||||
} else {
|
||||
xf86DrvMsg(scrnIndex, X_INFO,
|
||||
"Using hsync ranges from config file\n");
|
||||
}
|
||||
|
||||
if (!have_vrefresh) {
|
||||
if (!Monitor->nVrefresh)
|
||||
xf86DrvMsg(scrnIndex, X_INFO,
|
||||
"Using EDID range info for vertical refresh\n");
|
||||
Monitor->vrefresh[Monitor->nVrefresh].lo =
|
||||
DDC->det_mon[i].section.ranges.min_v;
|
||||
Monitor->vrefresh[Monitor->nVrefresh].hi =
|
||||
DDC->det_mon[i].section.ranges.max_v;
|
||||
Monitor->nVrefresh++;
|
||||
} else {
|
||||
xf86DrvMsg(scrnIndex, X_INFO,
|
||||
"Using vrefresh ranges from config file\n");
|
||||
}
|
||||
|
||||
clock = DDC->det_mon[i].section.ranges.max_clock * 1000;
|
||||
if (quirks & DDC_QUIRK_DVI_SINGLE_LINK)
|
||||
clock = min(clock, 165000);
|
||||
if (!have_maxpixclock && clock > Monitor->maxPixClock)
|
||||
Monitor->maxPixClock = clock;
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
p.Monitor = Monitor;
|
||||
p.quirks = xf86DDCDetectQuirks(scrnIndex, Monitor->DDC, FALSE);
|
||||
p.have_hsync = (Monitor->nHsync != 0);
|
||||
p.have_vrefresh = (Monitor->nVrefresh != 0);
|
||||
p.have_maxpixclock = (Monitor->maxPixClock != 0);
|
||||
xf86ForEachDetailedBlock(DDC, handle_detailed_monset, &p);
|
||||
|
||||
if (Modes) {
|
||||
/* Print Modes */
|
||||
|
|
Loading…
Reference in New Issue
Block a user