From 8b9badd6a6d5880f090028ea2976886472dd0793 Mon Sep 17 00:00:00 2001 From: ftrvxmtrx Date: Fri, 2 Jan 2015 13:24:27 +0100 Subject: aux/vga: fix switching with different mode Prior to switching display, switch to text mode 3, which is supported by anything, then set display, search for the desired mode, load it if found. If not found, set the display to the old one and switch to the old mode back. --- sys/src/cmd/aux/vga/vesa.c | 150 +++++++++++++++++++++++++++++++-------------- 1 file changed, 103 insertions(+), 47 deletions(-) diff --git a/sys/src/cmd/aux/vga/vesa.c b/sys/src/cmd/aux/vga/vesa.c index 699b2f8bf..706e7aec2 100644 --- a/sys/src/cmd/aux/vga/vesa.c +++ b/sys/src/cmd/aux/vga/vesa.c @@ -28,7 +28,7 @@ struct Vbe uchar *modebuf; int dspcon; /* connected displays bitmask */ int dspact; /* active displays bitmask */ - void (*scale)(Vga*, Ctlr*, int); + void (*scale)(Vga*, Ctlr*); }; struct Vmode @@ -100,7 +100,7 @@ int vbecheck(Vbe*); uchar *vbemodes(Vbe*); int vbemodeinfo(Vbe*, int, Vmode*); int vbegetmode(Vbe*); -int vbesetmode(Vbe*, int, int); +int vbesetmode(Vbe*, int); void vbeprintinfo(Vbe*); void vbeprintmodeinfo(Vbe*, int, char*); int vbesnarf(Vbe*, Vga*); @@ -111,6 +111,7 @@ void fixbios(Vbe*); uchar* vbesetup(Vbe*, Ureg*, int); int vbecall(Vbe*, Ureg*); int setdisplay(Vbe *vbe, int display); +int getdisplay(Vbe *vbe); int dbvesa(Vga* vga) @@ -142,32 +143,41 @@ dbvesa(Vga* vga) Mode* dbvesamode(char *size) { - int i, width, nargs; + int i, width, nargs, display; + int oldmode, olddisplay; uchar *p, *ep; Attr *a; Vmode vm; Mode *m; Modelist *l; - char *args[4], *scale, *display; + char *args[4], *scale; if(vbe == nil) return nil; scale = nil; - display = nil; + display = 0; + oldmode = olddisplay = 0; nargs = getfields(size, args, 4, 0, ","); if(nargs > 1){ if(args[1][0] == '#'){ - display = &args[1][1]; + display = atoi(&args[1][1]); if(nargs > 2) scale = args[2]; }else if(args[1][0] == 's'){ scale = args[1]; if(nargs > 2) - display = &args[2][1]; + display = atoi(&args[2][1]); } } + if(display != 0){ + olddisplay = getdisplay(vbe); + oldmode = vbegetmode(vbe); + if(setdisplay(vbe, display) < 0) + return nil; + } + if(strncmp(size, "0x", 2) == 0){ if(vbemodeinfo(vbe, strtol(size+2, nil, 16), &vm) == 0) goto havemode; @@ -190,10 +200,17 @@ dbvesamode(char *size) } } } + + if(display != 0 && setdisplay(vbe, olddisplay) == 0) + vbesetmode(vbe, oldmode); + werrstr("no such vesa mode"); return nil; havemode: + if(display != 0 && setdisplay(vbe, olddisplay) == 0) + vbesetmode(vbe, oldmode); + m = alloc(sizeof(Mode)); m->x = vm.dx; m->y = vm.dy; @@ -248,11 +265,11 @@ havemode: } /* display id */ - if(display != nil){ + if(display != 0){ a = alloc(sizeof(Attr)); a->attr = "display"; a->val = alloc(2); - strncpy(a->val, display, 2); + a->val[0] = '0' + display; a->next = m->attr; m->attr = a; @@ -302,6 +319,7 @@ static void load(Vga* vga, Ctlr* ctlr) { int mode, display; + int oldmode, olddisplay; char *ds; if(vbe == nil) @@ -309,16 +327,29 @@ load(Vga* vga, Ctlr* ctlr) mode = atoi(dbattr(vga->mode->attr, "id")); 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(vga, ctlr, 1); + vbe->scale(nil, nil); - if(vbesetmode(vbe, mode, display) < 0){ + if(display != 0){ + olddisplay = getdisplay(vbe); + oldmode = vbegetmode(vbe); + } + + if(setdisplay(vbe, display) < 0){ + ctlr->flag |= Ferror; + fprint(2, "vbesetmode: %r\n"); + }else if(vbesetmode(vbe, mode) < 0){ + 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, 0); + vbe->scale(vga, ctlr); } static void @@ -351,7 +382,7 @@ dump(Vga*, Ctlr*) } static void -intelscale(Vga* vga, Ctlr* ctlr, int reset) +intelscale(Vga* vga, Ctlr* ctlr) { Ureg u; int cx; @@ -360,31 +391,31 @@ intelscale(Vga* vga, Ctlr* ctlr, int reset) if(vbe == nil) error("no vesa bios\n"); - /* 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) + if(vga == nil) cx = 4; else{ - ctlr->flag |= Ferror; - fprint(2, "vbescale: unsupported mode %s\n", scale); - return; + /* 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; + } } - if(reset) - cx = 4; vbesetup(vbe, &u, 0x5F61); u.bx = 0; u.cx = cx; /* horizontal */ u.dx = cx; /* vertical */ vbecall(vbe, &u); - if(u.ax != 0x5f) - fprint(2, "vbescale: %#.4lux", u.ax); } static void -nvidiascale(Vga* vga, Ctlr* ctlr, int reset) +nvidiascale(Vga* vga, Ctlr* ctlr) { Ureg u; int cx; @@ -393,26 +424,26 @@ nvidiascale(Vga* vga, Ctlr* ctlr, int reset) if(vbe == nil) error("no vesa bios\n"); - 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) + if(vga == nil) cx = 0; else{ - ctlr->flag |= Ferror; - fprint(2, "vbescale: unsupported mode %s\n", scale); - return; + 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; + } } - if(reset) - cx = 0; vbesetup(vbe, &u, 0x4F14); u.bx = 0x102; u.cx = cx; - if(vbecall(vbe, &u) < 0) - fprint(2, "vbescale: %r\n"); } Ctlr vesa = { @@ -864,20 +895,25 @@ int vbegetmode(Vbe *vbe) { Ureg u; + char size[32]; + Mode *m; - vbesetup(vbe, &u, 0x4F03); - if(vbecall(vbe, &u) < 0) - return 0; - return u.bx; + vbesetup(vbe, &u, 0x5F29); + u.bx = 0x8000; /* current mode */ + vbecall(vbe, &u); + if(u.ax != 0x5f) + return -1; + snprint(size, sizeof(size), "%dx%dx%d", + (int)u.bx>>16, (int)u.bx & 0xffff, (int)u.cx & 0xff); + m = dbvesamode(size); + return m == nil ? -1 : atoi(dbattr(m->attr, "id")); } int -vbesetmode(Vbe *vbe, int id, int display) +vbesetmode(Vbe *vbe, int id) { Ureg u; - if(setdisplay(vbe, display) < 0) - return -1; vbesetup(vbe, &u, 0x4F02); u.bx = id; if(id != 3) @@ -895,7 +931,7 @@ vesatextmode(void) } if(vbecheck(vbe) < 0) error("vbecheck: %r\n"); - if(vbesetmode(vbe, 3, 0) < 0) + if(vbesetmode(vbe, 3) < 0) error("vbesetmode: %r\n"); } @@ -928,6 +964,23 @@ vbeddcedid(Vbe *vbe, Edid *e) return 0; } +int +getdisplay(Vbe *vbe) +{ + int i; + + for(i = 0; i < 8; i++) + if(vbe->dspact & 1<dspcon & 1<dspcon & cx){ vbesetup(vbe, &u, 0x5F64); -- cgit v1.2.3