#include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "io.h" #include "../port/error.h" #define Image IMAGE #include #include #include #include "screen.h" Memimage *gscreen; static struct { Rendez; Rectangle rect; Proc *proc; uintptr addr; } fbscreen; static struct { Rendez; Cursor; Proc *proc; uintptr addr; } hwcursor; void cursoron(void) { wakeup(&hwcursor); } void cursoroff(void) { } void setcursor(Cursor *curs) { hwcursor.Cursor = *curs; } void flushmemscreen(Rectangle r) { if(badrect(fbscreen.rect)) fbscreen.rect = r; else combinerect(&fbscreen.rect, r); wakeup(&fbscreen); } void screeninit(void) { conf.monitor = 1; } 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; /* make devdraw use gscreen->data */ *softscreen = 0xa110c; gscreen->data->ref++; return gscreen->data->bdata; } void getcolor(ulong, ulong *, ulong *, ulong *) { } int setcolor(ulong, ulong, ulong, ulong) { return 0; } void blankscreen(int) { } static void cursorproc(void *arg) { uchar *set, *clr; u32int *reg; Point xy; int i; for(i = 0; i < NSEG; i++) if(up->seg[i] == nil && i != ESEG) break; if(i == NSEG) panic(up->text); up->seg[i] = arg; hwcursor.proc = up; if(waserror()){ hwcursor.addr = 0; hwcursor.proc = nil; pexit("detached", 1); } reg = (u32int*)hwcursor.addr; for(;;){ eqlock(&drawlock); xy = addpt(mousexy(), hwcursor.offset); qunlock(&drawlock); set = hwcursor.set; clr = hwcursor.clr; for(i=0; i<8; i++){ reg[0x70/4 + i] = clr[i*4]<<24 | clr[i*4+1]<<16 | clr[i*4+2]<<8 | clr[i*4+3]; reg[0x90/4 + i] = set[i*4]<<24 | set[i*4+1]<<16 | set[i*4+2]<<8 | set[i*4+3]; } reg[0] = (xy.x<<16) | (xy.y&0xFFFF); sleep(&hwcursor, return0, nil); } } void mousectl(Cmdbuf *cb) { Segment *s; uintptr addr; if(strcmp(cb->f[0], "addr") == 0 && cb->nf == 2){ s = nil; addr = strtoul(cb->f[1], 0, 0); if(addr != 0){ if((s = seg(up, addr, 0)) == nil || (s->type&SG_RONLY) != 0 || (addr&3) != 0 || addr+0xB0 > s->top) error(Ebadarg); incref(s); } if(hwcursor.proc != nil){ postnote(hwcursor.proc, 0, "die", NUser); while(hwcursor.proc != nil) sched(); } if(addr != 0){ hwcursor.addr = addr; kproc("cursor", cursorproc, s); } return; } if(strcmp(cb->f[0], "linear") == 0){ mouseaccelerate(0); return; } if(strcmp(cb->f[0], "accelerated") == 0){ mouseaccelerate(cb->nf == 1 ? 1 : atoi(cb->f[1])); return; } } static int isflush(void *) { return !badrect(fbscreen.rect); } static void screenproc(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(up->text); up->seg[sno] = arg; fbscreen.proc = up; if(waserror()){ fbscreen.addr = 0; fbscreen.proc = nil; pexit("detached", 1); } 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: s = nil; addr = strtoul(cb->f[1], 0, 0); if(addr != 0){ if((s = seg(up, addr, 0)) == nil || (s->type&SG_RONLY) != 0) error(Ebadarg); incref(s); } if(fbscreen.proc != nil){ postnote(fbscreen.proc, 0, "die", NUser); while(fbscreen.proc != nil) sched(); } if(addr != 0){ fbscreen.addr = addr; kproc("screen", screenproc, 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"); 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(); 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); }