shithub: riscv

Download patch

ref: 8067368e10330a67550f9e3ee353da858266a6eb
parent: e34fa15921cd76d78e7adc28e471204de036d66a
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sun Feb 1 21:58:59 EST 2015

aux/vga: use optional edid information to determine mode when vgadb fails

igfx and vesa can determine monitor timing information from ddc
and store the edid info for connected monitors in vga->edid[].
when monitor type cannot be found in vgadb, we consult the edid
information and make a mode based on the edid info.

this avoids having to maintain a vgadb entry for each monitor.

monitor can be set to "[width]x[height]@[freq]Hz" for a specific
edid setting. when not found, a mode is searched based on the
size.

so the following should work:

aux/vga -m 1366x768@60Hz -l 1366x768x32
aux/vga -m auto -l 1366x768x32

--- a/sys/src/cmd/aux/vga/db.c
+++ b/sys/src/cmd/aux/vga/db.c
@@ -16,20 +16,35 @@
 	return db;
 }
 
+Attr*
+mkattr(Attr *tail, char *attr, char *fmt, ...)
+{
+	char val[1024];
+	va_list list;
+	Attr *a;
+
+	va_start(list, fmt);
+	snprint(val, sizeof(val), fmt, list);
+	va_end(list);
+
+	a = alloc(sizeof(Attr));
+	a->attr = alloc(strlen(attr)+1);
+	strcpy(a->attr, attr);
+	a->val = alloc(strlen(val)+1);
+	strcpy(a->val, val);
+	a->next = tail;
+
+	return a;
+}
+
 static void
 addattr(Attr** app, Ndbtuple* t)
 {
-	Attr *attr, *l;
+	Attr *l;
 
-	attr = alloc(sizeof(Attr));
-	attr->attr = alloc(strlen(t->attr)+1);
-	strcpy(attr->attr, t->attr);
-	attr->val = alloc(strlen(t->val)+1);
-	strcpy(attr->val, t->val);
-
 	for(l = *app; l; l = l->next)
 		app = &l->next;
-	*app = attr;
+	*app = mkattr(nil, t->attr, "%s", t->val);
 }
 
 char*
@@ -40,7 +55,6 @@
 			return ap->val;
 		ap = ap->next;
 	}
-
 	return 0;
 }
 
--- a/sys/src/cmd/aux/vga/edid.c
+++ b/sys/src/cmd/aux/vga/edid.c
@@ -5,7 +5,6 @@
 
 #include "pci.h"
 #include "vga.h"
-#include "edid.h"
 
 static Modelist*
 addmode(Modelist *l, Mode m)
@@ -182,20 +181,22 @@
 	return vesalookup(m, str);
 }
 
-int
-parseedid128(Edid *e, void *v)
+Edid*
+parseedid128(void *v)
 {
 	static uchar magic[8] = { 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00 };
 	uchar *p, *q, sum;
 	int dpms, estab, i, m, vid;
 	Mode mode;
+	Edid *e;
 
-	memset(e, 0, sizeof *e);
+	e = alloc(sizeof(Edid));
 
 	p = (uchar*)v;
 	if(memcmp(p, magic, 8) != 0) {
+		free(e);
 		werrstr("bad edid header");
-		return -1;
+		return nil;
 	}
 
 	sum = 0;
@@ -202,8 +203,9 @@
 	for(i=0; i<128; i++) 
 		sum += p[i];
 	if(sum != 0) {
+		free(e);
 		werrstr("bad edid checksum");
-		return -1;
+		return nil;
 	}
 	p += 8;
 
@@ -342,7 +344,7 @@
 	}
 
 	assert(p == (uchar*)v+8+10+2+5+10+3+16+72);
