shithub: riscv

Download patch

ref: 90b4fe9cf65bb24b55472ce2e32a7dbc3c5e7f97
parent: cda46731d8166e5b113a8acdf90479a03bb6a3a8
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Tue Jun 9 05:17:55 EDT 2015

zynq: add /dev/fbctl to attach framebuffer to devdraw

--- a/sys/src/9/zynq/devarch.c
+++ b/sys/src/9/zynq/devarch.c
@@ -11,6 +11,7 @@
 	Qdir = 0,
 	Qtemp,
 	Qpl,
+	Qfbctl,
 	Qbase,
 
 	Qmax = 16,
@@ -20,6 +21,7 @@
 	".",		{ Qdir, 0, QTDIR },	0,	0555,
 	"temp",		{ Qtemp, 0},		0,	0440,
 	"pl",		{ Qpl, 0 }, 		0,	0660,
+	"fbctl",	{ Qfbctl, 0 }, 		0,	0660,
 };
 static int narchdir = Qbase;
 
@@ -291,6 +293,8 @@
 		qunlock(&plrlock);
 		poperror();
 		return 0;
+	case Qfbctl:
+		return fbctlread(c, a, n, offset);
 	default:
 		error(Egreg);
 		return -1;
@@ -298,11 +302,13 @@
 }
 
 static long
