| plan 9 kernel history: overview | file list | diff list |
1995/0508/pc/devvga.c (diff list | history)
| pc/devvga.c on 1992/0527 | ||
| 1992/0527 | #include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "io.h" #include "../port/error.h" | |
| 1992/0603 | #include <libg.h> | |
| 1994/0414 | #include "screen.h" | |
| 1994/0624 | #include "vga.h" | |
| 1992/0527 | ||
| 1993/1116 | enum { | |
| 1995/0406 | /* default footprint is 64k */ | |
| 1994/0412 | Footshift= 16, Footprint= 1<<Footshift, | |
| 1995/0406 | /* CGA screen dimensions */ CGAWIDTH= 160, CGAHEIGHT= 24, }; /* * screen memory addresses */ #define SCREENMEM (0xA0000 | KZERO) #define CGASCREEN ((uchar*)(0xB8000 | KZERO)) static ulong screenmem = SCREENMEM; static int footprint = Footprint; static int footshift = Footshift; static int screendisabled; | |
| 1992/1119 | /* imported */ | |
| 1994/0413 | extern Subfont defont0; | |
| 1995/0126 | extern Cursor curs; /* barf */ | |
| 1992/1119 | /* exported */ | |
| 1994/0413 | Bitmap gscreen; | |
| 1994/0810 | Lock palettelock; /* access to DAC registers */ Cursor curcursor; /* current cursor */ | |
| 1992/1119 | ||
| 1993/1116 | /* vga screen */ static Lock screenlock; | |
| 1995/0126 | static ulong colormap[Pcolours][3]; | |
| 1992/1119 | ||
| 1993/1116 | /* cga screen */ static int cga = 1; /* true if in cga mode */ /* system window */ static Rectangle window; static int h, w; | |
| 1994/0413 | static Point curpos; | |
| 1993/1116 | ||
| 1995/0126 | static void nopage(int); | |
| 1992/1119 | ||
| 1995/0126 | static Vgac vga = { "vga", nopage, | |
| 1993/1116 | ||
| 1994/0624 | 0, }; | |
| 1995/0126 | static Vgac *vgactlr = &vga; /* available VGA ctlrs */ | |
| 1995/0204 | static Vgac *vgac = &vga; /* current VGA ctlr */ | |
| 1995/0126 | static Hwgc *hwgctlr; /* available HWGC's */ Hwgc *hwgc; /* current HWGC */ | |
| 1994/0930 | static char interlaced[2]; | |
| 1994/0624 | ||
| 1994/0415 | /* * work areas for bitblting screen characters, scrolling, and cursor redraw */ Bitmap chwork; Bitmap scrollwork; Bitmap cursorwork; | |
| 1993/1116 | /* predefined for the stupid compiler */ static void setscreen(int, int, int); static void cgascreenputc(int); static void cgascreenputs(char*, int); static void screenputc(char*); static void scroll(void); | |
| 1994/0415 | static void workinit(Bitmap*, int, int); | |
| 1994/0416 | extern void screenload(Rectangle, uchar*, int, int, int); extern void screenunload(Rectangle, uchar*, int, int, int); static void cursorlock(Rectangle); static void cursorunlock(void); | |
| 1993/1116 | ||
| 1994/0416 | extern int graphicssubtile(uchar*, int, int, Rectangle, Rectangle, uchar**); | |
| 1994/0413 | ||
| 1992/1119 | /* | |
| 1993/1116 | * vga device | |
| 1992/1119 | */ enum { | |
| 1994/0624 | Qdir = 0, Qvgaiob = 1, Qvgaiow = 2, Qvgaiol = 3, Qvgactl = 4, | |
| 1995/0508 | Qvgaiosl = 5, Nvga = Qvgaiosl, | |
| 1992/1119 | }; | |
| 1992/0527 | Dirtab vgadir[]={ | |
| 1994/0624 | "vgaiob", { Qvgaiob }, 0, 0666, "vgaiow", { Qvgaiow }, 0, 0666, "vgaiol", { Qvgaiol }, 0, 0666, | |
| 1995/0508 | "vgaiosl", { Qvgaiosl }, 0, 0666, /* Debugging: philw */ | |
| 1994/0624 | "vgactl", { Qvgactl }, 0, 0666, | |
| 1992/0527 | }; void | |
| 1992/1119 | vgareset(void) { | |
| 1994/0414 | cursor.disable++; | |
| 1992/0527 | } void vgainit(void) { } Chan* vgaattach(char *upec) { return devattach('v', upec); } Chan* vgaclone(Chan *c, Chan *nc) { return devclone(c, nc); } int vgawalk(Chan *c, char *name) { return devwalk(c, name, vgadir, Nvga, devgen); } void vgastat(Chan *c, char *dp) { | |
| 1992/1119 | devstat(c, dp, vgadir, Nvga, devgen); | |
| 1992/0527 | } Chan* vgaopen(Chan *c, int omode) { return devopen(c, omode, vgadir, Nvga, devgen); } void vgacreate(Chan *c, char *name, int omode, ulong perm) { | |
| 1992/0711 | USED(c, name, omode, perm); | |
| 1992/0527 | error(Eperm); } void vgaclose(Chan *c) { | |
| 1992/0711 | USED(c); | |
| 1992/0527 | } | |
| 1994/0624 | static int checkvgaport(int port, int len) { if((port == 0x102 || port == 0x46E8) && len == 1) return 0; if(port >= 0x3B0 && port+len < 0x3E0) return 0; return -1; } | |
| 1992/0527 | long vgaread(Chan *c, void *buf, long n, ulong offset) { | |
| 1992/0711 | int port; | |
| 1993/1116 | uchar *cp; | |
| 1995/0406 | char cbuf[128]; | |
| 1993/1116 | ushort *sp; | |
| 1994/0603 | ulong *lp; | |
| 1995/0126 | Vgac *vgacp; | |
| 1992/0528 | ||
| 1992/0527 | switch(c->qid.path&~CHDIR){ case Qdir: return devdirread(c, buf, n, vgadir, Nvga, devgen); | |
| 1994/0624 | case Qvgactl: | |
| 1995/0204 | if(cga) return readstr(offset, buf, n, "type: cga\n"); vgacp = vgac; | |
| 1995/0126 | port = sprint(cbuf, "type: %s\n", vgacp->name); | |
| 1994/0930 | port += sprint(cbuf+port, "size: %dx%dx%d%s\n", gscreen.r.max.x, gscreen.r.max.y, 1<<gscreen.ldepth, interlaced); | |
| 1994/0624 | port += sprint(cbuf+port, "hwgc: "); if(hwgc) | |
| 1995/0406 | port += sprint(cbuf+port, "%s\n", hwgc->name); | |
| 1994/0624 | else | |
| 1995/0406 | port += sprint(cbuf+port, "off\n"); sprint(cbuf+port, "addr: 0x%lux\n", screenmem&~KZERO); | |
| 1992/1119 | return readstr(offset, buf, n, cbuf); | |
| 1994/0624 | case Qvgaiob: port = offset; | |
| 1994/0702 | /*if(checkvgaport(port, n)) error(Eperm);*/ | |
| 1994/0624 | for(cp = buf; port < offset+n; port++) *cp++ = vgai(port); | |
| 1992/0528 | return n; | |
| 1994/0624 | case Qvgaiow: | |
| 1993/1116 | if((n & 01) || (offset & 01)) error(Ebadarg); n /= 2; for (sp = buf, port=offset; port<offset+n; port+=2) *sp++ = ins(port); return n*2; | |
| 1994/0624 | case Qvgaiol: | |
| 1994/0603 | if((n & 03) || (offset & 03)) error(Ebadarg); n /= 4; for (lp = buf, port=offset; port<offset+n; port+=4) *lp++ = inl(port); return n*4; | |
| 1992/0527 | } | |
| 1992/1119 | error(Eperm); return 0; | |
| 1992/0527 | } | |
| 1995/0108 | Block* vgabread(Chan *c, long n, ulong offset) { return devbread(c, n, offset); } | |
| 1994/0624 | static void vgactl(char *arg) { | |
| 1995/0406 | int n; ulong x, y, z; char *cp, *field[4]; | |
| 1995/0126 | Hwgc *hwgcp; Vgac *vgacp; | |
| 1994/0624 | ||
| 1995/0406 | n = getfields(arg, field, 4, " "); if(n < 2) | |
| 1994/0624 | error(Ebadarg); | |
| 1995/0406 | if(strcmp(field[0], "disable") == 0){ screendisabled = 1; } else if(strcmp(field[0], "enable") == 0){ screendisabled = 0; } else if(strcmp(field[0], "hwgc") == 0){ if(n < 2) error(Ebadarg); | |
| 1994/0624 | if(strcmp(field[1], "off") == 0){ if(hwgc){ (*hwgc->disable)(); hwgc = 0; cursoron(1); } return; } | |
| 1995/0126 | for(hwgcp = hwgctlr; hwgcp; hwgcp = hwgcp->link){ if(strcmp(field[1], hwgcp->name) == 0){ | |
| 1994/0624 | if(hwgc) (*hwgc->disable)(); else cursoroff(1); | |
| 1995/0126 | hwgc = hwgcp; | |
| 1994/0624 | (*hwgc->enable)(); setcursor(&curs); cursoron(1); return; } } } else if(strcmp(field[0], "type") == 0){ | |
| 1995/0406 | if(n < 2) error(Ebadarg); | |
| 1995/0126 | for(vgacp = vgactlr; vgacp; vgacp = vgacp->link){ if(strcmp(field[1], vgacp->name) == 0){ vgac = vgacp; | |
| 1994/0624 | return; } } } else if(strcmp(field[0], "size") == 0){ | |
| 1995/0406 | if(n < 2) error(Ebadarg); | |
| 1995/0206 | x = strtoul(field[1], &cp, 0); if(x == 0 || x > 2048) | |
| 1994/0624 | error(Ebadarg); if(*cp) cp++; | |
| 1995/0206 | y = strtoul(cp, &cp, 0); if(y == 0 || y > 1280) | |
| 1994/0624 | error(Ebadarg); if(*cp) cp++; | |
| 1995/0206 | switch(strtoul(cp, &cp, 0)){ case 8: z = 3; break; case 1: z = 0; break; default: | |
| 1995/0207 | z = 0; | |
| 1994/0624 | error(Ebadarg); | |
| 1995/0206 | } | |
| 1994/0930 | interlaced[0] = *cp; | |
| 1994/0624 | ||
| 1995/0206 | cursoroff(1); | |
| 1994/0624 | setscreen(x, y, z); cursoron(1); return; } | |
| 1995/0406 | else if(strcmp(field[0], "linear") == 0){ if(n < 2) error(Ebadarg); x = strtoul(field[1], 0, 0); if(n < 3) y = 0; else y = strtoul(field[2], 0, 0); | |
| 1994/0624 | ||
| 1995/0406 | /* see if it fits in the usual place */ | |
| 1995/0407 | if(x <= Footprint){ | |
| 1995/0406 | screenmem = SCREENMEM; | |
| 1995/0407 | if(x == 0){ | |
| 1995/0406 | footprint = Footprint; | |
| 1995/0407 | footshift = Footshift; } else { | |
| 1995/0406 | footprint = x; | |
| 1995/0407 | for(n = 0; n < 31; n++) if((1<<n) >= footprint) break; footshift = n; } | |
| 1995/0406 | gscreen.base = (void*)screenmem; return; } /* grab new space */ if(y == 0){ if(footprint >= x) return; } else { int s, e; s = screenmem & ~KZERO; e = s + footprint; s = ROUND(s, y); if(e > s + x) return; } y = getspace(x, y); if(y == 0) error("not enough free address space"); screenmem = y; gscreen.base = (void*)y; footprint = x; | |
| 1995/0407 | for(n = 0; n < 31; n++) if((1<<n) >= footprint) break; footshift = n; | |
| 1995/0406 | return; } | |
| 1994/0624 | error(Ebadarg); } | |
| 1992/0527 | long | |
| 1992/0528 | vgawrite(Chan *c, void *buf, long n, ulong offset) | |
| 1992/0527 | { | |
| 1994/0624 | int port; uchar *cp; char cbuf[64]; | |
| 1993/1116 | ushort *sp; | |
| 1994/0603 | ulong *lp; | |
| 1992/0528 | ||
| 1992/0527 | switch(c->qid.path&~CHDIR){ case Qdir: error(Eperm); | |
| 1994/0503 | case Qvgactl: if(offset != 0 || n >= sizeof(cbuf)) error(Ebadarg); memmove(cbuf, buf, n); cbuf[n] = 0; | |
| 1994/0624 | vgactl(cbuf); | |
| 1992/0603 | return n; | |
| 1994/0624 | case Qvgaiob: port = offset; | |
| 1994/0702 | /*if(checkvgaport(port, n)) error(Eperm);*/ | |
| 1994/0624 | for(cp = buf; port < offset+n; port++) vgao(port, *cp++); | |
| 1992/0604 | return n; | |
| 1994/0624 | case Qvgaiow: | |
| 1993/1116 | if((n & 01) || (offset & 01)) error(Ebadarg); n /= 2; for (sp = buf, port=offset; port<offset+n; port+=2) outs(port, *sp++); return n*2; | |
| 1994/0624 | case Qvgaiol: | |
| 1994/0603 | if((n & 03) || (offset & 03)) error(Ebadarg); n /= 4; for (lp = buf, port=offset; port<offset+n; port+=4) outl(port, *lp++); return n*4; | |
| 1995/0508 | case Qvgaiosl: if((n & 03) || (offset & 03)) error(Ebadarg); outsl(offset, buf, n/4); return n; | |
| 1992/0527 | } | |
| 1992/1119 | error(Eperm); return 0; | |
| 1995/0108 | } long vgabwrite(Chan *c, Block *bp, ulong offset) { return devbwrite(c, bp, offset); | |
| 1992/0527 | } void vgaremove(Chan *c) { | |
| 1992/0711 | USED(c); | |
| 1992/0527 | error(Eperm); } void vgawstat(Chan *c, char *dp) { | |
| 1992/0711 | USED(c, dp); | |
| 1992/0527 | error(Eperm); } | |
| 1992/1119 | ||
| 1994/0624 | int vgaxi(long port, uchar index) | |
| 1993/1116 | { | |
| 1994/0624 | uchar data; switch(port){ case Seqx: case Crtx: case Grx: outb(port, index); data = inb(port+1); break; case Attrx: /* * Allow processor access to the colour * palette registers. Writes to Attrx must * be preceded by a read from Status1 to * initialise the register to point to the * index register and not the data register. * Processor access is allowed by turning * off bit 0x20. */ inb(Status1); if(index < 0x10){ outb(Attrx, index); data = inb(Attrx+1); inb(Status1); outb(Attrx, 0x20|index); } else{ outb(Attrx, 0x20|index); data = inb(Attrx+1); } break; default: return -1; } return data & 0xFF; | |
| 1994/0416 | } | |
| 1994/0624 | int vgaxo(long port, uchar index, uchar data) | |
| 1994/0416 | { | |
| 1994/0624 | switch(port){ case Seqx: case Crtx: case Grx: /* * We could use an outport here, but some chips * (e.g. 86C928) have trouble with that for some * registers. */ outb(port, index); outb(port+1, data); break; case Attrx: inb(Status1); if(index < 0x10){ outb(Attrx, index); outb(Attrx, data); inb(Status1); outb(Attrx, 0x20|index); } else{ outb(Attrx, 0x20|index); outb(Attrx, data); } break; default: return -1; | |
| 1994/0416 | } | |
| 1994/0624 | return 0; | |
| 1994/0416 | } | |
| 1994/0624 | /* * start the screen in CGA mode. Create the fonts for VGA. Called by * main(). */ void screeninit(void) | |
| 1994/0416 | { | |
| 1994/0624 | int i; ulong *l; /* * swizzle the font longs. */ l = defont0.bits->base; for(i = defont0.bits->width*Dy(defont0.bits->r); i > 0; i--, l++) *l = (*l<<24) | ((*l>>8)&0x0000ff00) | ((*l<<8)&0x00ff0000) | (*l>>24); /* * start in CGA mode */ cga = 1; vgaxo(Crtx, 0x0A, 0xFF); /* turn off cursor */ memset(CGASCREEN, 0, CGAWIDTH*CGAHEIGHT); | |
| 1994/0416 | } | |
| 1993/1116 | ||
| 1994/1029 | static ulong xnto32(uchar x, int n) { int s; ulong y; x &= (1<<n)-1; y = 0; for(s = 32 - n; s > 0; s -= n) y |= x<<s; if(s < 0) y |= x>>(-s); return y; } | |
| 1993/1116 | /* * reconfigure screen shape */ static void setscreen(int maxx, int maxy, int ldepth) { | |
| 1994/0416 | int i, x, l, tl; uchar *a; Rectangle r; | |
| 1993/1116 | ||
| 1994/0415 | if(waserror()){ unlock(&screenlock); nexterror(); } lock(&screenlock); | |
| 1994/0416 | /* setup a bitmap for the new size */ | |
| 1993/1116 | gscreen.ldepth = ldepth; | |
| 1994/0415 | gscreen.width = (maxx*(1<<gscreen.ldepth)+31)/32; | |
| 1995/0406 | gscreen.base = (void*)screenmem; | |
| 1993/1116 | gscreen.r.min = Pt(0, 0); gscreen.r.max = Pt(maxx, maxy); gscreen.clipr = gscreen.r; | |
| 1995/0406 | for(i = 0; i < gscreen.width*BY2WD*maxy; i += footprint){ vgac->page(i>>footshift); memset(gscreen.base, 0xff, footprint); | |
| 1994/0412 | } | |
| 1993/1116 | ||
| 1994/0416 | /* get size for a system window */ | |
| 1994/0415 | h = defont0.height; w = defont0.info[' '].width; window.min = Pt(48, 48); | |
| 1994/0812 | window.max = add(window.min, Pt(10+w*80, 50*h)); | |
| 1994/0415 | if(window.max.y >= gscreen.r.max.y) window.max.y = gscreen.r.max.y-1; if(window.max.x >= gscreen.r.max.x) window.max.x = gscreen.r.max.x-1; window.max.y = window.min.y+((window.max.y-window.min.y)/h)*h; curpos = window.min; | |
| 1994/0416 | /* work areas change when dimensions change */ | |
| 1994/0415 | workinit(&chwork, w, h); | |
| 1994/0812 | workinit(&scrollwork, 80*w, 1); | |
| 1994/0416 | workinit(&scrollwork, Dx(window), 1); | |
| 1994/0415 | cursorinit(); | |
| 1994/0416 | /* clear the system window */ l = scrollwork.width * BY2WD; memset(scrollwork.base, 0, l); tl = graphicssubtile(0, l, gscreen.ldepth, gscreen.r, window, &a); for(i = window.min.y; i < window.max.y; i++){ r = Rect(window.min.x, i, window.max.x, i + 1); screenload(r, (uchar*)scrollwork.base, tl, l, 1); } | |
| 1994/0415 | unlock(&screenlock); poperror(); | |
| 1994/0416 | /* default color map (has to be outside the lock) */ | |
| 1993/1116 | switch(ldepth){ case 3: | |
| 1995/0126 | for(i = 0; i < Pcolours; i++) | |
| 1994/0528 | setcolor(i, xnto32(i>>5, 3), xnto32(i>>2, 3), xnto32(i, 2)); | |
| 1994/0507 | setcolor(0x55, xnto32(0x15, 6), xnto32(0x15, 6), xnto32(0x15, 6)); setcolor(0xaa, xnto32(0x2a, 6), xnto32(0x2a, 6), xnto32(0x2a, 6)); setcolor(0xff, xnto32(0x3f, 6), xnto32(0x3f, 6), xnto32(0x3f, 6)); | |
| 1993/1116 | break; case 2: case 1: case 0: for(i = 0; i < 16; i++){ | |
| 1994/0507 | x = xnto32((i*63)/15, 6); | |
| 1993/1116 | setcolor(i, x, x, x); } break; } | |
| 1994/0415 | ||
| 1994/0416 | /* switch software to graphics mode */ | |
| 1993/1116 | cga = 0; | |
| 1994/0415 | } | |
| 1993/1116 | ||
| 1994/0415 | /* * init a bitblt work area */ static void workinit(Bitmap *bm, int maxx, int maxy) { bm->ldepth = gscreen.ldepth; bm->r = Rect(0, 0, maxx, maxy); if(gscreen.ldepth != 3) bm->r.max.x += 1<<(3-gscreen.ldepth); bm->clipr = bm->r; bm->width = ((bm->r.max.x << gscreen.ldepth) + 31) >> 5; if(bm->base == 0) bm->base = xalloc(maxx*maxy); | |
| 1994/0412 | } | |
| 1993/1116 | ||
| 1994/0412 | /* * Load a byte into screen memory. Assume that if the page * is wrong we just need to increment it. */ static int byteload(uchar *q, uchar *data, int m, int *page, uchar *e) { int pg; int diff; diff = 0; if(q >= e){ pg = ++*page; | |
| 1995/0126 | vgac->page(pg); | |
| 1995/0406 | q -= footprint; diff -= footprint; | |
| 1994/0412 | } *q ^= (*data^*q) & m; return diff; | |
| 1993/1116 | } /* | |
| 1994/0412 | * Load adjacent bytes into a screen memory. Assume that if the page * is wrong we just need to increment it. */ static int lineload(uchar *q, uchar *data, int len, int *page, uchar *e) { int rem, pg; int diff; diff = 0; if(q >= e){ pg = ++*page; | |
| 1995/0126 | vgac->page(pg); | |
| 1995/0406 | q -= footprint; diff -= footprint; | |
| 1994/0412 | } rem = e - q; if(rem < len){ memmove(q, data, rem); pg = ++*page; | |
| 1995/0126 | vgac->page(pg); | |
| 1995/0406 | q -= footprint; diff -= footprint; | |
| 1994/0412 | memmove(q+rem, data+rem, len-rem); } else memmove(q, data, len); return diff; } /* * paste tile into hard screen. | |
| 1993/1217 | * tile is at location r, first pixel in *data. tl is length of scan line to insert, * l is amount to advance data after each scan line. | |
| 1993/1116 | */ void | |
| 1994/0412 | screenload(Rectangle r, uchar *data, int tl, int l, int dolock) | |
| 1993/1116 | { | |
| 1994/0412 | int y, lpart, rpart, mx, m, mr, page, sw; ulong off; uchar *q, *e; | |
| 1993/1116 | ||
| 1995/0406 | if(screendisabled || cga || !rectclip(&r, gscreen.r) || tl<=0) | |
| 1993/1116 | return; | |
| 1994/0412 | ||
| 1994/0624 | if(dolock && hwgc == 0) | |
| 1994/0412 | cursorlock(r); | |
| 1994/0729 | lock(&palettelock); | |
| 1994/0412 | ||
| 1994/0413 | q = byteaddr(&gscreen, r.min); | |
| 1993/1116 | mx = 7>>gscreen.ldepth; lpart = (r.min.x & mx) << gscreen.ldepth; rpart = (r.max.x & mx) << gscreen.ldepth; m = 0xFF >> lpart; mr = 0xFF ^ (0xFF >> rpart); | |
| 1994/0412 | off = q - (uchar*)gscreen.base; | |
| 1995/0406 | page = off>>footshift; | |
| 1995/0126 | vgac->page(page); | |
| 1995/0406 | q = ((uchar*)gscreen.base) + (off&(footprint-1)); | |
| 1994/0412 | sw = gscreen.width*sizeof(ulong); | |
| 1995/0406 | e = ((uchar*)gscreen.base) + footprint; | |
| 1994/0412 | ||
| 1993/1116 | /* may need to do bit insertion on edges */ | |
| 1994/0407 | if(tl <= 0){ ; }else if(tl == 1){ /* all in one byte */ | |
| 1993/1116 | if(rpart) | |
| 1993/1221 | m &= mr; | |
| 1993/1116 | for(y=r.min.y; y<r.max.y; y++){ | |
| 1994/0412 | if(q < e) *q ^= (*data^*q) & m; else q += byteload(q, data, m, &page, e); q += sw; | |
| 1993/1116 | data += l; } }else if(lpart==0 && rpart==0){ /* easy case */ for(y=r.min.y; y<r.max.y; y++){ | |
| 1994/0412 | if(q + tl <= e) memmove(q, data, tl); else q += lineload(q, data, tl, &page, e); q += sw; | |
| 1993/1116 | data += l; } }else if(rpart==0){ for(y=r.min.y; y<r.max.y; y++){ | |
| 1994/0412 | if(q + tl <= e){ *q ^= (*data^*q) & m; memmove(q+1, data+1, tl-1); } else { q += byteload(q, data, m, &page, e); q += lineload(q+1, data+1, tl-1, &page, e); } q += sw; | |
| 1993/1116 | data += l; } }else if(lpart == 0){ for(y=r.min.y; y<r.max.y; y++){ | |
| 1994/0412 | if(q + tl <= e){ memmove(q, data, tl-1); q[tl-1] ^= (data[tl-1]^q[tl-1]) & mr; } else { /* new page */ q += lineload(q, data, tl-1, &page, e); q += byteload(q+tl-1, data+tl-1, mr, &page, e); } q += sw; | |
| 1993/1116 | data += l; } }else for(y=r.min.y; y<r.max.y; y++){ | |
| 1994/0809 | if(q + tl <= e){ *q ^= (*data^*q) & m; if(tl > 2) memmove(q+1, data+1, tl-2); q[tl-1] ^= (data[tl-1]^q[tl-1]) & mr; } else { /* new page */ q += byteload(q, data, m, &page, e); if(tl > 2) q += lineload(q+1, data+1, tl-2, &page, e); q += byteload(q+tl-1, data+tl-1, mr, &page, e); | |
| 1993/1116 | } | |
| 1994/0809 | q += sw; data += l; } | |
| 1994/0412 | ||
| 1994/0729 | unlock(&palettelock); | |
| 1994/0624 | if(dolock && hwgc == 0) | |
| 1994/0412 | cursorunlock(); | |
| 1993/1116 | } /* | |
| 1994/0412 | * Get a byte from screen memory. Assume that if the page * is wrong we just need to increment it. | |
| 1993/1116 | */ | |
| 1994/0412 | static int byteunload(uchar *q, uchar *data, int m, int *page, uchar *e) | |
| 1993/1116 | { | |
| 1994/0412 | int pg; int diff; | |
| 1993/1116 | ||
| 1994/0412 | diff = 0; if(q >= e){ pg = ++*page; | |
| 1995/0126 | vgac->page(pg); | |
| 1995/0406 | q -= footprint; diff -= footprint; | |
| 1994/0412 | } *data ^= (*q^*data) & m; return diff; } | |
| 1993/1116 | ||
| 1994/0412 | /* * Get a vector of bytes from screen memory. Assume that if the page * is wrong we just need to increment it. */ static int lineunload(uchar *q, uchar *data, int len, int *page, uchar *e) { int rem, pg; int diff; | |
| 1993/1116 | ||
| 1994/0412 | diff = 0; if(q >= e){ pg = ++*page; | |
| 1995/0126 | vgac->page(pg); | |
| 1995/0406 | q -= footprint; diff -= footprint; | |
| 1994/0412 | } | |
| 1993/1116 | ||
| 1994/0412 | rem = e - q; | |
| 1993/1116 | ||
| 1994/0412 | if(rem < len){ memmove(data, q, rem); pg = ++*page; | |
| 1995/0126 | vgac->page(pg); | |
| 1995/0406 | q -= footprint; diff -= footprint; | |
| 1994/0412 | memmove(data+rem, q+rem, len-rem); } else memmove(data, q, len); return diff; } /* | |
| 1994/0809 | * get a tile from screen memory. * tile is at location r, first pixel in *data. * tl is length of scan line to insert, * l is amount to advance data after each scan line. | |
| 1994/0412 | */ void screenunload(Rectangle r, uchar *data, int tl, int l, int dolock) { int y, lpart, rpart, mx, m, mr, page, sw; ulong off; uchar *q, *e; | |
| 1995/0406 | if(screendisabled || cga || !rectclip(&r, gscreen.r) || tl<=0) | |
| 1993/1116 | return; | |
| 1994/0624 | if(dolock && hwgc == 0) | |
| 1994/0412 | cursorlock(r); | |
| 1994/0729 | lock(&palettelock); | |
| 1993/1116 | ||
| 1994/0413 | q = byteaddr(&gscreen, r.min); | |
| 1994/0412 | mx = 7>>gscreen.ldepth; lpart = (r.min.x & mx) << gscreen.ldepth; rpart = (r.max.x & mx) << gscreen.ldepth; m = 0xFF >> lpart; mr = 0xFF ^ (0xFF >> rpart); off = q - (uchar*)gscreen.base; | |
| 1995/0406 | page = off>>footshift; | |
| 1995/0126 | vgac->page(page); | |
| 1995/0406 | q = ((uchar*)gscreen.base) + (off&(footprint-1)); | |
| 1994/0412 | sw = gscreen.width*sizeof(ulong); | |
| 1995/0406 | e = ((uchar*)gscreen.base) + footprint; | |
| 1994/0412 | /* may need to do bit insertion on edges */ if(tl <= 0){ ; }else if(tl == 1){ /* all in one byte */ if(rpart) m &= mr; for(y=r.min.y; y<r.max.y; y++){ if(q < e) *data ^= (*q^*data) & m; else q += byteunload(q, data, m, &page, e); q += sw; data += l; } }else if(lpart==0 && rpart==0){ /* easy case */ for(y=r.min.y; y<r.max.y; y++){ if(q + tl <= e) memmove(data, q, tl); else q += lineunload(q, data, tl, &page, e); q += sw; data += l; } }else if(rpart==0){ for(y=r.min.y; y<r.max.y; y++){ if(q + tl <= e){ *data ^= (*q^*data) & m; memmove(data+1, q+1, tl-1); | |
| 1993/1116 | } else { | |
| 1994/0412 | q += byteunload(q, data, m, &page, e); q += lineunload(q+1, data+1, tl-1, &page, e); | |
| 1993/1116 | } | |
| 1994/0412 | q += sw; data += l; | |
| 1993/1116 | } | |
| 1994/0412 | }else if(lpart == 0){ for(y=r.min.y; y<r.max.y; y++){ if(q + tl <= e){ memmove(data, q, tl-1); data[tl-1] ^= (q[tl-1]^data[tl-1]) & mr; } else { /* new page */ q += lineunload(q, data, tl-1, &page, e); q += byteunload(q+tl-1, data+tl-1, mr, &page, e); } q += sw; data += l; } }else for(y=r.min.y; y<r.max.y; y++){ | |
| 1994/0809 | if(q + tl <= e){ *data ^= (*q^*data) & m; if(tl > 2) memmove(data+1, q+1, tl-2); data[tl-1] ^= (q[tl-1]^data[tl-1]) & mr; } else { /* new page */ q += byteunload(q, data, m, &page, e); if(tl > 2) q += lineunload(q+1, data+1, tl-2, &page, e); q += byteunload(q+tl-1, data+tl-1, mr, &page, e); | |
| 1994/0412 | } | |
| 1994/0809 | q += sw; data += l; } | |
| 1994/0412 | ||
| 1994/0729 | unlock(&palettelock); | |
| 1994/0624 | if(dolock && hwgc == 0) | |
| 1994/0412 | cursorunlock(); | |
| 1993/1116 | } | |
| 1994/0412 | /* * write a string to the screen */ | |
| 1993/1116 | void screenputs(char *s, int n) { int i; Rune r; char buf[4]; if(cga) { cgascreenputs(s, n); return; } if((getstatus() & IFLAG) == 0) { /* don't deadlock trying to print in interrupt */ if(!canlock(&screenlock)) return; } else lock(&screenlock); while(n > 0) { i = chartorune(&r, s); if(i == 0){ s++; --n; continue; } memmove(buf, s, i); buf[i] = 0; n -= i; s += i; screenputc(buf); } unlock(&screenlock); } | |
| 1992/1119 | static void nopage(int page) { USED(page); } | |
| 1994/0415 | /* * character mode console */ | |
| 1992/1119 | static void cgascreenputc(int c) { int i; static int color; static int pos; if(c == '\n'){ pos = pos/CGAWIDTH; pos = (pos+1)*CGAWIDTH; } else if(c == '\t'){ i = 8 - ((pos/2)&7); while(i-->0) cgascreenputc(' '); } else if(c == '\b'){ if(pos >= 2) pos -= 2; cgascreenputc(' '); pos -= 2; } else { CGASCREEN[pos++] = c; CGASCREEN[pos++] = 2; /* green on black */ } if(pos >= CGAWIDTH*CGAHEIGHT){ memmove(CGASCREEN, &CGASCREEN[CGAWIDTH], CGAWIDTH*(CGAHEIGHT-1)); memset(&CGASCREEN[CGAWIDTH*(CGAHEIGHT-1)], 0, CGAWIDTH); pos = CGAWIDTH*(CGAHEIGHT-1); } } | |
| 1993/1116 | static void | |
| 1992/1119 | cgascreenputs(char *s, int n) { while(n-- > 0) cgascreenputc(*s++); } | |
| 1994/0415 | /* * graphics mode console */ #define LINE2SCROLL 4 | |
| 1993/1116 | static void scroll(void) | |
| 1992/1119 | { | |
| 1994/0416 | int from, tl, l, diff; | |
| 1994/0415 | uchar *a; | |
| 1992/1119 | Rectangle r; | |
| 1994/0416 | diff = h*LINE2SCROLL; l = scrollwork.width * BY2WD; | |
| 1994/0415 | tl = graphicssubtile(0, l, gscreen.ldepth, gscreen.r, window, &a); | |
| 1994/0416 | /* move lines up */ for(from = window.min.y + diff; from < window.max.y; from++){ r = Rect(window.min.x, from, window.max.x, from + 1); | |
| 1994/0415 | screenunload(r, (uchar*)scrollwork.base, tl, l, 1); | |
| 1994/0416 | r = Rect(window.min.x, from - diff, window.max.x, from - diff + 1); | |
| 1994/0415 | screenload(r, (uchar*)scrollwork.base, tl, l, 1); } | |
| 1994/0416 | /* clear bottom */ memset(scrollwork.base, 0, l); for(from = window.max.y - diff; from < window.max.y; from++){ r = Rect(window.min.x, from, window.max.x, from + 1); screenload(r, (uchar*)scrollwork.base, tl, l, 1); } curpos.y -= diff; | |
| 1992/1119 | } | |
| 1993/1116 | static void screenputc(char *buf) | |
| 1992/1119 | { | |
| 1994/0415 | int pos, l, tl, off; uchar *a; Rectangle r; | |
| 1992/1119 | ||
| 1993/1116 | switch(buf[0]) { case '\n': | |
| 1994/0413 | if(curpos.y+h >= window.max.y) | |
| 1993/1116 | scroll(); | |
| 1994/0413 | curpos.y += h; | |
| 1993/1116 | screenputc("\r"); break; case '\r': | |
| 1994/0413 | curpos.x = window.min.x; | |
| 1993/1116 | break; case '\t': | |
| 1994/0413 | pos = (curpos.x-window.min.x)/w; | |
| 1993/1116 | pos = 8-(pos%8); | |
| 1994/0413 | curpos.x += pos*w; | |
| 1993/1116 | break; case '\b': | |
| 1994/0415 | if(curpos.x-w >= window.min.x){ | |
| 1994/0413 | curpos.x -= w; | |
| 1994/0415 | screenputc(" "); curpos.x -= w; } | |
| 1993/1116 | break; default: | |
| 1994/0413 | if(curpos.x >= window.max.x-w) | |
| 1993/1116 | screenputc("\n"); | |
| 1992/1119 | ||
| 1994/0415 | /* tile width */ r.min = curpos; r.max = add(r.min, Pt(w, h)); off = ((1<<gscreen.ldepth)*r.min.x) & 7; l = chwork.width*BY2WD; tl = graphicssubtile(0, l, gscreen.ldepth, gscreen.r, r, &a); /* add char into work area */ subfstring(&chwork, Pt(off, 0), &defont0, buf, S); /* move work area to screen */ screenload(r, (uchar*)chwork.base, tl, l, 0); curpos.x += w; | |
| 1992/1119 | } } int screenbits(void) { return 1<<gscreen.ldepth; /* bits per pixel */ } void getcolor(ulong p, ulong *pr, ulong *pg, ulong *pb) { | |
| 1993/1230 | ulong x; switch(gscreen.ldepth){ default: | |
| 1995/0126 | x = 0xF; | |
| 1993/1230 | break; case 3: | |
| 1995/0126 | x = 0xFF; | |
| 1993/1230 | break; } p &= x; p ^= x; | |
| 1994/0729 | lock(&palettelock); | |
| 1995/0126 | *pr = colormap[p][Pred]; *pg = colormap[p][Pgreen]; *pb = colormap[p][Pblue]; | |
| 1994/0729 | unlock(&palettelock); | |
| 1992/1119 | } int setcolor(ulong p, ulong r, ulong g, ulong b) { | |
| 1993/1230 | ulong x; switch(gscreen.ldepth){ default: | |
| 1995/0126 | x = 0xF; | |
| 1993/1230 | break; case 3: | |
| 1995/0126 | x = 0xFF; | |
| 1993/1230 | break; } p &= x; p ^= x; | |
| 1994/0729 | lock(&palettelock); | |
| 1995/0126 | colormap[p][Pred] = r; colormap[p][Pgreen] = g; colormap[p][Pblue] = b; vgao(PaddrW, p); vgao(Pdata, r>>(32-6)); vgao(Pdata, g>>(32-6)); vgao(Pdata, b>>(32-6)); | |
| 1994/0729 | unlock(&palettelock); | |
| 1992/1119 | return ~0; | |
| 1994/0414 | } /* * software cursor | |
| 1994/0624 | * and hacks for hardware cursor | |
| 1994/0414 | */ | |
| 1994/0415 | /* * area to store the bits that are behind the cursor */ | |
| 1994/0521 | static ulong backbits[16*4]; static ulong clrbits[16]; static ulong setbits[16]; | |
| 1994/0414 | ||
| 1994/0415 | /* * the white border around the cursor */ | |
| 1994/0414 | Bitmap clr = { {0, 0, 16, 16}, {0, 0, 16, 16}, 0, | |
| 1994/0521 | clrbits, | |
| 1994/0414 | 0, 1, }; | |
| 1994/0415 | /* * the black center of the cursor */ | |
| 1994/0414 | Bitmap set = { {0, 0, 16, 16}, {0, 0, 16, 16}, 0, | |
| 1994/0521 | setbits, | |
| 1994/0414 | 0, 1, }; void cursorinit(void) { static int already; lock(&cursor); | |
| 1994/0415 | workinit(&cursorwork, 16, 16); | |
| 1994/0414 | cursor.l = cursorwork.width*BY2WD; if(!already){ cursor.disable--; already = 1; } unlock(&cursor); } void | |
| 1994/0520 | setcursor(Cursor *curs) | |
| 1994/0414 | { | |
| 1994/0520 | uchar *p; int i; | |
| 1994/0624 | if(hwgc) (*hwgc->load)(curs); else for(i=0; i<16; i++){ | |
| 1994/0520 | p = (uchar*)&set.base[i]; *p = curs->set[2*i]; *(p+1) = curs->set[2*i+1]; p = (uchar*)&clr.base[i]; *p = curs->clr[2*i]; *(p+1) = curs->clr[2*i+1]; } | |
| 1994/0414 | } | |
| 1994/0624 | int | |
| 1994/0414 | cursoron(int dolock) { | |
| 1994/0624 | int xoff, yoff, s, ret; | |
| 1994/0414 | Rectangle r; uchar *a; struct { Bitmap *dm; Point p; Bitmap *sm; Rectangle r; Fcode f; } xx; if(cursor.disable) | |
| 1994/0624 | return 0; if(dolock){ s = 0; /* to avoid compiler warning */ | |
| 1994/0414 | lock(&cursor); | |
| 1994/0624 | } else s = spllo(); /* to avoid freezing out the eia ports */ | |
| 1994/0414 | ||
| 1994/0624 | ret = 0; if(hwgc) ret = (*hwgc->move)(mousexy()); | |
| 1994/0503 | else if(cursor.visible++ == 0){ | |
| 1994/0414 | cursor.r.min = mousexy(); cursor.r.max = add(cursor.r.min, Pt(16, 16)); cursor.r = raddp(cursor.r, cursor.offset); | |
| 1994/0416 | /* offsets into backup area and clr/set bitmaps */ r.min = Pt(0, 0); if(cursor.r.min.x < 0){ xoff = cursor.r.min.x; r.min.x = -xoff; } else xoff = ((1<<gscreen.ldepth)*cursor.r.min.x) & 7; if(cursor.r.min.y < 0){ yoff = cursor.r.min.y; r.min.y = -yoff; } else yoff = 0; r.max = add(r.min, Pt(16, 16)); | |
| 1994/0414 | /* clip the cursor rectangle */ xx.dm = &cursorwork; | |
| 1994/0416 | xx.p = Pt(xoff, yoff); | |
| 1994/0414 | xx.sm = &gscreen; xx.r = cursor.r; bitbltclip(&xx); /* tile width */ cursor.tl = graphicssubtile(0, cursor.l, gscreen.ldepth, gscreen.r, xx.r, &a); if(cursor.tl > 0){ /* get tile */ | |
| 1994/0415 | screenunload(xx.r, (uchar*)cursorwork.base, cursor.tl, cursor.l, 0); | |
| 1994/0414 | /* save for cursoroff */ | |
| 1994/0415 | memmove(backbits, cursorwork.base, cursor.l*16); | |
| 1994/0414 | /* add mouse into work area */ | |
| 1994/0415 | bitblt(&cursorwork, xx.p, &clr, r, D&~S); bitblt(&cursorwork, xx.p, &set, r, S|D); | |
| 1994/0414 | /* put back tile */ cursor.clipr = xx.r; | |
| 1994/0415 | screenload(xx.r, (uchar*)cursorwork.base, cursor.tl, cursor.l, 0); | |
| 1994/0414 | } } if(dolock) unlock(&cursor); | |
| 1994/0624 | else splx(s); return ret; | |
| 1994/0414 | } void cursoroff(int dolock) { | |
| 1994/0624 | if(hwgc) | |
| 1994/0503 | return; | |
| 1994/0414 | if(cursor.disable) return; | |
| 1994/0510 | if(dolock) | |
| 1994/0414 | lock(&cursor); | |
| 1994/0510 | ||
| 1994/0414 | if(--cursor.visible == 0 && cursor.tl > 0) screenload(cursor.clipr, (uchar*)backbits, cursor.tl, cursor.l, 0); | |
| 1994/0510 | ||
| 1994/0414 | if(dolock) unlock(&cursor); } | |
| 1994/0415 | static void | |
| 1994/0414 | cursorlock(Rectangle r) { lock(&cursor); if(rectXrect(cursor.r, r)){ cursoroff(0); cursor.frozen = 1; } cursor.disable++; unlock(&cursor); } | |
| 1994/0415 | static void | |
| 1994/0414 | cursorunlock(void) { lock(&cursor); cursor.disable--; if(cursor.frozen) cursoron(0); cursor.frozen = 0; unlock(&cursor); | |
| 1995/0126 | } void addhwgclink(Hwgc *hwgcp) { hwgcp->link = hwgctlr; hwgctlr = hwgcp; } void addvgaclink(Vgac *vgacp) { vgacp->link = vgactlr; vgactlr = vgacp; | |
| 1992/1119 | } | |