-	return 0;
+	return e;
 }
 
 Flag edidflags[] = {
--- a/sys/src/cmd/aux/vga/edid.h
+++ /dev/null
@@ -1,50 +1,0 @@
-typedef struct Modelist Modelist;
-typedef struct Edid Edid;
-typedef struct Flag Flag;
-
-struct Edid {
-	char		mfr[4];		/* manufacturer */
-	char		serialstr[16];	/* serial number as string (in extended data) */
-	char		name[16];	/* monitor name as string (in extended data) */
-	ushort		product;	/* product code, 0 = unused */
-	ulong		serial;		/* serial number, 0 = unused */
-	uchar		version;	/* major version number */
-	uchar		revision;	/* minor version number */
-	uchar		mfrweek;	/* week of manufacture, 0 = unused */
-	int		mfryear;	/* year of manufacture, 0 = unused */
-	uchar 		dxcm;		/* horizontal image size in cm. */
-	uchar		dycm;		/* vertical image size in cm. */
-	int		gamma;		/* gamma*100 */
-	int		rrmin;		/* minimum vertical refresh rate */
-	int		rrmax;		/* maximum vertical refresh rate */
-	int		hrmin;		/* minimum horizontal refresh rate */
-	int		hrmax;		/* maximum horizontal refresh rate */
-	ulong		pclkmax;	/* maximum pixel clock */
-	int		flags;
-	Modelist	*modelist;	/* list of supported modes */
-};
-
-struct Modelist
-{
-	Mode;
-	Modelist *next;
-};
-
-struct Flag {
-	int bit;
-	char *desc;
-};
-
-enum {
-	Fdigital	= 1<<0,	/* is a digital display */
-	Fdpmsstandby	= 1<<1,	/* supports DPMS standby mode */
-	Fdpmssuspend	= 1<<2,	/* supports DPMS suspend mode */
-	Fdpmsactiveoff	= 1<<3,	/* supports DPMS active off mode */
-	Fmonochrome	= 1<<4,	/* is a monochrome display */
-	Fgtf		= 1<<5,	/* supports VESA GTF: see /public/doc/vesa/gtf10.pdf */
-};
-Flag	edidflags[];
-void	printflags(Flag *f, int b);
-
-int	parseedid128(Edid *e, void *v);
-void	printedid(Edid *e);
--- a/sys/src/cmd/aux/vga/igfx.c
+++ b/sys/src/cmd/aux/vga/igfx.c
@@ -4,7 +4,6 @@
 
 #include "pci.h"
 #include "vga.h"
-#include "edid.h"
 
 typedef struct Reg Reg;
 typedef struct Dpll Dpll;
@@ -156,9 +155,6 @@
 	Reg	lvds;
 
 	Reg	vgacntrl;
-
-	Edid	*adpaedid;
-	Edid	*lvdsedid;
 };
 
 static u32int
@@ -465,8 +461,13 @@
 	for(x=0; x<igfx->npipe; x++)
 		snarfpipe(igfx, x);
 
-	igfx->adpaedid = snarfedid(igfx, 2, 0x50);
-	igfx->lvdsedid = snarfedid(igfx, 3, 0x50);
+	vga->edid[0] = snarfedid(igfx, 2, 0x50);
+	vga->edid[1] = snarfedid(igfx, 3, 0x50);
+	if(vga->edid[1] != nil){
+		Modelist *l;
+		for(l = vga->edid[1]->modelist; l != nil; l = l->next)
+			l->attr = mkattr(l->attr, "lcd", "1");
+	}
 
 	ctlr->flag |= Fsnarf;
 }
@@ -1332,15 +1333,6 @@
 	dumpreg(ctlr->name, "sdvoc", igfx->sdvoc);
 
 	dumpreg(ctlr->name, "vgacntrl", igfx->vgacntrl);
-
-	if(igfx->adpaedid != nil){
-		Bprint(&stdout, "edid adpa\n");
-		printedid(igfx->adpaedid);
-	}
-	if(igfx->lvdsedid != nil){
-		Bprint(&stdout, "edid lvds\n");
-		printedid(igfx->lvdsedid);
-	}
 }
 
 enum {
@@ -1404,7 +1396,6 @@
 snarfedid(Igfx *igfx, int port, int addr)
 {
 	uchar buf[256], tmp[256];
-	Edid *e;
 	int i;
 
 	/* read twice */
@@ -1424,13 +1415,7 @@
 		}
 	}
 