-archwrite(Chan *c, void *a, long n, vlong)
+archwrite(Chan *c, void *a, long n, vlong offset)
 {
 	switch((ulong)c->qid.path){
 	case Qpl:
 		return plcopy(a, n);
+	case Qfbctl:
+		return fbctlwrite(c, a, n, offset);
 	default:
 		error(Egreg);
 		return -1;
--- a/sys/src/9/zynq/fns.h
+++ b/sys/src/9/zynq/fns.h
@@ -53,6 +53,8 @@
 void intrinit(void);
 void intr(Ureg *);
 int uartconsole(void);
+long fbctlread(Chan*,void*,long,vlong);
+long fbctlwrite(Chan*,void*,long,vlong);
 void fpoff(void);
 void fpsave(FPsave *);
 void fprestore(FPsave *);
--- a/sys/src/9/zynq/screen.c
+++ b/sys/src/9/zynq/screen.c
@@ -13,23 +13,16 @@
 #include "screen.h"
 
 Memimage *gscreen;
-static Memdata xgdata;
 
-static Memimage xgscreen =
-{
-	{ 0, 0, 800, 600 },	/* r */
-	{ 0, 0, 800, 600 },	/* clipr */
-	24,			/* depth */
-	3,			/* nchan */
-	BGR24,			/* chan */
-	nil,			/* cmap */
-	&xgdata,		/* data */
-	0,			/* zero */
-	0, 			/* width in words of a single scan line */
-	0,			/* layer */
-	0,			/* flags */
-};
+static struct {
+	Rendez;
 
+	Rectangle	rect;
+	Proc		*proc;
+
+	uintptr		addr;
+} fbscreen;
+
 void
 cursoron(void)
 {
@@ -46,47 +39,33 @@
 }
 
 void
-flushmemscreen(Rectangle)
+flushmemscreen(Rectangle r)
 {
+	combinerect(&fbscreen.rect, r);
+	wakeup(&fbscreen);
 }
 
 void
-drawflushreal(void)
-{
-	uchar *fb, *fbe;
-	
-	fb = xgdata.bdata;
-	fbe = fb + Dx(xgscreen.r) * Dy(xgscreen.r) * 3;
-	cleandse(fb, fbe);
-	clean2pa(PADDR(fb), PADDR(fbe));
-}
-
-void
 screeninit(void)
 {
-	uchar *fb;
-
-	fb = xspanalloc(Dx(xgscreen.r) * Dy(xgscreen.r) * 3, 64, 0);
-	print("%p\n", PADDR(fb));
-	memsetchan(&xgscreen, BGR24);
 	conf.monitor = 1;
-	xgdata.bdata = fb;
-	xgdata.ref = 1;
-	gscreen = &xgscreen;
-	gscreen->width = wordsperline(gscreen->r, gscreen->depth);
-
-	memimageinit();
 }
 
 uchar*
 attachscreen(Rectangle *r, ulong *chan, int* d, int *width, int *softscreen)
 {
+	if(gscreen == nil)
+		return nil;
+
 	*r = gscreen->r;
 	*d = gscreen->depth;
 	*chan = gscreen->chan;
 	*width = gscreen->width;
-	*softscreen = 0;
 
+	/* make devdraw use gscreen->data */
+	*softscreen = 0xa110c;
+	gscreen->data->ref++;
+
 	return gscreen->data->bdata;
 }
 
@@ -110,3 +89,177 @@
 mousectl(Cmdbuf *)
 {
 }
+
+static int
+isflush(void *)
+{
+	return !badrect(fbscreen.rect);
+}
+
+static void
+flushproc(void *arg)
+{
+	int sno, n, w;
+	uchar *sp, *dp, *top;
+	Rectangle r;
+
+	for(sno = 0; sno < NSEG; sno++)
+		if(up->seg[sno] == nil && sno != ESEG)
+			break;
+	if(sno == NSEG)
+		panic("flushproc");
+
+	up->seg[sno] = arg;
+
+	cclose(up->dot);
+	up->dot = up->slash;
+	incref(up->dot);
+
+	fbscreen.proc = up;
+	if(waserror()){
+		print("flushproc: %s\n", up->errstr);
+		fbscreen.addr = 0;
+		fbscreen.proc = nil;
+		return;
+	}
+
+	for(;;){
+		sleep(&fbscreen, isflush, nil);
+
+		eqlock(&drawlock);
+		r = fbscreen.rect;
+		fbscreen.rect = ZR;
+		if(badrect(r) || gscreen == nil || rectclip(&r, gscreen->r) == 0){
+			qunlock(&drawlock);
+			continue;
+		}
+		w = sizeof(ulong)*gscreen->width;
+		n = bytesperline(r, gscreen->depth);
+		sp = byteaddr(gscreen, r.min);
+		dp = (uchar*)fbscreen.addr + (sp - &gscreen->data->bdata[gscreen->zero]);
+		top = (uchar*)up->seg[sno]->top;
+		if(dp+(Dy(r)-1)*w+n > top)
+			r.max.y = (top-(uchar*)fbscreen.addr)/w;
+		qunlock(&drawlock);
+
+		while(r.min.y < r.max.y) {
+			memmove(dp, sp, n);
+			sp += w;
+			dp += w;
+			r.min.y++;
+		}
+	}
+}
+
+enum {
+	CMaddr,
+	CMsize,
+	CMinit,
+};
+
+static Cmdtab fbctlmsg[] = {
+	CMaddr,		"addr",		2,
+	CMsize,		"size",		3,
+	CMinit,		"init",		1,
+};
+
+long
+fbctlwrite(Chan*, void *a, long n, vlong)
+{
+	Cmdbuf *cb;
+	Cmdtab *ct;
+	ulong x, y, z, chan;
+	Segment *s;
+	uintptr addr;
+	char *p;
+
+	cb = parsecmd(a, n);
+	if(waserror()){
+		free(cb);
+		nexterror();
+	}
+	ct = lookupcmd(cb, fbctlmsg, nelem(fbctlmsg));
+	switch(ct->index){
+	case CMaddr:
+		addr = strtoul(cb->f[1], 0, 0);
+
+		eqlock(&up->seglock);
+		if((s = seg(up, addr, 0)) == nil || (s->type&SG_RONLY) != 0){
+			qunlock(&up->seglock);
+			error(Ebadarg);
+		}
+		incref(s);
+		qunlock(&up->seglock);
+
+		if(fbscreen.proc != nil){
+			postnote(fbscreen.proc, 0, "die", NUser);
+			while(fbscreen.proc != nil)
+				sched();
+		}
+		fbscreen.addr = addr;
+		kproc("fbflush", flushproc, s);
+		break;
+
+	case CMsize:
+		x = strtoul(cb->f[1], &p, 0);
+		if(x == 0 || x > 10240)
+			error(Ebadarg);
+		if(*p)
+			p++;
+		y = strtoul(p, &p, 0);
+		if(y == 0 || y > 10240)
+			error(Ebadarg);
+		if(*p)
+			p++;
+		z = strtoul(p, &p, 0);
+
+		if((chan = strtochan(cb->f[2])) == 0)
+			error("bad channel");
+		if(chantodepth(chan) != z)
+			error("depth, channel do not match");
+
+		cursoroff();
+		deletescreenimage();
+		eqlock(&drawlock);
+		if(memimageinit() < 0){
+			qunlock(&drawlock);
+			error("memimageinit failed");
+		}
+		if(gscreen != nil){
+			freememimage(gscreen);
+			gscreen = nil;
+		}
+		gscreen = allocmemimage(Rect(0,0,x,y), chan);
+		qunlock(&drawlock);
+		/* wet floor */
+
+	case CMinit:
+		if(gscreen == nil)
+			error("no framebuffer");
+		resetscreenimage();
+		cursoron();
+		break;
+	}
+	free(cb);
+	poperror();
+	return n;
+}
+
+long
+fbctlread(Chan*, void *a, long n, vlong offset)
+{
+	char buf[256], chan[32], *p, *e;
+
+	p = buf;
+	e = p + sizeof(buf);
+	qlock(&drawlock);
+	if(gscreen != nil){
+		p = seprint(p, e, "size %dx%dx%d %s\n",
+			Dx(gscreen->r), Dy(gscreen->r), gscreen->depth,
+			chantostr(chan, gscreen->chan));
+	}
+	qunlock(&drawlock);
+	seprint(p, e, "addr %#p\n", fbscreen.addr);
+	return readstr(offset, a, n, buf);
+}
+
--- a/sys/src/9/zynq/screen.h
+++ b/sys/src/9/zynq/screen.h
@@ -32,6 +32,8 @@
 extern void	setcursor(Cursor*);
 
 /* devdraw.c */
+extern void	deletescreenimage(void);
+extern void	resetscreenimage(void);
 extern QLock	drawlock;
 
 #define ishwimage(i)	1		/* for ../port/devdraw.c */