| plan 9 kernel history: overview | file list | diff list |
1994/0415/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" | |
| 1992/0527 | ||
| 1993/1116 | enum { EMISCR= 0x3CC, /* control sync polarity */ EMISCW= 0x3C2, EFCW= 0x3DA, /* feature control */ EFCR= 0x3CA, GRX= 0x3CE, /* index to graphics registers */ GR= 0x3CF, /* graphics registers */ Grms= 0x04, /* read map select register */ SRX= 0x3C4, /* index to sequence registers */ SR= 0x3C5, /* sequence registers */ Smmask= 0x02, /* map mask */ CRX= 0x3D4, /* index to crt registers */ CR= 0x3D5, /* crt registers */ Cvre= 0x11, /* vertical retrace end */ ARW= 0x3C0, /* attribute registers (writing) */ ARR= 0x3C1, /* attribute registers (reading) */ CMRX= 0x3C7, /* color map read index */ CMWX= 0x3C8, /* color map write index */ CM= 0x3C9, /* color map data reg */ }; | |
| 1992/1119 | ||
| 1994/0412 | enum { Footshift= 16, Footprint= 1<<Footshift, }; | |
| 1992/1119 | /* imported */ | |
| 1994/0413 | extern Subfont defont0; | |
| 1993/1117 | extern Cursor arrow; | |
| 1992/1119 | /* exported */ | |
| 1994/0413 | Subfont *defont; Bitmap gscreen; | |
| 1992/1119 | ||
| 1993/1116 | /* vga screen */ static Lock screenlock; | |
| 1994/0415 | static Lock loadlock; | |
| 1993/1116 | static ulong colormap[256][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 | ||
| 1992/0527 | /* | |
| 1992/1119 | * screen dimensions | |
| 1992/0527 | */ | |
| 1993/1116 | #define MINX 8 | |
| 1992/1119 | #define MAXX 640 #define MAXY 480 | |
| 1993/1116 | #define CGAWIDTH 160 #define CGAHEIGHT 24 | |
| 1992/0527 | ||
| 1992/1119 | /* | |
| 1993/1116 | * screen memory addresses | |
| 1992/1119 | */ | |
| 1993/1116 | #define SCREENMEM (0xA0000 | KZERO) #define CGASCREEN ((uchar*)(0xB8000 | KZERO)) | |
| 1992/0527 | ||
| 1993/1116 | /* * VGA modes */ | |
| 1992/1119 | typedef struct VGAmode VGAmode; struct VGAmode { uchar general[2]; uchar sequencer[5]; uchar crt[0x19]; uchar graphics[9]; uchar attribute[0x15]; | |
| 1992/0527 | }; | |
| 1992/1119 | /* * 640x480 display, 1, 2, or 4 bit color. */ VGAmode mode12 = { /* general */ 0xe7, 0x00, /* sequence */ 0x03, 0x01, 0x0f, 0x00, 0x06, /* crt */ 0x65, 0x4f, 0x50, 0x88, 0x55, 0x9a, 0x09, 0x3e, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0x8b, 0xdf, 0x28, 0x00, 0xe7, 0x04, 0xe3, 0xff, /* graphics */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x0f, 0xff, /* attribute */ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x01, 0x10, 0x0f, 0x00, 0x00, }; /* * 320x200 display, 8 bit color. */ VGAmode mode13 = { /* general */ 0x63, 0x00, /* sequence */ 0x03, 0x01, 0x0f, 0x00, 0x0e, /* crt */ 0x5f, 0x4f, 0x50, 0x82, 0x54, 0x80, 0xbf, 0x1f, 0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x9c, 0x8e, 0x8f, 0x28, 0x40, 0x96, 0xb9, 0xa3, 0xff, /* graphics */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0f, 0xff, /* attribute */ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x41, 0x10, 0x0f, 0x00, 0x00, }; /* * definitions of known cards */ typedef struct Vgacard Vgacard; struct Vgacard { char *name; | |
| 1993/1116 | void (*setpage)(int); /* routine to page though display memory */ | |
| 1992/1119 | }; enum { | |
| 1992/1216 | Ati, /* ATI */ | |
| 1992/1124 | Pvga1a, /* paradise */ | |
| 1992/1216 | Trident, /* Trident 8900 */ Tseng, /* tseng labs te4000 */ | |
| 1993/0915 | Cirrus, /* Cirrus CLGD542X */ | |
| 1994/0311 | S3, | |
| 1992/1119 | Generic, }; | |
| 1993/1116 | static void nopage(int), tsengpage(int), tridentpage(int), parapage(int); | |
| 1994/0311 | static void atipage(int), cirruspage(int), s3page(int); | |
| 1993/1116 | ||
| 1993/0106 | Vgacard vgachips[] = | |
| 1992/1119 | { | |
| 1993/0106 | [Ati] { "ati", atipage, }, | |
| 1992/1124 | [Pvga1a] { "pvga1a", parapage, }, | |
| 1992/1216 | [Trident] { "trident", tridentpage, }, | |
| 1992/1119 | [Tseng] { "tseng", tsengpage, }, | |
| 1993/0915 | [Cirrus] { "cirrus", cirruspage, }, | |
| 1994/0311 | [S3] { "s3", s3page, }, | |
| 1992/1119 | [Generic] { "generic", nopage, }, { 0, 0, }, }; Vgacard *vgacard; /* current vga card */ | |
| 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 uchar srin(int); static void genout(int, int); static void srout(int, int); static void grout(int, int); static void arout(int, int); static void crout(int, int); static void cgascreenputc(int); static void cgascreenputs(char*, int); static void screenputc(char*); static void scroll(void); static ulong x3to32(uchar); static ulong x6to32(uchar); | |
| 1994/0415 | static void workinit(Bitmap*, int, int); | |
| 1993/1116 | ||
| 1994/0415 | static void cursorlock(Rectangle); static void cursorunlock(void); extern int graphicssubtile(uchar*, int, int, Rectangle, Rectangle, uchar**); | |
| 1994/0413 | ||
| 1992/1119 | /* | |
| 1993/1116 | * vga device | |
| 1992/1119 | */ enum { Qdir= 0, Qvgasize= 1, Qvgatype= 2, Qvgaport= 3, | |
| 1993/1116 | Qvgaportw= 4, Nvga= 4, | |
| 1992/1119 | }; | |
| 1992/0527 | Dirtab vgadir[]={ "vgasize", {Qvgasize}, 0, 0666, | |
| 1992/1119 | "vgatype", {Qvgatype}, 0, 0666, | |
| 1992/0528 | "vgaport", {Qvgaport}, 0, 0666, | |
| 1993/1116 | "vgaportw", {Qvgaportw}, 0, 0666, | |
| 1992/0527 | }; void | |
| 1992/1119 | vgareset(void) { | |
| 1993/0106 | vgacard = &vgachips[Generic]; | |
| 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 | } long vgaread(Chan *c, void *buf, long n, ulong offset) { | |
| 1992/0711 | int port; | |
| 1993/1116 | uchar *cp; | |
| 1992/1119 | char cbuf[64]; | |
| 1993/1116 | ushort *sp; | |
| 1992/0528 | ||
| 1992/0527 | switch(c->qid.path&~CHDIR){ case Qdir: return devdirread(c, buf, n, vgadir, Nvga, devgen); case Qvgasize: | |
| 1992/1119 | sprint(cbuf, "%dx%dx%d", gscreen.r.max.x, gscreen.r.max.y, 1<<gscreen.ldepth); return readstr(offset, buf, n, cbuf); case Qvgatype: return readstr(offset, buf, n, vgacard->name); | |
| 1992/0528 | case Qvgaport: | |
| 1993/1116 | for (cp = buf, port=offset; port<offset+n; port++) | |
| 1992/0528 | *cp++ = inb(port); return n; | |
| 1993/1116 | case Qvgaportw: 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; | |
| 1992/0527 | } | |
| 1992/1119 | error(Eperm); return 0; | |
| 1992/0527 | } long | |
| 1992/0528 | vgawrite(Chan *c, void *buf, long n, ulong offset) | |
| 1992/0527 | { | |
| 1992/1119 | char cbuf[64], *cp; Vgacard *vp; int port, maxx, maxy, ldepth; | |
| 1993/1116 | ushort *sp; | |
| 1992/0528 | ||
| 1992/0527 | switch(c->qid.path&~CHDIR){ case Qdir: error(Eperm); case Qvgatype: | |
| 1992/1119 | if(offset != 0 || n >= sizeof(cbuf) || n < 1) | |
| 1992/0528 | error(Ebadarg); | |
| 1992/1119 | memmove(cbuf, buf, n); cbuf[n] = 0; if(cp = strchr(cbuf, '\n')) *cp = 0; | |
| 1993/0106 | for(vp = vgachips; vp->name; vp++) | |
| 1992/1119 | if(strcmp(cbuf, vp->name) == 0){ vgacard = vp; return n; } error(Ebadarg); | |
| 1992/0527 | case Qvgasize: | |
| 1992/1119 | if(offset != 0 || n >= sizeof(cbuf)) | |
| 1992/0528 | error(Ebadarg); | |
| 1992/0603 | memmove(cbuf, buf, n); | |
| 1992/0604 | cbuf[n] = 0; | |
| 1992/0603 | cp = cbuf; maxx = strtoul(cp, &cp, 0); | |
| 1992/1119 | if(*cp!=0) cp++; | |
| 1992/0603 | maxy = strtoul(cp, &cp, 0); | |
| 1992/1119 | if(*cp!=0) cp++; switch(strtoul(cp, &cp, 0)){ case 1: ldepth = 0; break; case 2: ldepth = 1; break; case 4: ldepth = 2; break; case 8: ldepth = 3; break; default: ldepth = -1; } if(maxx == 0 || maxy == 0 || maxx > 1280 || maxy > 1024 || ldepth > 3 || ldepth < 0) | |
| 1992/0603 | error(Ebadarg); | |
| 1993/1117 | cursoroff(1); | |
| 1992/1119 | setscreen(maxx, maxy, ldepth); | |
| 1993/1117 | cursoron(1); | |
| 1992/0603 | return n; | |
| 1992/0528 | case Qvgaport: | |
| 1993/1116 | for (cp = buf, port=offset; port<offset+n; port++) | |
| 1992/0528 | outb(port, *cp++); | |
| 1992/0604 | return n; | |
| 1993/1116 | case Qvgaportw: 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; | |
| 1992/0527 | } | |
| 1992/1119 | error(Eperm); return 0; | |
| 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 | ||
| 1993/1116 | /* * start the screen in CGA mode. Create the fonts for VGA. */ void screeninit(void) { int i; ulong *l; /* | |
| 1993/1221 | * swizzle the font longs. | |
| 1993/1117 | */ | |
| 1994/0413 | l = defont0.bits->base; for(i = defont0.bits->width*Dy(defont0.bits->r); i > 0; i--, l++) | |
| 1993/1116 | *l = (*l<<24) | ((*l>>8)&0x0000ff00) | ((*l<<8)&0x00ff0000) | (*l>>24); | |
| 1994/0412 | ||
| 1993/1116 | /* * start in CGA mode */ cga = 1; crout(0x0a, 0xff); /* turn off cursor */ memset(CGASCREEN, 0, CGAWIDTH*CGAHEIGHT); } | |
| 1994/0412 | static void setmode(VGAmode *v) { int i; /* turn screen off (to avoid damage) */ srout(1, 0x21); for(i = 0; i < sizeof(v->general); i++) genout(i, v->general[i]); for(i = 0; i < sizeof(v->sequencer); i++) if(i == 1) srout(i, v->sequencer[i]|0x20); /* avoid enabling screen */ else srout(i, v->sequencer[i]); crout(Cvre, 0); /* allow writes to CRT registers 0-7 */ for(i = 0; i < sizeof(v->crt); i++) crout(i, v->crt[i]); for(i = 0; i < sizeof(v->graphics); i++) grout(i, v->graphics[i]); for(i = 0; i < sizeof(v->attribute); i++) arout(i, v->attribute[i]); /* turn screen on */ srout(1, v->sequencer[1]); } | |
| 1993/1116 | /* * reconfigure screen shape */ static void setscreen(int maxx, int maxy, int ldepth) { | |
| 1994/0412 | int i, x; | |
| 1993/1116 | ||
| 1994/0415 | if(waserror()){ unlock(&screenlock); nexterror(); } lock(&screenlock); | |
| 1994/0412 | switch(ldepth){ case 0: | |
| 1993/1116 | setmode(&mode12); | |
| 1994/0412 | break; case 3: setmode(&mode13); break; default: error(Ebadarg); } | |
| 1993/1116 | /* | |
| 1994/0412 | * setup a bitmap for the new size | |
| 1993/1116 | */ gscreen.ldepth = ldepth; | |
| 1994/0415 | gscreen.width = (maxx*(1<<gscreen.ldepth)+31)/32; | |
| 1994/0412 | gscreen.base = (void*)SCREENMEM; | |
| 1993/1116 | gscreen.r.min = Pt(0, 0); gscreen.r.max = Pt(maxx, maxy); gscreen.clipr = gscreen.r; | |
| 1994/0412 | for(i = 0; i < gscreen.width*BY2WD*maxy; i += Footprint){ vgacard->setpage(i>>Footshift); | |
| 1994/0415 | memset(gscreen.base, 0xff, Footprint); | |
| 1994/0412 | } | |
| 1993/1116 | /* | |
| 1994/0415 | * set up inset system window | |
| 1993/1116 | */ | |
| 1994/0415 | h = defont0.height; w = defont0.info[' '].width; window.min = Pt(48, 48); window.max = add(window.min, Pt(10+w*64, 36*h)); 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; vgacard->setpage(0); window.max.y = window.min.y+((window.max.y-window.min.y)/h)*h; bitblt(&gscreen, window.min, &gscreen, window, Zero); curpos = window.min; /* work areas */ workinit(&chwork, w, h); workinit(&scrollwork, 64*w, 1); cursorinit(); unlock(&screenlock); poperror(); /* * default color map (has to be outside the lock) */ | |
| 1993/1116 | switch(ldepth){ case 3: for(i = 0; i < 256; i++) setcolor(i, x3to32(i>>5), x3to32(i>>2), x3to32(i<<1)); break; case 2: case 1: case 0: for(i = 0; i < 16; i++){ x = x6to32((i*63)/15); setcolor(i, x, x, x); } break; } | |
| 1994/0415 | /* stop character mode changes */ | |
| 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; vgacard->setpage(pg); q -= Footprint; diff -= Footprint; } *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; vgacard->setpage(pg); q -= Footprint; diff -= Footprint; } rem = e - q; if(rem < len){ memmove(q, data, rem); pg = ++*page; vgacard->setpage(pg); q -= Footprint; diff -= Footprint; 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 | if(!rectclip(&r, gscreen.r) || tl<=0) return; | |
| 1994/0412 | if(dolock) cursorlock(r); | |
| 1994/0415 | lock(&loadlock); | |
| 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; page = off>>Footshift; vgacard->setpage(page); q = ((uchar*)gscreen.base) + (off&(Footprint-1)); sw = gscreen.width*sizeof(ulong); e = ((uchar*)gscreen.base) + Footprint; | |
| 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/0412 | 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); } q += sw; | |
| 1993/1116 | data += l; } | |
| 1994/0412 | ||
| 1994/0415 | unlock(&loadlock); | |
| 1994/0412 | if(dolock) 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; vgacard->setpage(pg); q -= Footprint; diff -= Footprint; } *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; vgacard->setpage(pg); q -= Footprint; diff -= Footprint; } | |
| 1993/1116 | ||
| 1994/0412 | rem = e - q; | |
| 1993/1116 | ||
| 1994/0412 | if(rem < len){ memmove(data, q, rem); pg = ++*page; vgacard->setpage(pg); q -= Footprint; diff -= Footprint; memmove(data+rem, q+rem, len-rem); } else memmove(data, q, len); return diff; } /* * paste tile into hard screen. * 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. */ 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; if(!rectclip(&r, gscreen.r) || tl<=0) | |
| 1993/1116 | return; | |
| 1994/0412 | if(dolock) cursorlock(r); | |
| 1994/0415 | lock(&loadlock); | |
| 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; page = off>>Footshift; | |
| 1993/1116 | vgacard->setpage(page); | |
| 1994/0412 | q = ((uchar*)gscreen.base) + (off&(Footprint-1)); sw = gscreen.width*sizeof(ulong); e = ((uchar*)gscreen.base) + Footprint; /* 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++){ 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); } q += sw; data += l; } | |
| 1994/0415 | unlock(&loadlock); | |
| 1994/0412 | if(dolock) 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); } /* * accessing registers */ static uchar | |
| 1993/0108 | srin(int i) { outb(SRX, i); return inb(SR); } | |
| 1993/1116 | static void | |
| 1992/1119 | genout(int reg, int val) { if(reg == 0) outb(EMISCW, val); else if (reg == 1) outb(EFCW, val); } | |
| 1993/1116 | static void | |
| 1992/1119 | srout(int reg, int val) { outb(SRX, reg); outb(SR, val); } | |
| 1993/1116 | static void | |
| 1992/1119 | grout(int reg, int val) { outb(GRX, reg); outb(GR, val); } | |
| 1993/1116 | static void | |
| 1992/1119 | arout(int reg, int val) { inb(0x3DA); if (reg <= 0xf) { outb(ARW, reg | 0x0); outb(ARW, val); inb(0x3DA); outb(ARW, reg | 0x20); } else { outb(ARW, reg | 0x20); outb(ARW, val); } } | |
| 1993/1116 | static void | |
| 1992/1119 | crout(int reg, int val) { outb(CRX, reg); outb(CR, val); } /* * expand 3 and 6 bits of color to 32 */ static ulong x3to32(uchar x) { ulong y; x = x&7; x= (x<<3)|x; y = (x<<(32-6))|(x<<(32-12))|(x<<(32-18))|(x<<(32-24))|(x<<(32-30)); return y; } static ulong x6to32(uchar x) { ulong y; x = x&0x3f; y = (x<<(32-6))|(x<<(32-12))|(x<<(32-18))|(x<<(32-24))|(x<<(32-30)); return y; } | |
| 1993/1116 | /* | |
| 1992/1119 | * paging routines for different cards */ static void nopage(int page) { USED(page); | |
| 1992/1216 | } | |
| 1993/1116 | ||
| 1993/0106 | /* | |
| 1993/1116 | * Extended registers can be read with inb(), but must be * written with outs(). The index must be written each time * before the register is accessed. * The page bits are spread across registers 0xAE and 0xB2. * This can go away when we use the memory aperture. | |
| 1993/0106 | */ | |
| 1992/1216 | static void | |
| 1993/0106 | atipage(int page) { /* the ext register is in the ATI ROM at a fixed address */ ushort extreg = *((ushort *)0x800C0010); uchar v; | |
| 1993/1116 | outb(extreg, 0xAE); v = (inb(extreg+1) & 0xFC)|((page>>4) & 0x03); outs(extreg, (v<<8)|0xAE); outb(extreg, 0xB2); v = (inb(extreg+1) & 0xE1)|((page & 0x0F)<<1); outs(extreg, (v<<8)|0xB2); | |
| 1993/0106 | } | |
| 1993/1116 | ||
| 1993/0206 | /* * The following assumes that the new mode registers have been selected. */ | |
| 1993/0106 | static void | |
| 1992/1216 | tridentpage(int page) { | |
| 1993/0915 | srout(0xe, (srin(0xe)&0xf0) | page^0x2); | |
| 1992/1119 | } static void tsengpage(int page) { outb(0x3cd, (page<<4)|page); | |
| 1992/1124 | } static void | |
| 1993/0915 | cirruspage(int page) { grout(0x9, page<<4); } static void | |
| 1992/1124 | parapage(int page) { | |
| 1993/0915 | grout(0x9, page<<4); | |
| 1994/0311 | } static void s3page(int page) { uchar crt51; /* | |
| 1994/0323 | * I don't understand why these are different. | |
| 1994/0311 | */ | |
| 1994/0412 | if(gscreen.ldepth == 3){ | |
| 1994/0323 | /* * The S3 registers need to be unlocked for this. * Let's hope they are already: * crout(0x38, 0x48); * crout(0x39, 0xA0); * * The page is 6 bits, the lower 4 bits in Crt35<3:0>, * the upper 2 in Crt51<3:2>. */ crout(0x35, page & 0x0F); outb(CRX, 0x51); crt51 = (0xF3 & inb(CR))|((page & 0x30)>>2); outb(CR, crt51); } else crout(0x35, (page<<2) & 0x0C); | |
| 1992/1119 | } | |
| 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/0415 | int from, to, tl, l; uchar *a; | |
| 1992/1119 | Rectangle r; | |
| 1994/0415 | l = gscreen.width * BY2WD; tl = graphicssubtile(0, l, gscreen.ldepth, gscreen.r, window, &a); from = window.min.y + LINE2SCROLL*h; to = window.min.y; for(; from < window.max.y; from++){ r = Rpt(Pt(window.min.x, from), Pt(window.max.x, from + 1)); screenunload(r, (uchar*)scrollwork.base, tl, l, 1); r = Rpt(Pt(window.min.x, to), Pt(window.max.x, to+1)); screenload(r, (uchar*)scrollwork.base, tl, l, 1); } curpos.y -= LINE2SCROLL*h; | |
| 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: x = 0xf; break; case 3: x = 0xff; break; } p &= x; p ^= x; | |
| 1993/1116 | lock(&screenlock); | |
| 1992/1119 | *pr = colormap[p][0]; *pg = colormap[p][1]; *pb = colormap[p][2]; | |
| 1993/1116 | unlock(&screenlock); | |
| 1992/1119 | } int setcolor(ulong p, ulong r, ulong g, ulong b) { | |
| 1993/1230 | ulong x; switch(gscreen.ldepth){ default: x = 0xf; break; case 3: x = 0xff; break; } p &= x; p ^= x; | |
| 1993/1116 | lock(&screenlock); | |
| 1992/1119 | colormap[p][0] = r; colormap[p][1] = g; colormap[p][2] = b; outb(CMWX, p); outb(CM, r>>(32-6)); outb(CM, g>>(32-6)); outb(CM, b>>(32-6)); | |
| 1993/1116 | unlock(&screenlock); | |
| 1992/1119 | return ~0; | |
| 1994/0414 | } /* * software cursor */ | |
| 1994/0415 | /* * area to store the bits that are behind the cursor */ ulong backbits[16*4]; | |
| 1994/0414 | ||
| 1994/0415 | /* * the white border around the cursor */ | |
| 1994/0414 | Bitmap clr = { {0, 0, 16, 16}, {0, 0, 16, 16}, 0, 0, 0, 1, }; | |
| 1994/0415 | /* * the black center of the cursor */ | |
| 1994/0414 | Bitmap set = { {0, 0, 16, 16}, {0, 0, 16, 16}, 0, 0, 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 setcursor(ulong *setbits, ulong *clrbits, int offx, int offy) { USED(offx, offy); set.base = setbits; clr.base = clrbits; } void cursoron(int dolock) { int off; Rectangle r; uchar *a; struct { Bitmap *dm; Point p; Bitmap *sm; Rectangle r; Fcode f; } xx; if(cursor.disable) return; if(dolock) lock(&cursor); if(cursor.visible++ == 0){ cursor.r.min = mousexy(); cursor.r.max = add(cursor.r.min, Pt(16, 16)); cursor.r = raddp(cursor.r, cursor.offset); /* bit offset into backup area */ if(cursor.r.min.x < 0) off = cursor.r.min.x; else off = ((1<<gscreen.ldepth)*cursor.r.min.x) & 7; /* clip the cursor rectangle */ xx.dm = &cursorwork; xx.p = Pt(off, 0); 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 */ r = Rect(0, 0, Dx(xx.r), Dy(xx.r)); | |
| 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); } void cursoroff(int dolock) { if(cursor.disable) return; if(dolock) lock(&cursor); if(--cursor.visible == 0 && cursor.tl > 0) screenload(cursor.clipr, (uchar*)backbits, cursor.tl, cursor.l, 0); 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); | |
| 1992/1119 | } | |