-	e = malloc(sizeof(Edid));
-	if(parseedid128(e, buf) != 0){
-		free(e);
-		return nil;
-	}
-
-	return e;
+	return parseedid128(buf);
 }
 
 Ctlr igfx = {
--- a/sys/src/cmd/aux/vga/main.c
+++ b/sys/src/cmd/aux/vga/main.c
@@ -17,6 +17,7 @@
 {
 	Ctlr *ctlr;
 	Attr *attr;
+	int i;
 	
 	if(vga->mode)
 		dbdumpmode(vga->mode);
@@ -37,6 +38,12 @@
 		(*ctlr->dump)(vga, ctlr);
 		ctlr->flag |= Fdump;
 	}
+
+	for(i=0; i < nelem(vga->edid); i++){
+		if(vga->edid[i])
+			printedid(vga->edid[i]);
+	}
+
 	Bprint(&stdout, "\n");
 }
 
@@ -135,6 +142,54 @@
 		vgactlw("linear", "0");
 }
 
+static Mode*
+dbedidmode(Vga *vga, char *type, char *size)
+{
+	char buf[32], *p;
+	int i, x, y, z;
+	Modelist *l;
+	Mode *m;
+
+	z = 32;
+	x = y = 0;
+	snprint(buf, sizeof(buf), "%s", size);
+	if((p = strchr(buf, 'x')) != nil){
+		*p++ = 0;
+		x = atoi(buf);
+		y = atoi(p);
+		if((p = strchr(p, 'x')) != nil){
+			*p++ = 0;
+			z = atoi(p);
+		}
+	}
+
+	for(i=0; i<nelem(vga->edid); i++){
+		if(vga->edid[i] == nil)
+			continue;
+		for(l = vga->edid[i]->modelist; l != nil; l = l->next)
+			if(strcmp(l->name, type) == 0)
+				goto found;
+	}
+	for(i=0; i<nelem(vga->edid); i++){
+		if(vga->edid[i] == nil)
+			continue;
+		for(l = vga->edid[i]->modelist; l != nil; l = l->next)
+			if((x == 0 || l->x == x) && (y == 0 || l->y == y))
+				goto found;
+	}
+	return nil;
+
+found:
+	m = alloc(sizeof(Mode));
+	*m = *((Mode*)l);
+	m->z = z;
+	x = m->x;
+	y = m->y;
+	snprint(m->type, sizeof(m->type), "%s", type);
+	snprint(m->size, sizeof(m->size), "%dx%dx%d", x, y, z);
+	return m;
+}
+
 char*
 chanstr[32+1] = {
 [1]	"k1",
@@ -291,10 +346,13 @@
 
 		if(vga->vesa){
 			strcpy(monitordb, "vesa bios");
-			vga->mode = dbvesamode(psize);
-		}else
+			vga->mode = dbvesamode(vga, psize);
+		}else {
 			vga->mode = dbmode(monitordb, type, psize);
-		if(vga->mode == 0)
+			if(vga->mode == nil)
+				vga->mode = dbedidmode(vga, type, psize);
+		}
+		if(vga->mode == nil)
 			error("main: %s@%s not in %s\n", type, psize, monitordb);
 
 		if(virtual){
--- a/sys/src/cmd/aux/vga/mkfile
+++ b/sys/src/cmd/aux/vga/mkfile
@@ -68,7 +68,6 @@
 HFILES=\
 	pci.h\
 	vga.h\
-	edid.h\
 
 UPDATE=\
 	mkfile\
--- a/sys/src/cmd/aux/vga/vesa.c
+++ b/sys/src/cmd/aux/vga/vesa.c
@@ -6,7 +6,6 @@
 
 #include "pci.h"
 #include "vga.h"
-#include "edid.h"
 
 typedef struct Vbe Vbe;
 typedef struct Vmode Vmode;
@@ -49,7 +48,6 @@
 #define PLONG(p, v) (p)[0] = (v); (p)[1] = (v)>>8; (p)[2] = (v)>>16; (p)[3] = (v)>>24
 
 static Vbe *vbe;
-static Edid *edid;
 
 static int dspcon;	/* connected displays bitmask */
 static int dspact;	/* active displays bitmask */
@@ -65,7 +63,7 @@
 void vbeprintmodeinfo(Vbe*, int, char*);
 int vbesnarf(Vbe*, Vga*);
 void vesaddc(void);
-int vbeddcedid(Vbe *vbe, Edid *e);
+Edid* vbeddcedid(Vbe *vbe);
 uchar* vbesetup(Vbe*, Ureg*, int);
 int vbecall(Vbe*, Ureg*);
 int setdisplay(Vbe *vbe, int display);
@@ -99,25 +97,6 @@
 	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)
 {
@@ -141,7 +120,7 @@
 }
 
 Mode*
