xref: /plan9/sys/src/9/pc/screen.c (revision 9c06fe1d54c51a5e47f19e590a2bc12b07b5d99e)
17dd7cddfSDavid du Colombier #include "u.h"
27dd7cddfSDavid du Colombier #include "../port/lib.h"
37dd7cddfSDavid du Colombier #include "mem.h"
47dd7cddfSDavid du Colombier #include "dat.h"
57dd7cddfSDavid du Colombier #include "fns.h"
67dd7cddfSDavid du Colombier #include "io.h"
77dd7cddfSDavid du Colombier #include "ureg.h"
87dd7cddfSDavid du Colombier #include "../port/error.h"
97dd7cddfSDavid du Colombier 
107dd7cddfSDavid du Colombier #define	Image	IMAGE
117dd7cddfSDavid du Colombier #include <draw.h>
127dd7cddfSDavid du Colombier #include <memdraw.h>
137dd7cddfSDavid du Colombier #include <cursor.h>
147dd7cddfSDavid du Colombier #include "screen.h"
157dd7cddfSDavid du Colombier 
167dd7cddfSDavid du Colombier #define RGB2K(r,g,b)	((156763*(r)+307758*(g)+59769*(b))>>19)
177dd7cddfSDavid du Colombier 
187dd7cddfSDavid du Colombier Point ZP = {0, 0};
197dd7cddfSDavid du Colombier 
207dd7cddfSDavid du Colombier Rectangle physgscreenr;
217dd7cddfSDavid du Colombier 
227dd7cddfSDavid du Colombier Memdata gscreendata;
237dd7cddfSDavid du Colombier Memimage *gscreen;
247dd7cddfSDavid du Colombier 
257dd7cddfSDavid du Colombier VGAscr vgascreen[1];
267dd7cddfSDavid du Colombier 
277dd7cddfSDavid du Colombier Cursor	arrow = {
287dd7cddfSDavid du Colombier 	{ -1, -1 },
297dd7cddfSDavid du Colombier 	{ 0xFF, 0xFF, 0x80, 0x01, 0x80, 0x02, 0x80, 0x0C,
307dd7cddfSDavid du Colombier 	  0x80, 0x10, 0x80, 0x10, 0x80, 0x08, 0x80, 0x04,
317dd7cddfSDavid du Colombier 	  0x80, 0x02, 0x80, 0x01, 0x80, 0x02, 0x8C, 0x04,
327dd7cddfSDavid du Colombier 	  0x92, 0x08, 0x91, 0x10, 0xA0, 0xA0, 0xC0, 0x40,
337dd7cddfSDavid du Colombier 	},
347dd7cddfSDavid du Colombier 	{ 0x00, 0x00, 0x7F, 0xFE, 0x7F, 0xFC, 0x7F, 0xF0,
357dd7cddfSDavid du Colombier 	  0x7F, 0xE0, 0x7F, 0xE0, 0x7F, 0xF0, 0x7F, 0xF8,
367dd7cddfSDavid du Colombier 	  0x7F, 0xFC, 0x7F, 0xFE, 0x7F, 0xFC, 0x73, 0xF8,
377dd7cddfSDavid du Colombier 	  0x61, 0xF0, 0x60, 0xE0, 0x40, 0x40, 0x00, 0x00,
387dd7cddfSDavid du Colombier 	},
397dd7cddfSDavid du Colombier };
407dd7cddfSDavid du Colombier 
414de34a7eSDavid du Colombier int didswcursorinit;
424de34a7eSDavid du Colombier 
437dd7cddfSDavid du Colombier int
447dd7cddfSDavid du Colombier screensize(int x, int y, int z, ulong chan)
457dd7cddfSDavid du Colombier {
467dd7cddfSDavid du Colombier 	VGAscr *scr;
477dd7cddfSDavid du Colombier 
484de34a7eSDavid du Colombier 	lock(&vgascreenlock);
497dd7cddfSDavid du Colombier 	memimageinit();
507dd7cddfSDavid du Colombier 	scr = &vgascreen[0];
517dd7cddfSDavid du Colombier 
527dd7cddfSDavid du Colombier 	/*
537dd7cddfSDavid du Colombier 	 * BUG: need to check if any xalloc'ed memory needs to
547dd7cddfSDavid du Colombier 	 * be given back if aperture is set.
557dd7cddfSDavid du Colombier 	 */
564de34a7eSDavid du Colombier 	if(scr->paddr == 0){
577dd7cddfSDavid du Colombier 		int width = (x*z)/BI2WD;
587dd7cddfSDavid du Colombier 
597dd7cddfSDavid du Colombier 		gscreendata.bdata = xalloc(width*BY2WD*y);
607dd7cddfSDavid du Colombier 		if(gscreendata.bdata == 0)
617dd7cddfSDavid du Colombier 			error("screensize: vga soft memory");
627dd7cddfSDavid du Colombier /*		memset(gscreendata.bdata, 0x72, width*BY2WD*y);	/* not really black */
637dd7cddfSDavid du Colombier 		scr->useflush = 1;
644de34a7eSDavid du Colombier 		scr->paddr = VGAMEM();
654de34a7eSDavid du Colombier 		scr->vaddr = KADDR(scr->paddr);
667dd7cddfSDavid du Colombier 		scr->apsize = 1<<16;
677dd7cddfSDavid du Colombier 	}
687dd7cddfSDavid du Colombier 	else
694de34a7eSDavid du Colombier 		gscreendata.bdata = scr->vaddr;
707dd7cddfSDavid du Colombier 
717dd7cddfSDavid du Colombier 	if(gscreen)
727dd7cddfSDavid du Colombier 		freememimage(gscreen);
734de34a7eSDavid du Colombier 	scr->gscreen = nil;
747dd7cddfSDavid du Colombier 
757dd7cddfSDavid du Colombier 	gscreen = allocmemimaged(Rect(0,0,x,y), chan, &gscreendata);
767dd7cddfSDavid du Colombier 	vgaimageinit(chan);
774de34a7eSDavid du Colombier 	if(gscreen == nil){
784de34a7eSDavid du Colombier 		unlock(&vgascreenlock);
797dd7cddfSDavid du Colombier 		return -1;
804de34a7eSDavid du Colombier 	}
817dd7cddfSDavid du Colombier 
829a747e4fSDavid du Colombier 	if(scr->dev && scr->dev->flush)
839a747e4fSDavid du Colombier 		scr->useflush = 1;
847dd7cddfSDavid du Colombier 
857dd7cddfSDavid du Colombier 	scr->palettedepth = 6;	/* default */
867dd7cddfSDavid du Colombier 	scr->gscreendata = &gscreendata;
877dd7cddfSDavid du Colombier 	scr->memdefont = getmemdefont();
887dd7cddfSDavid du Colombier 	scr->gscreen = gscreen;
897dd7cddfSDavid du Colombier 
907dd7cddfSDavid du Colombier 	physgscreenr = gscreen->r;
914de34a7eSDavid du Colombier 	unlock(&vgascreenlock);
927dd7cddfSDavid du Colombier 
934de34a7eSDavid du Colombier 	if(didswcursorinit)
944de34a7eSDavid du Colombier 		swcursorinit();
957dd7cddfSDavid du Colombier 	drawcmap();
967dd7cddfSDavid du Colombier 	return 0;
977dd7cddfSDavid du Colombier }
987dd7cddfSDavid du Colombier 
997dd7cddfSDavid du Colombier int
1007dd7cddfSDavid du Colombier screenaperture(int size, int align)
1017dd7cddfSDavid du Colombier {
1027dd7cddfSDavid du Colombier 	VGAscr *scr;
1037dd7cddfSDavid du Colombier 
1047dd7cddfSDavid du Colombier 	scr = &vgascreen[0];
1057dd7cddfSDavid du Colombier 
1064de34a7eSDavid du Colombier 	if(scr->paddr)	/* set up during enable */
1074de34a7eSDavid du Colombier 		return 0;
1084de34a7eSDavid du Colombier 
1094de34a7eSDavid du Colombier 	if(size == 0)
1104de34a7eSDavid du Colombier 		return 0;
1114de34a7eSDavid du Colombier 
1124de34a7eSDavid du Colombier 	if(scr->dev && scr->dev->linear){
1134de34a7eSDavid du Colombier 		scr->dev->linear(scr, size, align);
1147dd7cddfSDavid du Colombier 		return 0;
1157dd7cddfSDavid du Colombier 	}
1167dd7cddfSDavid du Colombier 
1174de34a7eSDavid du Colombier 	/*
1184de34a7eSDavid du Colombier 	 * Need to allocate some physical address space.
1194de34a7eSDavid du Colombier 	 * The driver will tell the card to use it.
1204de34a7eSDavid du Colombier 	 */
1214de34a7eSDavid du Colombier 	size = PGROUND(size);
1224de34a7eSDavid du Colombier 	scr->paddr = upaalloc(size, align);
1234de34a7eSDavid du Colombier 	if(scr->paddr == 0)
1244de34a7eSDavid du Colombier 		return -1;
1254de34a7eSDavid du Colombier 	scr->vaddr = vmap(scr->paddr, size);
1264de34a7eSDavid du Colombier 	if(scr->vaddr == nil)
1274de34a7eSDavid du Colombier 		return -1;
1287dd7cddfSDavid du Colombier 	scr->apsize = size;
1297dd7cddfSDavid du Colombier 
1307dd7cddfSDavid du Colombier 	return 0;
1317dd7cddfSDavid du Colombier }
1327dd7cddfSDavid du Colombier 
1337dd7cddfSDavid du Colombier uchar*
1347dd7cddfSDavid du Colombier attachscreen(Rectangle* r, ulong* chan, int* d, int* width, int *softscreen)
1357dd7cddfSDavid du Colombier {
1367dd7cddfSDavid du Colombier 	VGAscr *scr;
1377dd7cddfSDavid du Colombier 
1387dd7cddfSDavid du Colombier 	scr = &vgascreen[0];
1397dd7cddfSDavid du Colombier 	if(scr->gscreen == nil || scr->gscreendata == nil)
1407dd7cddfSDavid du Colombier 		return nil;
1417dd7cddfSDavid du Colombier 
1429a747e4fSDavid du Colombier 	*r = scr->gscreen->clipr;
1437dd7cddfSDavid du Colombier 	*chan = scr->gscreen->chan;
1447dd7cddfSDavid du Colombier 	*d = scr->gscreen->depth;
1457dd7cddfSDavid du Colombier 	*width = scr->gscreen->width;
1467dd7cddfSDavid du Colombier 	*softscreen = scr->useflush;
1477dd7cddfSDavid du Colombier 
1487dd7cddfSDavid du Colombier 	return scr->gscreendata->bdata;
1497dd7cddfSDavid du Colombier }
1507dd7cddfSDavid du Colombier 
1517dd7cddfSDavid du Colombier /*
1527dd7cddfSDavid du Colombier  * It would be fair to say that this doesn't work for >8-bit screens.
1537dd7cddfSDavid du Colombier  */
1547dd7cddfSDavid du Colombier void
1557dd7cddfSDavid du Colombier flushmemscreen(Rectangle r)
1567dd7cddfSDavid du Colombier {
1577dd7cddfSDavid du Colombier 	VGAscr *scr;
1587dd7cddfSDavid du Colombier 	uchar *sp, *disp, *sdisp, *edisp;
1597dd7cddfSDavid du Colombier 	int y, len, incs, off, page;
1607dd7cddfSDavid du Colombier 
1617dd7cddfSDavid du Colombier 	scr = &vgascreen[0];
1629a747e4fSDavid du Colombier 	if(scr->dev && scr->dev->flush){
1639a747e4fSDavid du Colombier 		scr->dev->flush(scr, r);
1649a747e4fSDavid du Colombier 		return;
1659a747e4fSDavid du Colombier 	}
1667dd7cddfSDavid du Colombier 	if(scr->gscreen == nil || scr->useflush == 0)
1677dd7cddfSDavid du Colombier 		return;
1687dd7cddfSDavid du Colombier 	if(scr->dev == nil || scr->dev->page == nil)
1697dd7cddfSDavid du Colombier 		return;
1707dd7cddfSDavid du Colombier 
1717dd7cddfSDavid du Colombier 	if(rectclip(&r, scr->gscreen->r) == 0)
1727dd7cddfSDavid du Colombier 		return;
1737dd7cddfSDavid du Colombier 
1747dd7cddfSDavid du Colombier 	incs = scr->gscreen->width * BY2WD;
1757dd7cddfSDavid du Colombier 
1767dd7cddfSDavid du Colombier 	switch(scr->gscreen->depth){
1777dd7cddfSDavid du Colombier 	default:
1787dd7cddfSDavid du Colombier 		len = 0;
1797dd7cddfSDavid du Colombier 		panic("flushmemscreen: depth\n");
1807dd7cddfSDavid du Colombier 		break;
1817dd7cddfSDavid du Colombier 	case 8:
1827dd7cddfSDavid du Colombier 		len = Dx(r);
1837dd7cddfSDavid du Colombier 		break;
1847dd7cddfSDavid du Colombier 	}
1857dd7cddfSDavid du Colombier 	if(len < 1)
1867dd7cddfSDavid du Colombier 		return;
1877dd7cddfSDavid du Colombier 
1887dd7cddfSDavid du Colombier 	off = r.min.y*scr->gscreen->width*BY2WD+(r.min.x*scr->gscreen->depth)/8;
1897dd7cddfSDavid du Colombier 	page = off/scr->apsize;
1907dd7cddfSDavid du Colombier 	off %= scr->apsize;
1914de34a7eSDavid du Colombier 	disp = scr->vaddr;
1927dd7cddfSDavid du Colombier 	sdisp = disp+off;
1937dd7cddfSDavid du Colombier 	edisp = disp+scr->apsize;
1947dd7cddfSDavid du Colombier 
1957dd7cddfSDavid du Colombier 	off = r.min.y*scr->gscreen->width*BY2WD+(r.min.x*scr->gscreen->depth)/8;
1967dd7cddfSDavid du Colombier 
1977dd7cddfSDavid du Colombier 	sp = scr->gscreendata->bdata + off;
1987dd7cddfSDavid du Colombier 
1997dd7cddfSDavid du Colombier 	scr->dev->page(scr, page);
2007dd7cddfSDavid du Colombier 	for(y = r.min.y; y < r.max.y; y++) {
2017dd7cddfSDavid du Colombier 		if(sdisp + incs < edisp) {
2027dd7cddfSDavid du Colombier 			memmove(sdisp, sp, len);
2037dd7cddfSDavid du Colombier 			sp += incs;
2047dd7cddfSDavid du Colombier 			sdisp += incs;
2057dd7cddfSDavid du Colombier 		}
2067dd7cddfSDavid du Colombier 		else {
2077dd7cddfSDavid du Colombier 			off = edisp - sdisp;
2087dd7cddfSDavid du Colombier 			page++;
2097dd7cddfSDavid du Colombier 			if(off <= len){
2107dd7cddfSDavid du Colombier 				if(off > 0)
2117dd7cddfSDavid du Colombier 					memmove(sdisp, sp, off);
2127dd7cddfSDavid du Colombier 				scr->dev->page(scr, page);
2137dd7cddfSDavid du Colombier 				if(len - off > 0)
2147dd7cddfSDavid du Colombier 					memmove(disp, sp+off, len - off);
2157dd7cddfSDavid du Colombier 			}
2167dd7cddfSDavid du Colombier 			else {
2177dd7cddfSDavid du Colombier 				memmove(sdisp, sp, len);
2187dd7cddfSDavid du Colombier 				scr->dev->page(scr, page);
2197dd7cddfSDavid du Colombier 			}
2207dd7cddfSDavid du Colombier 			sp += incs;
2217dd7cddfSDavid du Colombier 			sdisp += incs - scr->apsize;
2227dd7cddfSDavid du Colombier 		}
2237dd7cddfSDavid du Colombier 	}
2247dd7cddfSDavid du Colombier }
2257dd7cddfSDavid du Colombier 
2267dd7cddfSDavid du Colombier void
2277dd7cddfSDavid du Colombier getcolor(ulong p, ulong* pr, ulong* pg, ulong* pb)
2287dd7cddfSDavid du Colombier {
2297dd7cddfSDavid du Colombier 	VGAscr *scr;
2307dd7cddfSDavid du Colombier 	ulong x;
2317dd7cddfSDavid du Colombier 
2327dd7cddfSDavid du Colombier 	scr = &vgascreen[0];
2337dd7cddfSDavid du Colombier 	if(scr->gscreen == nil)
2347dd7cddfSDavid du Colombier 		return;
2357dd7cddfSDavid du Colombier 
2367dd7cddfSDavid du Colombier 	switch(scr->gscreen->depth){
2377dd7cddfSDavid du Colombier 	default:
2387dd7cddfSDavid du Colombier 		x = 0x0F;
2397dd7cddfSDavid du Colombier 		break;
2407dd7cddfSDavid du Colombier 	case 8:
2417dd7cddfSDavid du Colombier 		x = 0xFF;
2427dd7cddfSDavid du Colombier 		break;
2437dd7cddfSDavid du Colombier 	}
2447dd7cddfSDavid du Colombier 	p &= x;
2457dd7cddfSDavid du Colombier 
2467dd7cddfSDavid du Colombier 	lock(&cursor);
2477dd7cddfSDavid du Colombier 	*pr = scr->colormap[p][0];
2487dd7cddfSDavid du Colombier 	*pg = scr->colormap[p][1];
2497dd7cddfSDavid du Colombier 	*pb = scr->colormap[p][2];
2507dd7cddfSDavid du Colombier 	unlock(&cursor);
2517dd7cddfSDavid du Colombier }
2527dd7cddfSDavid du Colombier 
2537dd7cddfSDavid du Colombier int
2547dd7cddfSDavid du Colombier setpalette(ulong p, ulong r, ulong g, ulong b)
2557dd7cddfSDavid du Colombier {
2567dd7cddfSDavid du Colombier 	VGAscr *scr;
2577dd7cddfSDavid du Colombier 	int d;
2587dd7cddfSDavid du Colombier 
2597dd7cddfSDavid du Colombier 	scr = &vgascreen[0];
2607dd7cddfSDavid du Colombier 	d = scr->palettedepth;
2617dd7cddfSDavid du Colombier 
2627dd7cddfSDavid du Colombier 	lock(&cursor);
2637dd7cddfSDavid du Colombier 	scr->colormap[p][0] = r;
2647dd7cddfSDavid du Colombier 	scr->colormap[p][1] = g;
2657dd7cddfSDavid du Colombier 	scr->colormap[p][2] = b;
2667dd7cddfSDavid du Colombier 	vgao(PaddrW, p);
2677dd7cddfSDavid du Colombier 	vgao(Pdata, r>>(32-d));
2687dd7cddfSDavid du Colombier 	vgao(Pdata, g>>(32-d));
2697dd7cddfSDavid du Colombier 	vgao(Pdata, b>>(32-d));
2707dd7cddfSDavid du Colombier 	unlock(&cursor);
2717dd7cddfSDavid du Colombier 
2727dd7cddfSDavid du Colombier 	return ~0;
2737dd7cddfSDavid du Colombier }
2747dd7cddfSDavid du Colombier 
2757dd7cddfSDavid du Colombier /*
2767dd7cddfSDavid du Colombier  * On some video cards (e.g. Mach64), the palette is used as the
2777dd7cddfSDavid du Colombier  * DAC registers for >8-bit modes.  We don't want to set them when the user
2787dd7cddfSDavid du Colombier  * is trying to set a colormap and the card is in one of these modes.
2797dd7cddfSDavid du Colombier  */
2807dd7cddfSDavid du Colombier int
2817dd7cddfSDavid du Colombier setcolor(ulong p, ulong r, ulong g, ulong b)
2827dd7cddfSDavid du Colombier {
2837dd7cddfSDavid du Colombier 	VGAscr *scr;
2847dd7cddfSDavid du Colombier 	int x;
2857dd7cddfSDavid du Colombier 
2867dd7cddfSDavid du Colombier 	scr = &vgascreen[0];
2877dd7cddfSDavid du Colombier 	if(scr->gscreen == nil)
2887dd7cddfSDavid du Colombier 		return 0;
2897dd7cddfSDavid du Colombier 
2907dd7cddfSDavid du Colombier 	switch(scr->gscreen->depth){
2917dd7cddfSDavid du Colombier 	case 1:
2927dd7cddfSDavid du Colombier 	case 2:
2937dd7cddfSDavid du Colombier 	case 4:
2947dd7cddfSDavid du Colombier 		x = 0x0F;
2957dd7cddfSDavid du Colombier 		break;
2967dd7cddfSDavid du Colombier 	case 8:
2977dd7cddfSDavid du Colombier 		x = 0xFF;
2987dd7cddfSDavid du Colombier 		break;
2997dd7cddfSDavid du Colombier 	default:
3007dd7cddfSDavid du Colombier 		return 0;
3017dd7cddfSDavid du Colombier 	}
3027dd7cddfSDavid du Colombier 	p &= x;
3037dd7cddfSDavid du Colombier 
3047dd7cddfSDavid du Colombier 	return setpalette(p, r, g, b);
3057dd7cddfSDavid du Colombier }
3067dd7cddfSDavid du Colombier 
3077dd7cddfSDavid du Colombier int
3087dd7cddfSDavid du Colombier cursoron(int dolock)
3097dd7cddfSDavid du Colombier {
3107dd7cddfSDavid du Colombier 	VGAscr *scr;
3117dd7cddfSDavid du Colombier 	int v;
3127dd7cddfSDavid du Colombier 
3137dd7cddfSDavid du Colombier 	scr = &vgascreen[0];
3147dd7cddfSDavid du Colombier 	if(scr->cur == nil || scr->cur->move == nil)
3157dd7cddfSDavid du Colombier 		return 0;
3167dd7cddfSDavid du Colombier 
3177dd7cddfSDavid du Colombier 	if(dolock)
3187dd7cddfSDavid du Colombier 		lock(&cursor);
3197dd7cddfSDavid du Colombier 	v = scr->cur->move(scr, mousexy());
3207dd7cddfSDavid du Colombier 	if(dolock)
3217dd7cddfSDavid du Colombier 		unlock(&cursor);
3227dd7cddfSDavid du Colombier 
3237dd7cddfSDavid du Colombier 	return v;
3247dd7cddfSDavid du Colombier }
3257dd7cddfSDavid du Colombier 
3267dd7cddfSDavid du Colombier void
3277dd7cddfSDavid du Colombier cursoroff(int)
3287dd7cddfSDavid du Colombier {
3297dd7cddfSDavid du Colombier }
3307dd7cddfSDavid du Colombier 
3317dd7cddfSDavid du Colombier void
3327dd7cddfSDavid du Colombier setcursor(Cursor* curs)
3337dd7cddfSDavid du Colombier {
3347dd7cddfSDavid du Colombier 	VGAscr *scr;
3357dd7cddfSDavid du Colombier 
3367dd7cddfSDavid du Colombier 	scr = &vgascreen[0];
3377dd7cddfSDavid du Colombier 	if(scr->cur == nil || scr->cur->load == nil)
3387dd7cddfSDavid du Colombier 		return;
3397dd7cddfSDavid du Colombier 
3407dd7cddfSDavid du Colombier 	scr->cur->load(scr, curs);
3417dd7cddfSDavid du Colombier }
3427dd7cddfSDavid du Colombier 
3437dd7cddfSDavid du Colombier int hwaccel = 1;
3449a747e4fSDavid du Colombier int hwblank = 0;	/* turned on by drivers that are known good */
3459a747e4fSDavid du Colombier int panning = 0;
3467dd7cddfSDavid du Colombier 
3477dd7cddfSDavid du Colombier int
3487dd7cddfSDavid du Colombier hwdraw(Memdrawparam *par)
3497dd7cddfSDavid du Colombier {
3507dd7cddfSDavid du Colombier 	VGAscr *scr;
3514de34a7eSDavid du Colombier 	Memimage *dst, *src, *mask;
35259cc4ca5SDavid du Colombier 	int m;
3537dd7cddfSDavid du Colombier 
3547dd7cddfSDavid du Colombier 	if(hwaccel == 0)
3557dd7cddfSDavid du Colombier 		return 0;
3567dd7cddfSDavid du Colombier 
3577dd7cddfSDavid du Colombier 	scr = &vgascreen[0];
3584de34a7eSDavid du Colombier 	if((dst=par->dst) == nil || dst->data == nil)
3597dd7cddfSDavid du Colombier 		return 0;
3604de34a7eSDavid du Colombier 	if((src=par->src) == nil || src->data == nil)
3614de34a7eSDavid du Colombier 		return 0;
3624de34a7eSDavid du Colombier 	if((mask=par->mask) == nil || mask->data == nil)
3634de34a7eSDavid du Colombier 		return 0;
3644de34a7eSDavid du Colombier 
3654de34a7eSDavid du Colombier 	if(scr->cur == &swcursor){
3664de34a7eSDavid du Colombier 		if(dst->data->bdata == gscreendata.bdata)
3674de34a7eSDavid du Colombier 			swcursoravoid(par->r);
3684de34a7eSDavid du Colombier 		if(src->data->bdata == gscreendata.bdata)
3694de34a7eSDavid du Colombier 			swcursoravoid(par->sr);
3704de34a7eSDavid du Colombier 		if(mask->data->bdata == gscreendata.bdata)
3714de34a7eSDavid du Colombier 			swcursoravoid(par->mr);
3724de34a7eSDavid du Colombier 	}
3737dd7cddfSDavid du Colombier 
3747dd7cddfSDavid du Colombier 	if(dst->data->bdata != gscreendata.bdata)
3757dd7cddfSDavid du Colombier 		return 0;
3767dd7cddfSDavid du Colombier 
3777dd7cddfSDavid du Colombier 	if(scr->fill==nil && scr->scroll==nil)
3787dd7cddfSDavid du Colombier 		return 0;
3797dd7cddfSDavid du Colombier 
3807dd7cddfSDavid du Colombier 	/*
3817dd7cddfSDavid du Colombier 	 * If we have an opaque mask and source is one opaque
3827dd7cddfSDavid du Colombier 	 * pixel we can convert to the destination format and just
3837dd7cddfSDavid du Colombier 	 * replicate with memset.
3847dd7cddfSDavid du Colombier 	 */
38559cc4ca5SDavid du Colombier 	m = Simplesrc|Simplemask|Fullmask;
3866a9fc400SDavid du Colombier 	if(scr->fill
3876a9fc400SDavid du Colombier 	&& (par->state&m)==m
3886a9fc400SDavid du Colombier 	&& ((par->srgba&0xFF) == 0xFF)
3896a9fc400SDavid du Colombier 	&& (par->op&S) == S)
3907dd7cddfSDavid du Colombier 		return scr->fill(scr, par->r, par->sdval);
3917dd7cddfSDavid du Colombier 
3927dd7cddfSDavid du Colombier 	/*
3937dd7cddfSDavid du Colombier 	 * If no source alpha, an opaque mask, we can just copy the
3947dd7cddfSDavid du Colombier 	 * source onto the destination.  If the channels are the same and
3957dd7cddfSDavid du Colombier 	 * the source is not replicated, memmove suffices.
3967dd7cddfSDavid du Colombier 	 */
3976a9fc400SDavid du Colombier 	m = Simplemask|Fullmask;
3986a9fc400SDavid du Colombier 	if(scr->scroll
3996a9fc400SDavid du Colombier 	&& src->data->bdata==dst->data->bdata
4006a9fc400SDavid du Colombier 	&& !(src->flags&Falpha)
4016a9fc400SDavid du Colombier 	&& (par->state&m)==m
4026a9fc400SDavid du Colombier 	&& (par->op&S) == S)
4037dd7cddfSDavid du Colombier 		return scr->scroll(scr, par->r, par->sr);
4047dd7cddfSDavid du Colombier 
4057dd7cddfSDavid du Colombier 	return 0;
4067dd7cddfSDavid du Colombier }
4077dd7cddfSDavid du Colombier 
4087dd7cddfSDavid du Colombier void
4097dd7cddfSDavid du Colombier blankscreen(int blank)
4107dd7cddfSDavid du Colombier {
4117dd7cddfSDavid du Colombier 	VGAscr *scr;
4127dd7cddfSDavid du Colombier 
4137dd7cddfSDavid du Colombier 	scr = &vgascreen[0];
4149a747e4fSDavid du Colombier 	if(hwblank){
4159a747e4fSDavid du Colombier 		if(scr->blank)
4167dd7cddfSDavid du Colombier 			scr->blank(scr, blank);
4179a747e4fSDavid du Colombier 		else
4189a747e4fSDavid du Colombier 			vgablank(scr, blank);
4199a747e4fSDavid du Colombier 	}
4207dd7cddfSDavid du Colombier }
4214de34a7eSDavid du Colombier 
4224de34a7eSDavid du Colombier void
4234de34a7eSDavid du Colombier vgalinearpciid(VGAscr *scr, int vid, int did)
4244de34a7eSDavid du Colombier {
4254de34a7eSDavid du Colombier 	Pcidev *p;
4264de34a7eSDavid du Colombier 
4274de34a7eSDavid du Colombier 	p = nil;
4284de34a7eSDavid du Colombier 	while((p = pcimatch(p, vid, 0)) != nil){
4294de34a7eSDavid du Colombier 		if(p->ccrb != 3)	/* video card */
4304de34a7eSDavid du Colombier 			continue;
4314de34a7eSDavid du Colombier 		if(did != 0 && p->did != did)
4324de34a7eSDavid du Colombier 			continue;
4334de34a7eSDavid du Colombier 		break;
4344de34a7eSDavid du Colombier 	}
4354de34a7eSDavid du Colombier 	if(p == nil)
4364de34a7eSDavid du Colombier 		error("pci video card not found");
4374de34a7eSDavid du Colombier 
4384de34a7eSDavid du Colombier 	scr->pci = p;
4394de34a7eSDavid du Colombier 	vgalinearpci(scr);
4404de34a7eSDavid du Colombier }
4414de34a7eSDavid du Colombier 
4424de34a7eSDavid du Colombier void
4434de34a7eSDavid du Colombier vgalinearpci(VGAscr *scr)
4444de34a7eSDavid du Colombier {
4454de34a7eSDavid du Colombier 	ulong paddr;
4464de34a7eSDavid du Colombier 	int i, size, best;
4474de34a7eSDavid du Colombier 	Pcidev *p;
4484de34a7eSDavid du Colombier 
4494de34a7eSDavid du Colombier 	p = scr->pci;
4504de34a7eSDavid du Colombier 	if(p == nil)
4514de34a7eSDavid du Colombier 		return;
4524de34a7eSDavid du Colombier 
4534de34a7eSDavid du Colombier 	/*
4544de34a7eSDavid du Colombier 	 * Scan for largest memory region on card.
4554de34a7eSDavid du Colombier 	 * Some S3 cards (e.g. Savage) have enormous
4564de34a7eSDavid du Colombier 	 * mmio regions (but even larger frame buffers).
457*9c06fe1dSDavid du Colombier 	 * Some 3dfx cards (e.g., Voodoo3) have mmio
458*9c06fe1dSDavid du Colombier 	 * buffers the same size as the frame buffer,
459*9c06fe1dSDavid du Colombier 	 * but only the frame buffer is marked as
460*9c06fe1dSDavid du Colombier 	 * prefetchable (bar&8).  If a card doesn't fit
461*9c06fe1dSDavid du Colombier 	 * into these heuristics, its driver will have to
462*9c06fe1dSDavid du Colombier 	 * call vgalinearaddr directly.
4634de34a7eSDavid du Colombier 	 */
4644de34a7eSDavid du Colombier 	best = -1;
4654de34a7eSDavid du Colombier 	for(i=0; i<nelem(p->mem); i++){
4664de34a7eSDavid du Colombier 		if(p->mem[i].bar&1)	/* not memory */
4674de34a7eSDavid du Colombier 			continue;
4684de34a7eSDavid du Colombier 		if(p->mem[i].size < 640*480)	/* not big enough */
4694de34a7eSDavid du Colombier 			continue;
470*9c06fe1dSDavid du Colombier 		if(best==-1
471*9c06fe1dSDavid du Colombier 		|| p->mem[i].size > p->mem[best].size
472*9c06fe1dSDavid du Colombier 		|| (p->mem[i].size == p->mem[best].size && (p->mem[i].bar&8)))
4734de34a7eSDavid du Colombier 			best = i;
4744de34a7eSDavid du Colombier 	}
4754de34a7eSDavid du Colombier 	if(best >= 0){
4764de34a7eSDavid du Colombier 		paddr = p->mem[best].bar & ~0x0F;
4774de34a7eSDavid du Colombier 		size = p->mem[best].size;
4784de34a7eSDavid du Colombier 		vgalinearaddr(scr, paddr, size);
4794de34a7eSDavid du Colombier 		return;
4804de34a7eSDavid du Colombier 	}
4814de34a7eSDavid du Colombier 	error("no video memory found on pci card");
4824de34a7eSDavid du Colombier }
4834de34a7eSDavid du Colombier 
4844de34a7eSDavid du Colombier void
4854de34a7eSDavid du Colombier vgalinearaddr(VGAscr *scr, ulong paddr, int size)
4864de34a7eSDavid du Colombier {
4874de34a7eSDavid du Colombier 	int x, nsize;
4884de34a7eSDavid du Colombier 	ulong npaddr;
4894de34a7eSDavid du Colombier 
4904de34a7eSDavid du Colombier 	/*
4914de34a7eSDavid du Colombier 	 * new approach.  instead of trying to resize this
4924de34a7eSDavid du Colombier 	 * later, let's assume that we can just allocate the
4934de34a7eSDavid du Colombier 	 * entire window to start with.
4944de34a7eSDavid du Colombier 	 */
4954de34a7eSDavid du Colombier 
4964de34a7eSDavid du Colombier 	if(scr->paddr == paddr && size <= scr->apsize)
4974de34a7eSDavid du Colombier 		return;
4984de34a7eSDavid du Colombier 
4994de34a7eSDavid du Colombier 	if(scr->paddr){
5004de34a7eSDavid du Colombier 		/*
5014de34a7eSDavid du Colombier 		 * could call vunmap and vmap,
5024de34a7eSDavid du Colombier 		 * but worried about dangling pointers in devdraw
5034de34a7eSDavid du Colombier 		 */
5044de34a7eSDavid du Colombier 		error("cannot grow vga frame buffer");
5054de34a7eSDavid du Colombier 	}
5064de34a7eSDavid du Colombier 
5074de34a7eSDavid du Colombier 	/* round to page boundary, just in case */
5084de34a7eSDavid du Colombier 	x = paddr&(BY2PG-1);
5094de34a7eSDavid du Colombier 	npaddr = paddr-x;
5104de34a7eSDavid du Colombier 	nsize = PGROUND(size+x);
5114de34a7eSDavid du Colombier 
5124de34a7eSDavid du Colombier 	scr->vaddr = vmap(npaddr, nsize);
5134de34a7eSDavid du Colombier 	if(scr->vaddr == 0)
5144de34a7eSDavid du Colombier 		error("cannot allocate vga frame buffer");
5154de34a7eSDavid du Colombier 	scr->vaddr = (char*)scr->vaddr+x;
5164de34a7eSDavid du Colombier 	scr->paddr = paddr;
5174de34a7eSDavid du Colombier 	scr->apsize = nsize;
5184de34a7eSDavid du Colombier }
5194de34a7eSDavid du Colombier 
5204de34a7eSDavid du Colombier 
5214de34a7eSDavid du Colombier /*
5224de34a7eSDavid du Colombier  * Software cursor.
5234de34a7eSDavid du Colombier  */
5244de34a7eSDavid du Colombier int	swvisible;	/* is the cursor visible? */
5254de34a7eSDavid du Colombier int	swenabled;	/* is the cursor supposed to be on the screen? */
5264de34a7eSDavid du Colombier Memimage*	swback;	/* screen under cursor */
5274de34a7eSDavid du Colombier Memimage*	swimg;	/* cursor image */
5284de34a7eSDavid du Colombier Memimage*	swmask;	/* cursor mask */
5294de34a7eSDavid du Colombier Memimage*	swimg1;
5304de34a7eSDavid du Colombier Memimage*	swmask1;
5314de34a7eSDavid du Colombier 
5324de34a7eSDavid du Colombier Point	swoffset;
5334de34a7eSDavid du Colombier Rectangle	swrect;	/* screen rectangle in swback */
5344de34a7eSDavid du Colombier Point	swpt;	/* desired cursor location */
5354de34a7eSDavid du Colombier Point	swvispt;	/* actual cursor location */
5364de34a7eSDavid du Colombier int	swvers;	/* incremented each time cursor image changes */
5374de34a7eSDavid du Colombier int	swvisvers;	/* the version on the screen */
5384de34a7eSDavid du Colombier 
5394de34a7eSDavid du Colombier /*
5404de34a7eSDavid du Colombier  * called with drawlock locked for us, most of the time.
5414de34a7eSDavid du Colombier  * kernel prints at inopportune times might mean we don't
5424de34a7eSDavid du Colombier  * hold the lock, but memimagedraw is now reentrant so
5434de34a7eSDavid du Colombier  * that should be okay: worst case we get cursor droppings.
5444de34a7eSDavid du Colombier  */
5454de34a7eSDavid du Colombier void
5464de34a7eSDavid du Colombier swcursorhide(void)
5474de34a7eSDavid du Colombier {
5484de34a7eSDavid du Colombier 	if(swvisible == 0)
5494de34a7eSDavid du Colombier 		return;
5504de34a7eSDavid du Colombier 	if(swback == nil)
5514de34a7eSDavid du Colombier 		return;
5524de34a7eSDavid du Colombier 	swvisible = 0;
5534de34a7eSDavid du Colombier 	memimagedraw(gscreen, swrect, swback, ZP, memopaque, ZP, S);
5544de34a7eSDavid du Colombier }
5554de34a7eSDavid du Colombier 
5564de34a7eSDavid du Colombier void
5574de34a7eSDavid du Colombier swcursoravoid(Rectangle r)
5584de34a7eSDavid du Colombier {
5594de34a7eSDavid du Colombier 	if(swvisible && rectXrect(r, swrect))
5604de34a7eSDavid du Colombier 		swcursorhide();
5614de34a7eSDavid du Colombier }
5624de34a7eSDavid du Colombier 
5634de34a7eSDavid du Colombier void
5644de34a7eSDavid du Colombier swcursordraw(void)
5654de34a7eSDavid du Colombier {
5664de34a7eSDavid du Colombier 	if(swvisible)
5674de34a7eSDavid du Colombier 		return;
5684de34a7eSDavid du Colombier 	if(swenabled == 0)
5694de34a7eSDavid du Colombier 		return;
5704de34a7eSDavid du Colombier 	if(swback == nil || swimg1 == nil || swmask1 == nil)
5714de34a7eSDavid du Colombier 		return;
5724de34a7eSDavid du Colombier 	assert(!canqlock(&drawlock));
5734de34a7eSDavid du Colombier 	swvispt = swpt;
5744de34a7eSDavid du Colombier 	swvisvers = swvers;
5754de34a7eSDavid du Colombier 	swrect = rectaddpt(Rect(0,0,16,16), swvispt);
5764de34a7eSDavid du Colombier 	memimagedraw(swback, swback->r, gscreen, swpt, memopaque, ZP, S);
5774de34a7eSDavid du Colombier 	memimagedraw(gscreen, swrect, swimg1, ZP, swmask1, ZP, SoverD);
5784de34a7eSDavid du Colombier 	swvisible = 1;
5794de34a7eSDavid du Colombier }
5804de34a7eSDavid du Colombier 
5814de34a7eSDavid du Colombier /*
5824de34a7eSDavid du Colombier  * Need to lock drawlock for ourselves.
5834de34a7eSDavid du Colombier  */
5844de34a7eSDavid du Colombier void
5854de34a7eSDavid du Colombier swenable(VGAscr*)
5864de34a7eSDavid du Colombier {
5874de34a7eSDavid du Colombier 	swenabled = 1;
5884de34a7eSDavid du Colombier 	if(canqlock(&drawlock)){
5894de34a7eSDavid du Colombier 		swcursordraw();
5904de34a7eSDavid du Colombier 		qunlock(&drawlock);
5914de34a7eSDavid du Colombier 	}
5924de34a7eSDavid du Colombier }
5934de34a7eSDavid du Colombier 
5944de34a7eSDavid du Colombier void
5954de34a7eSDavid du Colombier swdisable(VGAscr*)
5964de34a7eSDavid du Colombier {
5974de34a7eSDavid du Colombier 	swenabled = 0;
5984de34a7eSDavid du Colombier 	if(canqlock(&drawlock)){
5994de34a7eSDavid du Colombier 		swcursorhide();
6004de34a7eSDavid du Colombier 		qunlock(&drawlock);
6014de34a7eSDavid du Colombier 	}
6024de34a7eSDavid du Colombier }
6034de34a7eSDavid du Colombier 
6044de34a7eSDavid du Colombier void
6054de34a7eSDavid du Colombier swload(VGAscr*, Cursor *curs)
6064de34a7eSDavid du Colombier {
6074de34a7eSDavid du Colombier 	uchar *ip, *mp;
6084de34a7eSDavid du Colombier 	int i, j, set, clr;
6094de34a7eSDavid du Colombier 
6104de34a7eSDavid du Colombier 	if(!swimg || !swmask || !swimg1 || !swmask1)
6114de34a7eSDavid du Colombier 		return;
6124de34a7eSDavid du Colombier 	/*
6134de34a7eSDavid du Colombier 	 * Build cursor image and mask.
6144de34a7eSDavid du Colombier 	 * Image is just the usual cursor image
6154de34a7eSDavid du Colombier 	 * but mask is a transparent alpha mask.
6164de34a7eSDavid du Colombier 	 *
6174de34a7eSDavid du Colombier 	 * The 16x16x8 memimages do not have
6184de34a7eSDavid du Colombier 	 * padding at the end of their scan lines.
6194de34a7eSDavid du Colombier 	 */
6204de34a7eSDavid du Colombier 	ip = byteaddr(swimg, ZP);
6214de34a7eSDavid du Colombier 	mp = byteaddr(swmask, ZP);
6224de34a7eSDavid du Colombier 	for(i=0; i<32; i++){
6234de34a7eSDavid du Colombier 		set = curs->set[i];
6244de34a7eSDavid du Colombier 		clr = curs->clr[i];
6254de34a7eSDavid du Colombier 		for(j=0x80; j; j>>=1){
6264de34a7eSDavid du Colombier 			*ip++ = set&j ? 0x00 : 0xFF;
6274de34a7eSDavid du Colombier 			*mp++ = (clr|set)&j ? 0xFF : 0x00;
6284de34a7eSDavid du Colombier 		}
6294de34a7eSDavid du Colombier 	}
6304de34a7eSDavid du Colombier 	swoffset = curs->offset;
6314de34a7eSDavid du Colombier 	swvers++;
6324de34a7eSDavid du Colombier 	memimagedraw(swimg1, swimg1->r, swimg, ZP, memopaque, ZP, S);
6334de34a7eSDavid du Colombier 	memimagedraw(swmask1, swmask1->r, swmask, ZP, memopaque, ZP, S);
6344de34a7eSDavid du Colombier }
6354de34a7eSDavid du Colombier 
6364de34a7eSDavid du Colombier int
6374de34a7eSDavid du Colombier swmove(VGAscr*, Point p)
6384de34a7eSDavid du Colombier {
6394de34a7eSDavid du Colombier 	swpt = addpt(p, swoffset);
6404de34a7eSDavid du Colombier 	return 0;
6414de34a7eSDavid du Colombier }
6424de34a7eSDavid du Colombier 
6434de34a7eSDavid du Colombier void
6444de34a7eSDavid du Colombier swcursorclock(void)
6454de34a7eSDavid du Colombier {
6464de34a7eSDavid du Colombier 	int x;
6474de34a7eSDavid du Colombier 
6484de34a7eSDavid du Colombier 	if(!swenabled)
6494de34a7eSDavid du Colombier 		return;
6504de34a7eSDavid du Colombier 	if(swvisible && eqpt(swpt, swvispt) && swvers==swvisvers)
6514de34a7eSDavid du Colombier 		return;
6524de34a7eSDavid du Colombier 
6534de34a7eSDavid du Colombier 	x = splhi();
6544de34a7eSDavid du Colombier 	if(swenabled)
6554de34a7eSDavid du Colombier 	if(!swvisible || !eqpt(swpt, swvispt) || swvers!=swvisvers)
6564de34a7eSDavid du Colombier 	if(canqlock(&drawlock)){
6574de34a7eSDavid du Colombier 		swcursorhide();
6584de34a7eSDavid du Colombier 		swcursordraw();
6594de34a7eSDavid du Colombier 		qunlock(&drawlock);
6604de34a7eSDavid du Colombier 	}
6614de34a7eSDavid du Colombier 	splx(x);
6624de34a7eSDavid du Colombier }
6634de34a7eSDavid du Colombier 
6644de34a7eSDavid du Colombier void
6654de34a7eSDavid du Colombier swcursorinit(void)
6664de34a7eSDavid du Colombier {
6674de34a7eSDavid du Colombier 	static int init, warned;
6684de34a7eSDavid du Colombier 	VGAscr *scr;
6694de34a7eSDavid du Colombier 
6704de34a7eSDavid du Colombier 	didswcursorinit = 1;
6714de34a7eSDavid du Colombier 	if(!init){
6724de34a7eSDavid du Colombier 		init = 1;
67326ad7229SDavid du Colombier 		addclock0link(swcursorclock, 10);
6744de34a7eSDavid du Colombier 	}
6754de34a7eSDavid du Colombier 	scr = &vgascreen[0];
6764de34a7eSDavid du Colombier 	if(scr==nil || scr->gscreen==nil)
6774de34a7eSDavid du Colombier 		return;
6784de34a7eSDavid du Colombier 
6794de34a7eSDavid du Colombier 	if(scr->dev == nil || scr->dev->linear == nil){
6804de34a7eSDavid du Colombier 		if(!warned){
6814de34a7eSDavid du Colombier 			print("cannot use software cursor on non-linear vga screen\n");
6824de34a7eSDavid du Colombier 			warned = 1;
6834de34a7eSDavid du Colombier 		}
6844de34a7eSDavid du Colombier 		return;
6854de34a7eSDavid du Colombier 	}
6864de34a7eSDavid du Colombier 
6874de34a7eSDavid du Colombier 	if(swback){
6884de34a7eSDavid du Colombier 		freememimage(swback);
6894de34a7eSDavid du Colombier 		freememimage(swmask);
6904de34a7eSDavid du Colombier 		freememimage(swmask1);
6914de34a7eSDavid du Colombier 		freememimage(swimg);
6924de34a7eSDavid du Colombier 		freememimage(swimg1);
6934de34a7eSDavid du Colombier 	}
6944de34a7eSDavid du Colombier 
6954de34a7eSDavid du Colombier 	swback = allocmemimage(Rect(0,0,32,32), gscreen->chan);
6964de34a7eSDavid du Colombier 	swmask = allocmemimage(Rect(0,0,16,16), GREY8);
6974de34a7eSDavid du Colombier 	swmask1 = allocmemimage(Rect(0,0,16,16), GREY1);
6984de34a7eSDavid du Colombier 	swimg = allocmemimage(Rect(0,0,16,16), GREY8);
6994de34a7eSDavid du Colombier 	swimg1 = allocmemimage(Rect(0,0,16,16), GREY1);
7004de34a7eSDavid du Colombier 	if(swback==nil || swmask==nil || swmask1==nil || swimg==nil || swimg1 == nil){
7014de34a7eSDavid du Colombier 		print("software cursor: allocmemimage: %r");
7024de34a7eSDavid du Colombier 		return;
7034de34a7eSDavid du Colombier 	}
7044de34a7eSDavid du Colombier 
7054de34a7eSDavid du Colombier 	memfillcolor(swmask, DOpaque);
7064de34a7eSDavid du Colombier 	memfillcolor(swmask1, DOpaque);
7074de34a7eSDavid du Colombier 	memfillcolor(swimg, DBlack);
7084de34a7eSDavid du Colombier 	memfillcolor(swimg1, DBlack);
7094de34a7eSDavid du Colombier }
7104de34a7eSDavid du Colombier 
7114de34a7eSDavid du Colombier VGAcur swcursor =
7124de34a7eSDavid du Colombier {
7134de34a7eSDavid du Colombier 	"soft",
7144de34a7eSDavid du Colombier 	swenable,
7154de34a7eSDavid du Colombier 	swdisable,
7164de34a7eSDavid du Colombier 	swload,
7174de34a7eSDavid du Colombier 	swmove,
7184de34a7eSDavid du Colombier };
7194de34a7eSDavid du Colombier 
720