/*
* Parse VESA EDID information. Based on the VESA
* Extended Display Identification Data standard, Version 3,
* November 13, 1997. See /public/doc/vesa/edidv3.pdf.
*
* This only handles 128-byte EDID blocks. Until I find
* a monitor that produces 256-byte blocks, I'm not going
* to try to decode them.
*/
/*
* Established timings block. There is a bitmap
* that says whether each mode is supported. Most
* of these have VESA definitions. Those that don't are marked
* as such, and we ignore them (the lookup fails).
*/
static char *estabtime[] = {
"720x400@70Hz", /* non-VESA: IBM, VGA */
"720x400@88Hz", /* non-VESA: IBM, XGA2 */
"640x480@60Hz",
"640x480@67Hz", /* non-VESA: Apple, Mac II */
"640x480@72Hz",
"640x480@75Hz",
"800x600@56Hz",
"800x600@60Hz",
"800x600@72Hz",
"800x600@75Hz",
"832x624@75Hz", /* non-VESA: Apple, Mac II */
"1024x768i@87Hz", /* non-VESA: IBM */
"1024x768@60Hz",
"1024x768@70Hz",
"1024x768@75Hz",
"1280x1024@75Hz",
"1152x870@75Hz", /* non-VESA: Apple, Mac II */
};
/*
* Decode the EDID detailed timing block. See pp. 20-21 of the standard.
*/
static int
decodedtb(Mode *m, uchar *p)
{
int ha, hb, hso, hspw, rr, va, vb, vso, vspw;
/* int hbord, vbord, dxmm, dymm, hbord, vbord; */
if(p[17] & 0x60) /* some form of stereo monitor mode; no support */
return -1;
/*
* Sync signal description. I have no idea how to properly handle the
* first three cases, which I think are aimed at things other than
* canonical SVGA monitors.
*/
switch((p[17] & 0x18)>>3) {
case 0: /* analog composite sync signal*/
case 1: /* bipolar analog composite sync signal */
/* p[17] & 0x04 means serration: hsync during vsync */
/* p[17] & 0x02 means sync pulse appears on RGB not just G */
break;
case 2: /* digital composite sync signal */
/* p[17] & 0x04 means serration: hsync during vsync */
/* p[17] & 0x02 means hsync positive outside vsync */
break;
case 3: /* digital separate sync signal; the norm */
m->vsync = (p[17] & 0x04) ? '+' : '-';
m->hsync = (p[17] & 0x02) ? '+' : '-';
break;
}
/* p[17] & 0x01 is another stereo bit, only referenced if p[17] & 0x60 != 0 */
static int
decodesti(Mode *m, uchar *p)
{
int x, y, rr;
char str[20];
x = (p[0]+31)*8;
switch((p[1]>>6) & 3){
default:
case 0:
y = x;
break;
case 1:
y = (x*4)/3;
break;
case 2:
y = (x*5)/4;
break;
case 3:
y = (x*16)/9;
break;
}
rr = (p[1] & 0x1F) + 60;
sprint(str, "%dx%d@%dHz", x, y, rr);
return vesalookup(m, str);
}
sum = 0;
for(i=0; i<128; i++)
sum += p[i];
if(sum != 0) {
free(e);
werrstr("bad edid checksum");
return nil;
}
p += 8;
assert(p == (uchar*)v+8); /* assertion offsets from pp. 12-13 of the standard */
/*
* Manufacturer name is three 5-bit ascii letters, packed
* into a big endian [sic] short in big endian order. The high bit is unused.
*/
i = (p[0]<<8) | p[1];
p += 2;
e->mfr[0] = 'A'-1 + ((i>>10) & 0x1F);
e->mfr[1] = 'A'-1 + ((i>>5) & 0x1F);
e->mfr[2] = 'A'-1 + (i & 0x1F);
e->mfr[3] = '\0';
/*
* Product code is a little endian short.
*/
e->product = (p[1]<<8) | p[0];
p += 2;
/*
* Serial number is a little endian long, 0x01010101 = unused.
*/
e->serial = (p[3]<<24) | (p[2]<<16) | (p[1]<<8) | p[0];
p += 4;
if(e->serial == 0x01010101)
e->serial = 0;
e->mfrweek = *p++;
e->mfryear = 1990 + *p++;
assert(p == (uchar*)v+8+10);
/*
* Structure version is next two bytes: major.minor.
*/
e->version = *p++;
e->revision = *p++;
assert(p == (uchar*)v+8+10+2);
/*
* Basic display parameters / features.
*/
/*
* Video input definition byte: 0x80 tells whether it is
* an analog or digital screen; we ignore the other bits.
* See p. 15 of the standard.
*/
vid = *p++;
if(vid & 0x80)
e->flags |= Fdigital;