-dbvesamode(char *size)
+dbvesamode(Vga *vga, char *size)
 {
 	int i, width, display;
 	int oldmode, olddisplay;
@@ -217,8 +196,10 @@
 		*m = *vesamodes[i];
 		break;
 	}
-	if(edid != nil){
-		for(l = edid->modelist; l; l = l->next){
+	for(i=0; i<nelem(vga->edid); i++){
+		if(vga->edid[i] == nil)
+			continue;
+		for(l = vga->edid[i]->modelist; l; l = l->next){
 			if(l->x != vm.dx || l->y != vm.dy)
 				continue;
 			*m = *((Mode*)l);
@@ -234,14 +215,14 @@
 	/* account for framebuffer stride */
 	width = vm.bpl * 8 / m->z;
 	if(width > m->x)
-		m->attr = newattr(m->attr, "virtx", "%d", width);
+		m->attr = mkattr(m->attr, "virtx", "%d", width);
 
 	if(scale != nil)
-		m->attr = newattr(m->attr, "scale", "%s", scale);
+		m->attr = mkattr(m->attr, "scale", "%s", scale);
 	if(display != 0)
-		m->attr = newattr(m->attr, "display", "%d", display);
+		m->attr = mkattr(m->attr, "display", "%d", display);
 
-	m->attr = newattr(m->attr, "id", "0x%x", vm.id);
+	m->attr = mkattr(m->attr, "id", "0x%x", vm.id);
 
 	return m;
 }
@@ -317,7 +298,7 @@
 }
 
 static void
-dump(Vga*, Ctlr*)
+dump(Vga *, Ctlr*)
 {
 	int i;
 	char did[0x200];
@@ -341,8 +322,6 @@
 	for(i=0x100; i<0x1FF; i++)
 		if(!did[i])
 			vbeprintmodeinfo(vbe, i, " (unoffered)");
-	if(edid != nil)
-		printedid(edid);
 }
 
 static int
@@ -644,16 +623,11 @@
 		dspact = u.cx;
 
 	}
-	else if(memcmp(oem, "NVIDIA", 6) == 0 && 0)	/* untested */
+	else if(memcmp(oem, "NVIDIA", 6) == 0)
 		setscale = nvidiascale;
 
-	if(edid == nil){
-		edid = alloc(sizeof(Edid));
-		if(vbeddcedid(vbe, edid) < 0){
-			free(edid);
-			edid = nil;
-		}
-	}
+	vga->edid[0] = vbeddcedid(vbe);
+
 	return 0;
 }
 
@@ -864,10 +838,8 @@
 		error("vbesetmode: %r\n");
 }
 
-int parseedid128(Edid *e, void *v);
-
-int
-vbeddcedid(Vbe *vbe, Edid *e)
+Edid*
+vbeddcedid(Vbe *vbe)
 {
 	uchar *p;
 	Ureg u;
@@ -875,12 +847,8 @@
 	p = vbesetup(vbe, &u, 0x4F15);
 	u.bx = 0x0001;
 	if(vbecall(vbe, &u) < 0)
-		return -1;
-	if(parseedid128(e, p) < 0){
-		werrstr("parseedid128: %r");
-		return -1;
-	}
-	return 0;
+		return nil;
+	return parseedid128(p);
 }
 
 int
--- a/sys/src/cmd/aux/vga/vga.h
+++ b/sys/src/cmd/aux/vga/vga.h
@@ -82,12 +82,12 @@
 };
 
 typedef struct Attr Attr;
