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

This commit is contained in:
cinap_lenrek 2015-06-09 09:17:55 +02:00
parent cda46731d8
commit 90b4fe9cf6
4 changed files with 203 additions and 40 deletions

View file

@ -11,6 +11,7 @@ enum {
Qdir = 0,
Qtemp,
Qpl,
Qfbctl,
Qbase,
Qmax = 16,
@ -20,6 +21,7 @@ static Dirtab archdir[Qmax] = {
".", { 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 @@ archread(Chan *c, void *a, long n, vlong offset)
qunlock(&plrlock);
poperror();
return 0;
case Qfbctl:
return fbctlread(c, a, n, offset);
default:
error(Egreg);
return -1;
@ -298,11 +302,13 @@ archread(Chan *c, void *a, long n, vlong offset)
}
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;

View file

@ -53,6 +53,8 @@ void intrenable(int, void (*)(Ureg *, void *), void *, int, char *);
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 *);

View file

@ -13,22 +13,15 @@
#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,46 +39,32 @@ setcursor(Cursor*)
}
void
flushmemscreen(Rectangle)
flushmemscreen(Rectangle r)
{
}
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));
combinerect(&fbscreen.rect, r);
wakeup(&fbscreen);
}
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 @@ void
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);
}

View file

@ -32,6 +32,8 @@ extern void cursoroff(void);
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 */