summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--sys/src/cmd/aux/vga/vesa.c306
1 files changed, 150 insertions, 156 deletions
diff --git a/sys/src/cmd/aux/vga/vesa.c b/sys/src/cmd/aux/vga/vesa.c
index 21bc85161..e10b7c2b8 100644
--- a/sys/src/cmd/aux/vga/vesa.c
+++ b/sys/src/cmd/aux/vga/vesa.c
@@ -25,9 +25,6 @@ struct Vbe
uchar *mem; /* copy of memory; 1MB */
uchar *isvalid; /* 1byte per 4kB in mem */
uchar *modebuf;
- int dspcon; /* connected displays bitmask */
- int dspact; /* active displays bitmask */
- void (*scale)(Vga*, Ctlr*);
};
struct Vmode
@@ -54,6 +51,10 @@ struct Vmode
static Vbe *vbe;
static Edid *edid;
+static int dspcon; /* connected displays bitmask */
+static int dspact; /* active displays bitmask */
+static int (*setscale)(Vbe*, char*);
+
Vbe *mkvbe(void);
int vbecheck(Vbe*);
uchar *vbemodes(Vbe*);
@@ -68,7 +69,7 @@ int vbeddcedid(Vbe *vbe, Edid *e);
uchar* vbesetup(Vbe*, Ureg*, int);
int vbecall(Vbe*, Ureg*);
int setdisplay(Vbe *vbe, int display);
-int getdisplay(Vbe *vbe);
+int getdisplay(Vbe*);
void fixbios(Vbe*);
int
@@ -98,37 +99,64 @@ dbvesa(Vga* vga)
return 1;
}
+static Attr*
+newattr(Attr *tail, char *attr, char *fmt, ...)
+{
+ va_list list;
+ char *val;
+ Attr *a;
+
+ va_start(list, fmt);
+ val = vsmprint(fmt, list);
+ va_end(list);
+
+ a = alloc(sizeof(Attr));
+ a->attr = attr;
+ a->val = val;
+ a->next = tail;
+
+ return a;
+}
+
+static char*
+cracksize(char *size, char **scale, int *display)
+{
+ static char buf[256];
+ char *f[4];
+ int i, n;
+
+ *scale = nil;
+ *display = 0;
+ snprint(buf, sizeof(buf), "%s", size);
+ n = getfields(buf, f, nelem(f), 0, ",");
+ for(i=1; i<n; i++){
+ if(f[i][0] == '#')
+ *display = atoi(&f[i][1]);
+ else if(strncmp(f[i], "scale", 5) == 0)
+ *scale = f[i];
+ else
+ error("bad size option: %s for %s\n", f[i], f[0]);
+ }
+ return f[0];
+}
+
Mode*
dbvesamode(char *size)
{
- int i, width, nargs, display;
+ int i, width, display;
int oldmode, olddisplay;
uchar *p, *ep;
- Attr *a;
Vmode vm;
Mode *m;
Modelist *l;
- char *args[4], *scale;
+ char *scale;
if(vbe == nil)
return nil;
- scale = nil;
- display = 0;
- oldmode = olddisplay = 0;
- nargs = getfields(size, args, 4, 0, ",");
- if(nargs > 1){
- if(args[1][0] == '#'){
- display = atoi(&args[1][1]);
- if(nargs > 2)
- scale = args[2];
- }else if(args[1][0] == 's'){
- scale = args[1];
- if(nargs > 2)
- display = atoi(&args[2][1]);
- }
- }
+ size = cracksize(size, &scale, &display);
+ oldmode = olddisplay = 0;
if(display != 0){
olddisplay = getdisplay(vbe);
oldmode = vbegetmode(vbe);
@@ -203,47 +231,17 @@ havemode:
strcpy(m->chan, vm.chan);
m->z = vm.depth;
- a = alloc(sizeof(Attr));
- a->attr = "id";
- a->val = alloc(32);
- sprint(a->val, "0x%x", vm.id);
-
- a->next = nil;
- m->attr = a;
-
- /* scaling mode */
- if(scale != nil){
- a = alloc(sizeof(Attr));
- a->attr = "scale";
- a->val = alloc(32);
- strncpy(a->val, scale, 32);
-
- a->next = m->attr;
- m->attr = a;
- }
-
- /* display id */
- if(display != 0){
- a = alloc(sizeof(Attr));
- a->attr = "display";
- a->val = alloc(2);
- a->val[0] = '0' + display;
-
- a->next = m->attr;
- m->attr = a;
- }
-
/* account for framebuffer stride */
width = vm.bpl * 8 / m->z;
- if(width > m->x){
- a = alloc(sizeof(Attr));
- a->attr = "virtx";
- a->val = alloc(32);
- sprint(a->val, "%d", width);
-
- a->next = m->attr;
- m->attr = a;
- }
+ if(width > m->x)
+ m->attr = newattr(m->attr, "virtx", "%d", width);
+
+ if(scale != nil)
+ m->attr = newattr(m->attr, "scale", "%s", scale);
+ if(display != 0)
+ m->attr = newattr(m->attr, "display", "%d", display);
+
+ m->attr = newattr(m->attr, "id", "0x%x", vm.id);
return m;
}
@@ -278,36 +276,44 @@ load(Vga* vga, Ctlr* ctlr)
{
int mode, display;
int oldmode, olddisplay;
- char *ds;
+ char *ds, *scale;
if(vbe == nil)
error("no vesa bios\n");
mode = atoi(dbattr(vga->mode->attr, "id"));
+ scale = dbattr(vga->mode->attr, "scale");
ds = dbattr(vga->mode->attr, "display");
display = ds == nil ? 0 : atoi(ds);
olddisplay = oldmode = 0;
/* need to reset scaling before switching displays */
- if(vbe->scale != nil)
- vbe->scale(nil, nil);
-
+ if(setscale != nil)
+ (*setscale)(vbe, "scalefull");
if(display != 0){
olddisplay = getdisplay(vbe);
oldmode = vbegetmode(vbe);
+ if(setdisplay(vbe, display) < 0){
+ fprint(2, "setdisplay: %r\n");
+ ctlr->flag |= Ferror;
+ return;
+ }
}
-
- if(setdisplay(vbe, display) < 0){
- ctlr->flag |= Ferror;
+ if(vbesetmode(vbe, mode) < 0){
fprint(2, "vbesetmode: %r\n");
- }else if(vbesetmode(vbe, mode) < 0){
+ ctlr->flag |= Ferror;
if(display != 0){
setdisplay(vbe, olddisplay);
vbesetmode(vbe, oldmode);
}
- ctlr->flag |= Ferror;
- fprint(2, "vbesetmode: %r\n");
- }else if(vbe->scale != nil)
- vbe->scale(vga, ctlr);
+ return;
+ }
+ if(setscale != nil){
+ if((*setscale)(vbe, scale) < 0){
+ fprint(2, "setscale: %r\n");
+ ctlr->flag |= Ferror;
+ return;
+ }
+ }
}
static void
@@ -339,69 +345,47 @@ dump(Vga*, Ctlr*)
printedid(edid);
}
-static void
-intelscale(Vga* vga, Ctlr* ctlr)
+static int
+intelscale(Vbe *vbe, char *scale)
{
Ureg u;
int cx;
- char *scale;
- if(vbe == nil)
- error("no vesa bios\n");
-
- if(vga == nil)
+ if(scale == nil)
+ cx = 0;
+ else if(strcmp(scale, "scalefull") == 0)
cx = 4;
- else{
- /* NOTE: intel doesn't support "aspect" scaling mode :( */
- scale = dbattr(vga->mode->attr, "scale");
- if(scale == nil)
- cx = 0;
- else if(strcmp(scale, "scalefull") == 0)
- cx = 4;
- else{
- ctlr->flag |= Ferror;
- fprint(2, "vbescale: unsupported mode %s\n", scale);
- return;
- }
+ else {
+ werrstr("intelscale: not supported: %s", scale);
+ return -1;
}
-
vbesetup(vbe, &u, 0x5F61);
u.bx = 0;
u.cx = cx; /* horizontal */
u.dx = cx; /* vertical */
- vbecall(vbe, &u);
+ return vbecall(vbe, &u);
}
-static void
-nvidiascale(Vga* vga, Ctlr* ctlr)
+static int
+nvidiascale(Vbe *vbe, char *scale)
{
Ureg u;
int cx;
- char *scale;
- if(vbe == nil)
- error("no vesa bios\n");
-
- if(vga == nil)
+ if(scale == nil)
+ cx = 1;
+ else if(strcmp(scale, "scaleaspect") == 0)
+ cx = 3;
+ else if(strcmp(scale, "scalefull") == 0)
cx = 0;
- else{
- scale = dbattr(vga->mode->attr, "scale");
- if(scale == nil)
- cx = 1;
- else if(strcmp(scale, "scaleaspect") == 0)
- cx = 3;
- else if(strcmp(scale, "scalefull") == 0)
- cx = 0;
- else{
- ctlr->flag |= Ferror;
- fprint(2, "vbescale: unsupported mode %s\n", scale);
- return;
- }
+ else {
+ werrstr("nvidiascale: not supported: %s", scale);
+ return -1;
}
-
vbesetup(vbe, &u, 0x4F14);
u.bx = 0x102;
u.cx = cx;
+ return vbecall(vbe, &u);
}
Ctlr vesa = {
@@ -584,6 +568,9 @@ vbeflush(Vbe *vbe)
int
vbecall(Vbe *vbe, Ureg *u)
{
+ int ax;
+
+ ax = u->ax >> 8;
u->trap = 0x10;
vbeflush(vbe);
@@ -595,7 +582,7 @@ vbecall(Vbe *vbe, Ureg *u)
getmem(vbe, RealModeBuf, 0);
- if((u->ax&0xFFFF) != 0x004F){
+ if((u->ax&0xFFFF) != ax){
werrstr("VBE error %#.4lux", u->ax&0xFFFF);
return -1;
}
@@ -605,7 +592,6 @@ vbecall(Vbe *vbe, Ureg *u)
int
vbecheck(Vbe *vbe)
{
- char *oem;
uchar *p;
Ureg u;
@@ -621,29 +607,13 @@ vbecheck(Vbe *vbe)
werrstr("invalid vesa version: %.4H\n", p+4);
return -1;
}
- oem = unfarptr(vbe, p+6);
- if(strncmp(oem, "Intel", 5) == 0){
- vbe->scale = intelscale;
-
- /* detect connected display devices */
- vbesetup(vbe, &u, 0x5F64);
- u.bx = 0x200;
- vbecall(vbe, &u);
- vbe->dspcon = u.cx >> 8; /* CH = connected, CL = available? */
-
- /* detect active display devices */
- vbesetup(vbe, &u, 0x5F64);
- u.bx = 0x100;
- vbecall(vbe, &u);
- vbe->dspact = u.cx;
- }else if(memcmp(oem, "NVIDIA", 6) == 0)
- vbe->scale = nvidiascale;
return 0;
}
int
vbesnarf(Vbe *vbe, Vga *vga)
{
+ char *oem;
uchar *p;
Ureg u;
@@ -654,6 +624,29 @@ vbesnarf(Vbe *vbe, Vga *vga)
if(memcmp(p, "VESA", 4) != 0 || p[5] < 2)
return -1;
vga->apz = WORD(p+18)*0x10000UL;
+
+ oem = unfarptr(vbe, p+6);
+ if(strncmp(oem, "Intel", 5) == 0){
+ setscale = intelscale;
+
+ /* detect connected display devices */
+ vbesetup(vbe, &u, 0x5F64);
+ u.bx = 0x200;
+ if(vbecall(vbe, &u) < 0)
+ u.cx = 0;
+ dspcon = u.cx >> 8; /* CH = connected, CL = available? */
+
+ /* detect active display devices */
+ vbesetup(vbe, &u, 0x5F64);
+ u.bx = 0x100;
+ if(vbecall(vbe, &u) < 0)
+ u.cx = 0;
+ dspact = u.cx;
+
+ }
+ else if(memcmp(oem, "NVIDIA", 6) == 0 && 0) /* untested */
+ setscale = nvidiascale;
+
if(edid == nil){
edid = alloc(sizeof(Edid));
if(vbeddcedid(vbe, edid) < 0){
@@ -696,17 +689,20 @@ vbeprintinfo(Vbe *vbe)
printitem("vesa", "mem");
Bprint(&stdout, "%lud\n", WORD(p+18)*0x10000UL);
- printitem("vesa", "dsp con");
- for(i = 0; i < 8; i++)
- if(vbe->dspcon & (1<<i))
- Bprint(&stdout, "%d ", i+1);
- Bprint(&stdout, "\n");
-
- printitem("vesa", "dsp act");
- for(i = 0; i < 8; i++)
- if(vbe->dspact & (1<<i))
- Bprint(&stdout, "%d ", i+1);
- Bprint(&stdout, "\n");
+ if(dspcon != 0){
+ printitem("vesa", "dsp con");
+ for(i = 0; i < 8; i++)
+ if(dspcon & (1<<i))
+ Bprint(&stdout, "%d ", i+1);
+ Bprint(&stdout, "\n");
+ }
+ if(dspact != 0){
+ printitem("vesa", "dsp act");
+ for(i = 0; i < 8; i++)
+ if(dspact & (1<<i))
+ Bprint(&stdout, "%d ", i+1);
+ Bprint(&stdout, "\n");
+ }
}
uchar*
@@ -888,17 +884,17 @@ vbeddcedid(Vbe *vbe, Edid *e)
}
int
-getdisplay(Vbe *vbe)
+getdisplay(Vbe*)
{
int i;
for(i = 0; i < 8; i++)
- if(vbe->dspact & 1<<i)
+ if(dspact & 1<<i)
return i+1;
/* fallback to a connected one */
for(i = 0; i < 8; i++)
- if(vbe->dspcon & 1<<i)
+ if(dspcon & 1<<i)
return i+1;
return 0;
@@ -914,20 +910,18 @@ setdisplay(Vbe *vbe, int display)
return 0;
cx = 1<<(display-1);
- if(vbe->dspcon & cx){
+ if(dspcon & cx){
/* switch to common mode before trying */
vbesetmode(vbe, 3);
vbesetup(vbe, &u, 0x5F64);
u.bx = 0;
u.cx = cx;
- vbecall(vbe, &u);
- if(u.ax == 0x5f)
- return 0;
- werrstr("setdisplay: VBE error %#.4lux", u.ax);
- }else
- werrstr("setdisplay: %d not connected", display);
- return -1;
+ return vbecall(vbe, &u);
+ } else {
+ werrstr("display #%d not connected", display);
+ return -1;
+ }
}
void