-typedef struct Attr {
+struct Attr {
 	char*	attr;
 	char*	val;
 
 	Attr*	next;
-} Attr;
+};
 
 typedef struct Mode {
 	char	type[Namelen+1];	/* monitor type e.g. "vs1782" */
@@ -124,6 +124,39 @@
 	Attr*	attr;
 } Mode;
 
+typedef struct Modelist Modelist;
+struct Modelist {
+	Mode;
+	Modelist *next;
+};
+
+typedef struct Edid {
+	char		mfr[4];		/* manufacturer */
+	char		serialstr[16];	/* serial number as string (in extended data) */
+	char		name[16];	/* monitor name as string (in extended data) */
+	ushort		product;	/* product code, 0 = unused */
+	ulong		serial;		/* serial number, 0 = unused */
+	uchar		version;	/* major version number */
+	uchar		revision;	/* minor version number */
+	uchar		mfrweek;	/* week of manufacture, 0 = unused */
+	int		mfryear;	/* year of manufacture, 0 = unused */
+	uchar 		dxcm;		/* horizontal image size in cm. */
+	uchar		dycm;		/* vertical image size in cm. */
+	int		gamma;		/* gamma*100 */
+	int		rrmin;		/* minimum vertical refresh rate */
+	int		rrmax;		/* maximum vertical refresh rate */
+	int		hrmin;		/* minimum horizontal refresh rate */
+	int		hrmax;		/* maximum horizontal refresh rate */
+	ulong		pclkmax;	/* maximum pixel clock */
+	int		flags;
+	Modelist	*modelist;	/* list of supported modes */
+} Edid;
+
+typedef struct Flag {
+	int bit;
+	char *desc;
+} Flag;
+
 /*
  * The sizes of the register sets are large as many SVGA and GUI chips have extras.
  * The Crt registers are ushorts in order to keep overflow bits handy.
@@ -188,11 +221,13 @@
 	Ctlr*	ramdac;
 	Ctlr*	clock;
 	Ctlr*	hwgc;
-	Ctlr* vesa;
+	Ctlr*	vesa;
 	Ctlr*	link;
 	int	linear;
 	Attr*	attr;
 
+	Edid*	edid[8];		/* edid information for connected monitors */
+
 	void*	private;
 } Vga;
 
@@ -247,11 +282,26 @@
 extern ushort dacxreg[4];
 
 /* db.c */
+extern Attr* mkattr(Attr*, char*, char*, ...);
 extern char* dbattr(Attr*, char*);
 extern int dbctlr(char*, Vga*);
 extern Mode* dbmode(char*, char*, char*);
 extern void dbdumpmode(Mode*);
 
+/* edid.c */
+enum {
+	Fdigital	= 1<<0,	/* is a digital display */
+	Fdpmsstandby	= 1<<1,	/* supports DPMS standby mode */
+	Fdpmssuspend	= 1<<2,	/* supports DPMS suspend mode */
+	Fdpmsactiveoff	= 1<<3,	/* supports DPMS active off mode */
+	Fmonochrome	= 1<<4,	/* is a monochrome display */
+	Fgtf		= 1<<5,	/* supports VESA GTF: see /public/doc/vesa/gtf10.pdf */
+};
+extern Flag edidflags[];
+extern void printflags(Flag *f, int b);
+extern Edid* parseedid128(void *v);
+extern void printedid(Edid *e);
+
 /* error.c */
 extern void error(char*, ...);
 extern void trace(char*, ...);
@@ -435,7 +485,7 @@
 extern Ctlr vesa;
 extern Ctlr softhwgc;	/* has to go somewhere */
 extern int dbvesa(Vga*);
-extern Mode *dbvesamode(char*);
+extern Mode *dbvesamode(Vga*,char*);
 extern void vesatextmode(void);
 
 /* vesadb.c */
@@ -466,3 +516,4 @@
 
 #pragma	varargck	argpos	error	1
 #pragma	varargck	argpos	trace	1
+#pragma	varargck	argpos	mkattr	3