aux/vga: return modes according to EDID timing priority order
EDID 1.3 section 5 gives a table describing the priority order of timing information. Use this ordering when constructing the EDID mode list. Since aux/vga selects the first mode in the modelist that matches the given size, it will now select the mode of that size with the highest preference. Or, if you set vgasize=auto (or some other string without an 'x'), aux/vga will select the Preferred Detailed Timing. This should make it unnecessary to modify vgadb in many cases.
This commit is contained in:
parent
d082a8972f
commit
954f9f1fcf
1 changed files with 76 additions and 63 deletions
|
@ -6,8 +6,8 @@
|
|||
#include "pci.h"
|
||||
#include "vga.h"
|
||||
|
||||
static Modelist*
|
||||
addmode(Modelist *l, Mode m)
|
||||
static void
|
||||
addmode(Modelist **l, Mode m)
|
||||
{
|
||||
Modelist *ll;
|
||||
int rr;
|
||||
|
@ -15,17 +15,15 @@ addmode(Modelist *l, Mode m)
|
|||
rr = (m.frequency+m.ht*m.vt/2)/(m.ht*m.vt);
|
||||
snprint(m.name, sizeof m.name, "%dx%d@%dHz", m.x, m.y, rr);
|
||||
|
||||
for(ll = l; ll != nil; ll = ll->next){
|
||||
if(strcmp(ll->name, m.name) == 0){
|
||||
ll->Mode = m;
|
||||
return l;
|
||||
}
|
||||
for(ll = *l; ll != nil; ll = *l){
|
||||
if(strcmp(ll->name, m.name) == 0)
|
||||
return;
|
||||
l = &ll->next;
|
||||
}
|
||||
|
||||
ll = alloc(sizeof(Modelist));
|
||||
ll->Mode = m;
|
||||
ll->next = l;
|
||||
return ll;
|
||||
*l = ll;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -281,71 +279,86 @@ parseedid128(void *v)
|
|||
p += 10;
|
||||
|
||||
assert(p == (uchar*)v+8+10+2+5+10);
|
||||
/*
|
||||
* Timing information priority order (EDID 1.3 section 5)
|
||||
* 1. Preferred Timing Mode (first detailed timing block)
|
||||
* 2. Other Detailed Timing Mode, in order listed
|
||||
* 3. Standard Timings, in order listed
|
||||
* 4. Established Timings
|
||||
*/
|
||||
|
||||
/*
|
||||
* Detailed Timings
|
||||
*/
|
||||
p = (uchar*)v+8+10+2+5+10+3+16;
|
||||
for(i=0; i<4; i++, p+=18)
|
||||
if(p[0] || p[1]) /* detailed timing block: p[0] or p[1] != 0 */
|
||||
if(decodedtb(&mode, p) == 0)
|
||||
addmode(&e->modelist, mode);
|
||||
assert(p == (uchar*)v+8+10+2+5+10+3+16+72);
|
||||
|
||||
/*
|
||||
* Standard Timing Identifications: eight 2-byte selectors
|
||||
* of more standard timings.
|
||||
*/
|
||||
p = (uchar*)v+8+10+2+5+10+3;
|
||||
for(i=0; i<8; i++, p+=2)
|
||||
if(decodesti(&mode, p+2*i) == 0)
|
||||
addmode(&e->modelist, mode);
|
||||
assert(p == (uchar*)v+8+10+2+5+10+3+16);
|
||||
|
||||
p = (uchar*)v+8+10+2+5+10+3+16;
|
||||
for(i=0; i<4; i++, p+=18){
|
||||
if(p[0] || p[1])
|
||||
continue;
|
||||
/* monitor descriptor block */
|
||||
switch(p[3]) {
|
||||
case 0xFF: /* monitor serial number (13-byte ascii, 0A terminated) */
|
||||
if(q = memchr(p+5, 0x0A, 13))
|
||||
*q = '\0';
|
||||
memset(e->serialstr, 0, sizeof(e->serialstr));
|
||||
strncpy(e->serialstr, (char*)p+5, 13);
|
||||
break;
|
||||
case 0xFE: /* ascii string (13-byte ascii, 0A terminated) */
|
||||
break;
|
||||
case 0xFD: /* monitor range limits */
|
||||
e->rrmin = p[5];
|
||||
e->rrmax = p[6];
|
||||
e->hrmin = p[7]*1000;
|
||||
e->hrmax = p[8]*1000;
|
||||
if(p[9] != 0xFF)
|
||||
e->pclkmax = p[9]*10*1000000;
|
||||
break;
|
||||
case 0xFC: /* monitor name (13-byte ascii, 0A terminated) */
|
||||
if(q = memchr(p+5, 0x0A, 13))
|
||||
*q = '\0';
|
||||
memset(e->name, 0, sizeof(e->name));
|
||||
strncpy(e->name, (char*)p+5, 13);
|
||||
break;
|
||||
case 0xFB: /* extra color point data */
|
||||
break;
|
||||
case 0xFA: /* extra standard timing identifications */
|
||||
for(i=0; i<6; i++)
|
||||
if(decodesti(&mode, p+5+2*i) == 0)
|
||||
addmode(&e->modelist, mode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert(p == (uchar*)v+8+10+2+5+10+3+16+72);
|
||||
|
||||
/*
|
||||
* Established timings: a bitmask of 19 preset timings.
|
||||
*/
|
||||
p = (uchar*)v+8+10+2+5+10;
|
||||
estab = (p[0]<<16) | (p[1]<<8) | p[2];
|
||||
p += 3;
|
||||
|
||||
for(i=0, m=1<<23; i<nelem(estabtime); i++, m>>=1)
|
||||
if(estab & m)
|
||||
if(vesalookup(&mode, estabtime[i]) == 0)
|
||||
e->modelist = addmode(e->modelist, mode);
|
||||
|
||||
addmode(&e->modelist, mode);
|
||||
assert(p == (uchar*)v+8+10+2+5+10+3);
|
||||
/*
|
||||
* Standard Timing Identifications: eight 2-byte selectors
|
||||
* of more standard timings.
|
||||
*/
|
||||
|
||||
for(i=0; i<8; i++, p+=2)
|
||||
if(decodesti(&mode, p+2*i) == 0)
|
||||
e->modelist = addmode(e->modelist, mode);
|
||||
|
||||
assert(p == (uchar*)v+8+10+2+5+10+3+16);
|
||||
/*
|
||||
* Detailed Timings
|
||||
*/
|
||||
for(i=0; i<4; i++, p+=18) {
|
||||
if(p[0] || p[1]) { /* detailed timing block: p[0] or p[1] != 0 */
|
||||
if(decodedtb(&mode, p) == 0)
|
||||
e->modelist = addmode(e->modelist, mode);
|
||||
} else if(p[2]==0) { /* monitor descriptor block */
|
||||
switch(p[3]) {
|
||||
case 0xFF: /* monitor serial number (13-byte ascii, 0A terminated) */
|
||||
if(q = memchr(p+5, 0x0A, 13))
|
||||
*q = '\0';
|
||||
memset(e->serialstr, 0, sizeof(e->serialstr));
|
||||
strncpy(e->serialstr, (char*)p+5, 13);
|
||||
break;
|
||||
case 0xFE: /* ascii string (13-byte ascii, 0A terminated) */
|
||||
break;
|
||||
case 0xFD: /* monitor range limits */
|
||||
e->rrmin = p[5];
|
||||
e->rrmax = p[6];
|
||||
e->hrmin = p[7]*1000;
|
||||
e->hrmax = p[8]*1000;
|
||||
if(p[9] != 0xFF)
|
||||
e->pclkmax = p[9]*10*1000000;
|
||||
break;
|
||||
case 0xFC: /* monitor name (13-byte ascii, 0A terminated) */
|
||||
if(q = memchr(p+5, 0x0A, 13))
|
||||
*q = '\0';
|
||||
memset(e->name, 0, sizeof(e->name));
|
||||
strncpy(e->name, (char*)p+5, 13);
|
||||
break;
|
||||
case 0xFB: /* extra color point data */
|
||||
break;
|
||||
case 0xFA: /* extra standard timing identifications */
|
||||
for(i=0; i<6; i++)
|
||||
if(decodesti(&mode, p+5+2*i) == 0)
|
||||
e->modelist = addmode(e->modelist, mode);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert(p == (uchar*)v+8+10+2+5+10+3+16+72);
|
||||
return e;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue