shithub: riscv

Download patch

ref: e34fa15921cd76d78e7adc28e471204de036d66a
parent: 7fbed4d63541f9695c00f295e1dfde10bb8d9808
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sun Feb 1 14:28:24 EST 2015

aux/vga: cleanup vesa code

dbvesamode() modified the passed in size string in the process
of option parsing. this is a no-go because the string might be
constant in the read only section. provide cracksize() function
for the parsing and make a static copy.

do the vendor specific monitor detection in vbesnarf() instead
of vbecheck(). vbecheck()'s purpose is to check if vesa bios
service is avialable, not snarf graphics card state.

nvidiascale() was a no-op because it missed the vbecall() at
the end of the function. this means it was never tested so i
add the missing vbecall(), but disable nvidiascale for now
until someone tests this.

keep fancy stuff out of the Vbe structure. it is just there for
making bios calls, not keep state about the graphics card.

--- a/sys/src/cmd/aux/vga/vesa.c
+++ b/sys/src/cmd/aux/vga/vesa.c
@@ -25,9 +25,6 @@
 	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 @@
 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 @@
 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 @@
 	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,48 +231,18 @@
 	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);
+	if(width > m->x)
+		m->attr = newattr(m->attr, "virtx", "%d", width);
 
-		a->next = m->attr;
-		m->attr = a;
-	}
+	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 @@
 {
 	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 @@
 		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 @@
 int
 vbecall(Vbe *vbe, Ureg *u)
 {
+	int ax;
+
+	ax = u->ax >> 8;
 	u->trap = 0x10;
 
 	vbeflush(vbe);
@@ -595,7 +582,7 @@
 
 	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 @@
 int
 vbecheck(Vbe *vbe)
 {
-	char *oem;
 	uchar *p;
 	Ureg u;
 
@@ -621,23 +607,6 @@
 		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;
 }
 
@@ -644,6 +613,7 @@
 int
 vbesnarf(Vbe *vbe, Vga *vga)
 {
+	char *oem;
 	uchar *p;
 	Ureg u;
 
@@ -654,6 +624,29 @@
 	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 @@
 	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 @@
 }
 
 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,7 +910,7 @@
 		return 0;
 
 	cx = 1<<(display-1);
-	if(vbe->dspcon & cx){
+	if(dspcon & cx){
 		/* switch to common mode before trying */
 		vbesetmode(vbe, 3);
 
@@ -921,13 +917,11 @@
 		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