interpret_edid.c revision 05b261ec
1 2/* interpret_edid.c: interpret a primary EDID block 3 * 4 * Copyright 1998 by Egbert Eich <Egbert.Eich@Physik.TU-Darmstadt.DE> 5 */ 6#ifdef HAVE_XORG_CONFIG_H 7#include <xorg-config.h> 8#endif 9 10#include "misc.h" 11#include "xf86.h" 12#include "xf86_OSproc.h" 13#define _PARSE_EDID_ 14#include "xf86DDC.h" 15#include <string.h> 16 17static void get_vendor_section(Uchar*, struct vendor *); 18static void get_version_section(Uchar*, struct edid_version *); 19static void get_display_section(Uchar*, struct disp_features *, 20 struct edid_version *); 21static void get_established_timing_section(Uchar*, struct established_timings *); 22static void get_std_timing_section(Uchar*, struct std_timings *, 23 struct edid_version *); 24static void get_dt_md_section(Uchar *, struct edid_version *, 25 struct detailed_monitor_section *det_mon); 26static void copy_string(Uchar *, Uchar *); 27static void get_dst_timing_section(Uchar *, struct std_timings *, 28 struct edid_version *); 29static void get_monitor_ranges(Uchar *, struct monitor_ranges *); 30static void get_whitepoint_section(Uchar *, struct whitePoints *); 31static void get_detailed_timing_section(Uchar*, struct detailed_timings *); 32static Bool validate_version(int scrnIndex, struct edid_version *); 33 34static void 35handle_edid_quirks(xf86MonPtr m) 36{ 37 int i, j; 38 struct detailed_timings *preferred_timing; 39 struct monitor_ranges *ranges; 40 41 /* 42 * max_clock is only encoded in EDID in tens of MHz, so occasionally we 43 * find a monitor claiming a max of 160 with a mode requiring 162, or 44 * similar. Strictly we should refuse to round up too far, but let's 45 * see how well this works. 46 */ 47 for (i = 0; i < 4; i++) { 48 if (m->det_mon[i].type == DS_RANGES) { 49 ranges = &m->det_mon[i].section.ranges; 50 for (j = 0; j < 4; j++) { 51 if (m->det_mon[j].type == DT) { 52 preferred_timing = &m->det_mon[j].section.d_timings; 53 if (!ranges->max_clock) continue; /* zero is legal */ 54 if (ranges->max_clock * 1000000 < preferred_timing->clock) { 55 xf86Msg(X_WARNING, 56 "EDID preferred timing clock %.2fMHz exceeds " 57 "claimed max %dMHz, fixing\n", 58 preferred_timing->clock / 1.0e6, 59 ranges->max_clock); 60 ranges->max_clock = 61 (preferred_timing->clock+999999)/1000000; 62 return; 63 } 64 } 65 } 66 } 67 } 68} 69 70xf86MonPtr 71xf86InterpretEDID(int scrnIndex, Uchar *block) 72{ 73 xf86MonPtr m; 74 75 if (!block) return NULL; 76 if (! (m = xnfcalloc(sizeof(xf86Monitor),1))) return NULL; 77 m->scrnIndex = scrnIndex; 78 m->rawData = block; 79 80 get_vendor_section(SECTION(VENDOR_SECTION,block),&m->vendor); 81 get_version_section(SECTION(VERSION_SECTION,block),&m->ver); 82 if (!validate_version(scrnIndex, &m->ver)) goto error; 83 get_display_section(SECTION(DISPLAY_SECTION,block),&m->features, 84 &m->ver); 85 get_established_timing_section(SECTION(ESTABLISHED_TIMING_SECTION,block), 86 &m->timings1); 87 get_std_timing_section(SECTION(STD_TIMING_SECTION,block),m->timings2, 88 &m->ver); 89 get_dt_md_section(SECTION(DET_TIMING_SECTION,block),&m->ver, m->det_mon); 90 m->no_sections = (int)*(char *)SECTION(NO_EDID,block); 91 92 handle_edid_quirks(m); 93 94 return (m); 95 96 error: 97 xfree(m); 98 return NULL; 99} 100 101static void 102get_vendor_section(Uchar *c, struct vendor *r) 103{ 104 r->name[0] = L1; 105 r->name[1] = L2; 106 r->name[2] = L3; 107 r->name[3] = '\0'; 108 109 r->prod_id = PROD_ID; 110 r->serial = SERIAL_NO; 111 r->week = WEEK; 112 r->year = YEAR; 113} 114 115static void 116get_version_section(Uchar *c, struct edid_version *r) 117{ 118 r->version = VERSION; 119 r->revision = REVISION; 120} 121 122static void 123get_display_section(Uchar *c, struct disp_features *r, 124 struct edid_version *v) 125{ 126 r->input_type = INPUT_TYPE; 127 if (!DIGITAL(r->input_type)) { 128 r->input_voltage = INPUT_VOLTAGE; 129 r->input_setup = SETUP; 130 r->input_sync = SYNC; 131 } else if (v->version > 1 || v->revision > 2) 132 r->input_dfp = DFP; 133 r->hsize = HSIZE_MAX; 134 r->vsize = VSIZE_MAX; 135 r->gamma = GAMMA; 136 r->dpms = DPMS; 137 r->display_type = DISPLAY_TYPE; 138 r->msc = MSC; 139 r->redx = REDX; 140 r->redy = REDY; 141 r->greenx = GREENX; 142 r->greeny = GREENY; 143 r->bluex = BLUEX; 144 r->bluey = BLUEY; 145 r->whitex = WHITEX; 146 r->whitey = WHITEY; 147} 148 149static void 150get_established_timing_section(Uchar *c, struct established_timings *r) 151{ 152 r->t1 = T1; 153 r->t2 = T2; 154 r->t_manu = T_MANU; 155} 156 157static void 158get_std_timing_section(Uchar *c, struct std_timings *r, 159 struct edid_version *v) 160{ 161 int i; 162 163 for (i=0;i<STD_TIMINGS;i++){ 164 if (VALID_TIMING) { 165 r[i].hsize = HSIZE1; 166 VSIZE1(r[i].vsize); 167 r[i].refresh = REFRESH_R; 168 r[i].id = STD_TIMING_ID; 169 } else { 170 r[i].hsize = r[i].vsize = r[i].refresh = r[i].id = 0; 171 } 172 NEXT_STD_TIMING; 173 } 174} 175 176static void 177get_dt_md_section(Uchar *c, struct edid_version *ver, 178 struct detailed_monitor_section *det_mon) 179{ 180 int i; 181 182 for (i=0;i<DET_TIMINGS;i++) { 183 if (ver->version == 1 && ver->revision >= 1 && IS_MONITOR_DESC) { 184 185 switch (MONITOR_DESC_TYPE) { 186 case SERIAL_NUMBER: 187 det_mon[i].type = DS_SERIAL; 188 copy_string(c,det_mon[i].section.serial); 189 break; 190 case ASCII_STR: 191 det_mon[i].type = DS_ASCII_STR; 192 copy_string(c,det_mon[i].section.ascii_data); 193 break; 194 case MONITOR_RANGES: 195 det_mon[i].type = DS_RANGES; 196 get_monitor_ranges(c,&det_mon[i].section.ranges); 197 break; 198 case MONITOR_NAME: 199 det_mon[i].type = DS_NAME; 200 copy_string(c,det_mon[i].section.name); 201 break; 202 case ADD_COLOR_POINT: 203 det_mon[i].type = DS_WHITE_P; 204 get_whitepoint_section(c,det_mon[i].section.wp); 205 break; 206 case ADD_STD_TIMINGS: 207 det_mon[i].type = DS_STD_TIMINGS; 208 get_dst_timing_section(c,det_mon[i].section.std_t, ver); 209 break; 210 case ADD_DUMMY: 211 det_mon[i].type = DS_DUMMY; 212 break; 213 default: 214 det_mon[i].type = DS_UNKOWN; 215 break; 216 } 217 } else { 218 det_mon[i].type = DT; 219 get_detailed_timing_section(c,&det_mon[i].section.d_timings); 220 } 221 NEXT_DT_MD_SECTION; 222 } 223} 224 225static void 226copy_string(Uchar *c, Uchar *s) 227{ 228 int i; 229 c = c + 5; 230 for (i = 0; (i < 13 && *c != 0x0A); i++) 231 *(s++) = *(c++); 232 *s = 0; 233 while (i-- && (*--s == 0x20)) *s = 0; 234} 235 236static void 237get_dst_timing_section(Uchar *c, struct std_timings *t, 238 struct edid_version *v) 239{ 240 int j; 241 c = c + 5; 242 for (j = 0; j < 5; j++) { 243 t[j].hsize = HSIZE1; 244 VSIZE1(t[j].vsize); 245 t[j].refresh = REFRESH_R; 246 t[j].id = STD_TIMING_ID; 247 NEXT_STD_TIMING; 248 } 249} 250 251static void 252get_monitor_ranges(Uchar *c, struct monitor_ranges *r) 253{ 254 r->min_v = MIN_V; 255 r->max_v = MAX_V; 256 r->min_h = MIN_H; 257 r->max_h = MAX_H; 258 r->max_clock = 0; 259 if(MAX_CLOCK != 0xff) /* is specified? */ 260 r->max_clock = MAX_CLOCK * 10; 261 if (HAVE_2ND_GTF) { 262 r->gtf_2nd_f = F_2ND_GTF; 263 r->gtf_2nd_c = C_2ND_GTF; 264 r->gtf_2nd_m = M_2ND_GTF; 265 r->gtf_2nd_k = K_2ND_GTF; 266 r->gtf_2nd_j = J_2ND_GTF; 267 } else 268 r->gtf_2nd_f = 0; 269} 270 271static void 272get_whitepoint_section(Uchar *c, struct whitePoints *wp) 273{ 274 wp[1].white_x = WHITEX1; 275 wp[1].white_y = WHITEY1; 276 wp[2].white_x = WHITEX2; 277 wp[2].white_y = WHITEY2; 278 wp[1].index = WHITE_INDEX1; 279 wp[2].index = WHITE_INDEX2; 280 wp[1].white_gamma = WHITE_GAMMA1; 281 wp[2].white_gamma = WHITE_GAMMA2; 282} 283 284static void 285get_detailed_timing_section(Uchar *c, struct detailed_timings *r) 286{ 287 r->clock = PIXEL_CLOCK; 288 r->h_active = H_ACTIVE; 289 r->h_blanking = H_BLANK; 290 r->v_active = V_ACTIVE; 291 r->v_blanking = V_BLANK; 292 r->h_sync_off = H_SYNC_OFF; 293 r->h_sync_width = H_SYNC_WIDTH; 294 r->v_sync_off = V_SYNC_OFF; 295 r->v_sync_width = V_SYNC_WIDTH; 296 r->h_size = H_SIZE; 297 r->v_size = V_SIZE; 298 r->h_border = H_BORDER; 299 r->v_border = V_BORDER; 300 r->interlaced = INTERLACED; 301 r->stereo = STEREO; 302 r->stereo_1 = STEREO1; 303 r->sync = SYNC_T; 304 r->misc = MISC; 305} 306 307#define MAX_EDID_MINOR 3 308 309static Bool 310validate_version(int scrnIndex, struct edid_version *r) 311{ 312 if (r->version != 1) 313 return FALSE; 314 315 if (r->revision > MAX_EDID_MINOR) 316 xf86DrvMsg(scrnIndex, X_WARNING, 317 "Assuming version 1.%d is compatible with 1.%d\n", 318 r->revision, MAX_EDID_MINOR); 319 320 return TRUE; 321} 322