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.
This commit is contained in:
parent
96595f5101
commit
8b9badd6a6
|
@ -28,7 +28,7 @@ struct Vbe
|
||||||
uchar *modebuf;
|
uchar *modebuf;
|
||||||
int dspcon; /* connected displays bitmask */
|
int dspcon; /* connected displays bitmask */
|
||||||
int dspact; /* active displays bitmask */
|
int dspact; /* active displays bitmask */
|
||||||
void (*scale)(Vga*, Ctlr*, int);
|
void (*scale)(Vga*, Ctlr*);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Vmode
|
struct Vmode
|
||||||
|
@ -100,7 +100,7 @@ int vbecheck(Vbe*);
|
||||||
uchar *vbemodes(Vbe*);
|
uchar *vbemodes(Vbe*);
|
||||||
int vbemodeinfo(Vbe*, int, Vmode*);
|
int vbemodeinfo(Vbe*, int, Vmode*);
|
||||||
int vbegetmode(Vbe*);
|
int vbegetmode(Vbe*);
|
||||||
int vbesetmode(Vbe*, int, int);
|
int vbesetmode(Vbe*, int);
|
||||||
void vbeprintinfo(Vbe*);
|
void vbeprintinfo(Vbe*);
|
||||||
void vbeprintmodeinfo(Vbe*, int, char*);
|
void vbeprintmodeinfo(Vbe*, int, char*);
|
||||||
int vbesnarf(Vbe*, Vga*);
|
int vbesnarf(Vbe*, Vga*);
|
||||||
|
@ -111,6 +111,7 @@ void fixbios(Vbe*);
|
||||||
uchar* vbesetup(Vbe*, Ureg*, int);
|
uchar* vbesetup(Vbe*, Ureg*, int);
|
||||||
int vbecall(Vbe*, Ureg*);
|
int vbecall(Vbe*, Ureg*);
|
||||||
int setdisplay(Vbe *vbe, int display);
|
int setdisplay(Vbe *vbe, int display);
|
||||||
|
int getdisplay(Vbe *vbe);
|
||||||
|
|
||||||
int
|
int
|
||||||
dbvesa(Vga* vga)
|
dbvesa(Vga* vga)
|
||||||
|
@ -142,32 +143,41 @@ dbvesa(Vga* vga)
|
||||||
Mode*
|
Mode*
|
||||||
dbvesamode(char *size)
|
dbvesamode(char *size)
|
||||||
{
|
{
|
||||||
int i, width, nargs;
|
int i, width, nargs, display;
|
||||||
|
int oldmode, olddisplay;
|
||||||
uchar *p, *ep;
|
uchar *p, *ep;
|
||||||
Attr *a;
|
Attr *a;
|
||||||
Vmode vm;
|
Vmode vm;
|
||||||
Mode *m;
|
Mode *m;
|
||||||
Modelist *l;
|
Modelist *l;
|
||||||
char *args[4], *scale, *display;
|
char *args[4], *scale;
|
||||||
|
|
||||||
if(vbe == nil)
|
if(vbe == nil)
|
||||||
return nil;
|
return nil;
|
||||||
|
|
||||||
scale = nil;
|
scale = nil;
|
||||||
display = nil;
|
display = 0;
|
||||||
|
oldmode = olddisplay = 0;
|
||||||
nargs = getfields(size, args, 4, 0, ",");
|
nargs = getfields(size, args, 4, 0, ",");
|
||||||
if(nargs > 1){
|
if(nargs > 1){
|
||||||
if(args[1][0] == '#'){
|
if(args[1][0] == '#'){
|
||||||
display = &args[1][1];
|
display = atoi(&args[1][1]);
|
||||||
if(nargs > 2)
|
if(nargs > 2)
|
||||||
scale = args[2];
|
scale = args[2];
|
||||||
}else if(args[1][0] == 's'){
|
}else if(args[1][0] == 's'){
|
||||||
scale = args[1];
|
scale = args[1];
|
||||||
if(nargs > 2)
|
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(strncmp(size, "0x", 2) == 0){
|
||||||
if(vbemodeinfo(vbe, strtol(size+2, nil, 16), &vm) == 0)
|
if(vbemodeinfo(vbe, strtol(size+2, nil, 16), &vm) == 0)
|
||||||
goto havemode;
|
goto havemode;
|
||||||
|
@ -190,10 +200,17 @@ dbvesamode(char *size)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(display != 0 && setdisplay(vbe, olddisplay) == 0)
|
||||||
|
vbesetmode(vbe, oldmode);
|
||||||
|
|
||||||
werrstr("no such vesa mode");
|
werrstr("no such vesa mode");
|
||||||
return nil;
|
return nil;
|
||||||
|
|
||||||
havemode:
|
havemode:
|
||||||
|
if(display != 0 && setdisplay(vbe, olddisplay) == 0)
|
||||||
|
vbesetmode(vbe, oldmode);
|
||||||
|
|
||||||
m = alloc(sizeof(Mode));
|
m = alloc(sizeof(Mode));
|
||||||
m->x = vm.dx;
|
m->x = vm.dx;
|
||||||
m->y = vm.dy;
|
m->y = vm.dy;
|
||||||
|
@ -248,11 +265,11 @@ havemode:
|
||||||
}
|
}
|
||||||
|
|
||||||
/* display id */
|
/* display id */
|
||||||
if(display != nil){
|
if(display != 0){
|
||||||
a = alloc(sizeof(Attr));
|
a = alloc(sizeof(Attr));
|
||||||
a->attr = "display";
|
a->attr = "display";
|
||||||
a->val = alloc(2);
|
a->val = alloc(2);
|
||||||
strncpy(a->val, display, 2);
|
a->val[0] = '0' + display;
|
||||||
|
|
||||||
a->next = m->attr;
|
a->next = m->attr;
|
||||||
m->attr = a;
|
m->attr = a;
|
||||||
|
@ -302,6 +319,7 @@ static void
|
||||||
load(Vga* vga, Ctlr* ctlr)
|
load(Vga* vga, Ctlr* ctlr)
|
||||||
{
|
{
|
||||||
int mode, display;
|
int mode, display;
|
||||||
|
int oldmode, olddisplay;
|
||||||
char *ds;
|
char *ds;
|
||||||
|
|
||||||
if(vbe == nil)
|
if(vbe == nil)
|
||||||
|
@ -309,16 +327,29 @@ load(Vga* vga, Ctlr* ctlr)
|
||||||
mode = atoi(dbattr(vga->mode->attr, "id"));
|
mode = atoi(dbattr(vga->mode->attr, "id"));
|
||||||
ds = dbattr(vga->mode->attr, "display");
|
ds = dbattr(vga->mode->attr, "display");
|
||||||
display = ds == nil ? 0 : atoi(ds);
|
display = ds == nil ? 0 : atoi(ds);
|
||||||
|
olddisplay = oldmode = 0;
|
||||||
|
|
||||||
/* need to reset scaling before switching displays */
|
/* need to reset scaling before switching displays */
|
||||||
if(vbe->scale != nil)
|
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;
|
ctlr->flag |= Ferror;
|
||||||
fprint(2, "vbesetmode: %r\n");
|
fprint(2, "vbesetmode: %r\n");
|
||||||
}else if(vbe->scale != nil)
|
}else if(vbe->scale != nil)
|
||||||
vbe->scale(vga, ctlr, 0);
|
vbe->scale(vga, ctlr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -351,7 +382,7 @@ dump(Vga*, Ctlr*)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
intelscale(Vga* vga, Ctlr* ctlr, int reset)
|
intelscale(Vga* vga, Ctlr* ctlr)
|
||||||
{
|
{
|
||||||
Ureg u;
|
Ureg u;
|
||||||
int cx;
|
int cx;
|
||||||
|
@ -360,31 +391,31 @@ intelscale(Vga* vga, Ctlr* ctlr, int reset)
|
||||||
if(vbe == nil)
|
if(vbe == nil)
|
||||||
error("no vesa bios\n");
|
error("no vesa bios\n");
|
||||||
|
|
||||||
/* NOTE: intel doesn't support "aspect" scaling mode :( */
|
if(vga == nil)
|
||||||
scale = dbattr(vga->mode->attr, "scale");
|
|
||||||
if(scale == nil)
|
|
||||||
cx = 0;
|
|
||||||
else if(strcmp(scale, "scalefull") == 0)
|
|
||||||
cx = 4;
|
cx = 4;
|
||||||
else{
|
else{
|
||||||
ctlr->flag |= Ferror;
|
/* NOTE: intel doesn't support "aspect" scaling mode :( */
|
||||||
fprint(2, "vbescale: unsupported mode %s\n", scale);
|
scale = dbattr(vga->mode->attr, "scale");
|
||||||
return;
|
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);
|
vbesetup(vbe, &u, 0x5F61);
|
||||||
u.bx = 0;
|
u.bx = 0;
|
||||||
u.cx = cx; /* horizontal */
|
u.cx = cx; /* horizontal */
|
||||||
u.dx = cx; /* vertical */
|
u.dx = cx; /* vertical */
|
||||||
vbecall(vbe, &u);
|
vbecall(vbe, &u);
|
||||||
if(u.ax != 0x5f)
|
|
||||||
fprint(2, "vbescale: %#.4lux", u.ax);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
nvidiascale(Vga* vga, Ctlr* ctlr, int reset)
|
nvidiascale(Vga* vga, Ctlr* ctlr)
|
||||||
{
|
{
|
||||||
Ureg u;
|
Ureg u;
|
||||||
int cx;
|
int cx;
|
||||||
|
@ -393,26 +424,26 @@ nvidiascale(Vga* vga, Ctlr* ctlr, int reset)
|
||||||
if(vbe == nil)
|
if(vbe == nil)
|
||||||
error("no vesa bios\n");
|
error("no vesa bios\n");
|
||||||
|
|
||||||
scale = dbattr(vga->mode->attr, "scale");
|
if(vga == nil)
|
||||||
if(scale == nil)
|
|
||||||
cx = 1;
|
|
||||||
else if(strcmp(scale, "scaleaspect") == 0)
|
|
||||||
cx = 3;
|
|
||||||
else if(strcmp(scale, "scalefull") == 0)
|
|
||||||
cx = 0;
|
cx = 0;
|
||||||
else{
|
else{
|
||||||
ctlr->flag |= Ferror;
|
scale = dbattr(vga->mode->attr, "scale");
|
||||||
fprint(2, "vbescale: unsupported mode %s\n", scale);
|
if(scale == nil)
|
||||||
return;
|
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);
|
vbesetup(vbe, &u, 0x4F14);
|
||||||
u.bx = 0x102;
|
u.bx = 0x102;
|
||||||
u.cx = cx;
|
u.cx = cx;
|
||||||
if(vbecall(vbe, &u) < 0)
|
|
||||||
fprint(2, "vbescale: %r\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ctlr vesa = {
|
Ctlr vesa = {
|
||||||
|
@ -864,20 +895,25 @@ int
|
||||||
vbegetmode(Vbe *vbe)
|
vbegetmode(Vbe *vbe)
|
||||||
{
|
{
|
||||||
Ureg u;
|
Ureg u;
|
||||||
|
char size[32];
|
||||||
|
Mode *m;
|
||||||
|
|
||||||
vbesetup(vbe, &u, 0x4F03);
|
vbesetup(vbe, &u, 0x5F29);
|
||||||
if(vbecall(vbe, &u) < 0)
|
u.bx = 0x8000; /* current mode */
|
||||||
return 0;
|
vbecall(vbe, &u);
|
||||||
return u.bx;
|
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
|
int
|
||||||
vbesetmode(Vbe *vbe, int id, int display)
|
vbesetmode(Vbe *vbe, int id)
|
||||||
{
|
{
|
||||||
Ureg u;
|
Ureg u;
|
||||||
|
|
||||||
if(setdisplay(vbe, display) < 0)
|
|
||||||
return -1;
|
|
||||||
vbesetup(vbe, &u, 0x4F02);
|
vbesetup(vbe, &u, 0x4F02);
|
||||||
u.bx = id;
|
u.bx = id;
|
||||||
if(id != 3)
|
if(id != 3)
|
||||||
|
@ -895,7 +931,7 @@ vesatextmode(void)
|
||||||
}
|
}
|
||||||
if(vbecheck(vbe) < 0)
|
if(vbecheck(vbe) < 0)
|
||||||
error("vbecheck: %r\n");
|
error("vbecheck: %r\n");
|
||||||
if(vbesetmode(vbe, 3, 0) < 0)
|
if(vbesetmode(vbe, 3) < 0)
|
||||||
error("vbesetmode: %r\n");
|
error("vbesetmode: %r\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -928,6 +964,23 @@ vbeddcedid(Vbe *vbe, Edid *e)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
getdisplay(Vbe *vbe)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for(i = 0; i < 8; i++)
|
||||||
|
if(vbe->dspact & 1<<i)
|
||||||
|
return i+1;
|
||||||
|
|
||||||
|
/* fallback to a connected one */
|
||||||
|
for(i = 0; i < 8; i++)
|
||||||
|
if(vbe->dspcon & 1<<i)
|
||||||
|
return i+1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
setdisplay(Vbe *vbe, int display)
|
setdisplay(Vbe *vbe, int display)
|
||||||
{
|
{
|
||||||
|
@ -937,6 +990,9 @@ setdisplay(Vbe *vbe, int display)
|
||||||
if(display == 0)
|
if(display == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
/* switch to common mode before trying */
|
||||||
|
vbesetmode(vbe, 3);
|
||||||
|
|
||||||
cx = 1<<(display-1);
|
cx = 1<<(display-1);
|
||||||
if(vbe->dspcon & cx){
|
if(vbe->dspcon & cx){
|
||||||
vbesetup(vbe, &u, 0x5F64);
|
vbesetup(vbe, &u, 0x5F64);
|
||||||
|
|
Loading…
Reference in a new issue