xref: /plan9/sys/src/9/pc/screen.c (revision cb8c047aa49e908a428eac8b13623e1b242fa11e)
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 
43*cb8c047aSDavid du Colombier static void *softscreen;
44*cb8c047aSDavid du Colombier 
457dd7cddfSDavid du Colombier int
screensize(int x,int y,int z,ulong chan)467dd7cddfSDavid du Colombier screensize(int x, int y, int z, ulong chan)
477dd7cddfSDavid du Colombier {
487dd7cddfSDavid du Colombier 	VGAscr *scr;
49*cb8c047aSDavid du Colombier 	void *oldsoft;
507dd7cddfSDavid du Colombier 
514de34a7eSDavid du Colombier 	lock(&vgascreenlock);
52*cb8c047aSDavid du Colombier 	if(waserror()){
53*cb8c047aSDavid du Colombier 		unlock(&vgascreenlock);
54*cb8c047aSDavid du Colombier 		nexterror();
55*cb8c047aSDavid du Colombier 	}
56*cb8c047aSDavid du Colombier 
577dd7cddfSDavid du Colombier 	memimageinit();
587dd7cddfSDavid du Colombier 	scr = &vgascreen[0];
59*cb8c047aSDavid du Colombier 	oldsoft = softscreen;
607dd7cddfSDavid du Colombier 
614de34a7eSDavid du Colombier 	if(scr->paddr == 0){
627dd7cddfSDavid du Colombier 		int width = (x*z)/BI2WD;
63*cb8c047aSDavid du Colombier 		void *p;
647dd7cddfSDavid du Colombier 
65*cb8c047aSDavid du Colombier 		p = xalloc(width*BY2WD*y);
66*cb8c047aSDavid du Colombier 		if(p == nil)
67*cb8c047aSDavid du Colombier 			error("no memory for vga soft screen");
68*cb8c047aSDavid du Colombier 		gscreendata.bdata = softscreen = p;
69*cb8c047aSDavid du Colombier 		if(scr->dev && scr->dev->page){
70*cb8c047aSDavid du Colombier 			scr->vaddr = KADDR(VGAMEM());
717dd7cddfSDavid du Colombier 			scr->apsize = 1<<16;
727dd7cddfSDavid du Colombier 		}
73*cb8c047aSDavid du Colombier 		scr->useflush = 1;
74*cb8c047aSDavid du Colombier 	}
75*cb8c047aSDavid du Colombier 	else{
764de34a7eSDavid du Colombier 		gscreendata.bdata = scr->vaddr;
77*cb8c047aSDavid du Colombier 		scr->useflush = scr->dev && scr->dev->flush;
784de34a7eSDavid du Colombier 	}
797dd7cddfSDavid du Colombier 
80*cb8c047aSDavid du Colombier 	scr->gscreen = nil;
81*cb8c047aSDavid du Colombier 	if(gscreen)
82*cb8c047aSDavid du Colombier 		freememimage(gscreen);
83*cb8c047aSDavid du Colombier 	gscreen = allocmemimaged(Rect(0,0,x,y), chan, &gscreendata);
84*cb8c047aSDavid du Colombier 	if(gscreen == nil)
85*cb8c047aSDavid du Colombier 		error("no memory for vga memimage");
86*cb8c047aSDavid du Colombier 	vgaimageinit(chan);
877dd7cddfSDavid du Colombier 
887dd7cddfSDavid du Colombier 	scr->palettedepth = 6;	/* default */
897dd7cddfSDavid du Colombier 	scr->gscreendata = &gscreendata;
907dd7cddfSDavid du Colombier 	scr->memdefont = getmemdefont();
917dd7cddfSDavid du Colombier 	scr->gscreen = gscreen;
927dd7cddfSDavid du Colombier 
937dd7cddfSDavid du Colombier 	physgscreenr = gscreen->r;
944de34a7eSDavid du Colombier 	unlock(&vgascreenlock);
95*cb8c047aSDavid du Colombier 	poperror();
96*cb8c047aSDavid du Colombier 	if(oldsoft)
97*cb8c047aSDavid du Colombier 		xfree(oldsoft);
98*cb8c047aSDavid du Colombier 
99*cb8c047aSDavid du Colombier 	memimagedraw(gscreen, gscreen->r, memblack, ZP, nil, ZP, S);
100*cb8c047aSDavid du Colombier 	flushmemscreen(gscreen->r);
1017dd7cddfSDavid du Colombier 
1024de34a7eSDavid du Colombier 	if(didswcursorinit)
1034de34a7eSDavid du Colombier 		swcursorinit();
1047dd7cddfSDavid du Colombier 	drawcmap();
1057dd7cddfSDavid du Colombier 	return 0;
1067dd7cddfSDavid du Colombier }
1077dd7cddfSDavid du Colombier 
1087dd7cddfSDavid du Colombier int
screenaperture(int size,int align)1097dd7cddfSDavid du Colombier screenaperture(int size, int align)
1107dd7cddfSDavid du Colombier {
1117dd7cddfSDavid du Colombier 	VGAscr *scr;
1127dd7cddfSDavid du Colombier 
1137dd7cddfSDavid du Colombier 	scr = &vgascreen[0];
1147dd7cddfSDavid du Colombier 
1154de34a7eSDavid du Colombier 	if(scr->paddr)	/* set up during enable */
1164de34a7eSDavid du Colombier 		return 0;
1174de34a7eSDavid du Colombier 
1184de34a7eSDavid du Colombier 	if(size == 0)
1194de34a7eSDavid du Colombier 		return 0;
1204de34a7eSDavid du Colombier 
1214de34a7eSDavid du Colombier 	if(scr->dev && scr->dev->linear){
1224de34a7eSDavid du Colombier 		scr->dev->linear(scr, size, align);
1237dd7cddfSDavid du Colombier 		return 0;
1247dd7cddfSDavid du Colombier 	}
1257dd7cddfSDavid du Colombier 
1264de34a7eSDavid du Colombier 	/*
1274de34a7eSDavid du Colombier 	 * Need to allocate some physical address space.
1284de34a7eSDavid du Colombier 	 * The driver will tell the card to use it.
1294de34a7eSDavid du Colombier 	 */
1304de34a7eSDavid du Colombier 	size = PGROUND(size);
1314de34a7eSDavid du Colombier 	scr->paddr = upaalloc(size, align);
1324de34a7eSDavid du Colombier 	if(scr->paddr == 0)
1334de34a7eSDavid du Colombier 		return -1;
1344de34a7eSDavid du Colombier 	scr->vaddr = vmap(scr->paddr, size);
1354de34a7eSDavid du Colombier 	if(scr->vaddr == nil)
1364de34a7eSDavid du Colombier 		return -1;
1377dd7cddfSDavid du Colombier 	scr->apsize = size;
1387dd7cddfSDavid du Colombier 
1397dd7cddfSDavid du Colombier 	return 0;
1407dd7cddfSDavid du Colombier }
1417dd7cddfSDavid du Colombier 
1427dd7cddfSDavid du Colombier uchar*
attachscreen(Rectangle * r,ulong * chan,int * d,int * width,int * softscreen)1437dd7cddfSDavid du Colombier attachscreen(Rectangle* r, ulong* chan, int* d, int* width, int *softscreen)
1447dd7cddfSDavid du Colombier {
1457dd7cddfSDavid du Colombier 	VGAscr *scr;
1467dd7cddfSDavid du Colombier 
1477dd7cddfSDavid du Colombier 	scr = &vgascreen[0];
1487dd7cddfSDavid du Colombier 	if(scr->gscreen == nil || scr->gscreendata == nil)
1497dd7cddfSDavid du Colombier 		return nil;
1507dd7cddfSDavid du Colombier 
1519a747e4fSDavid du Colombier 	*r = scr->gscreen->clipr;
1527dd7cddfSDavid du Colombier 	*chan = scr->gscreen->chan;
1537dd7cddfSDavid du Colombier 	*d = scr->gscreen->depth;
1547dd7cddfSDavid du Colombier 	*width = scr->gscreen->width;
1557dd7cddfSDavid du Colombier 	*softscreen = scr->useflush;
1567dd7cddfSDavid du Colombier 
1577dd7cddfSDavid du Colombier 	return scr->gscreendata->bdata;
1587dd7cddfSDavid du Colombier }
1597dd7cddfSDavid du Colombier 
1607dd7cddfSDavid du Colombier /*
1617dd7cddfSDavid du Colombier  * It would be fair to say that this doesn't work for >8-bit screens.
1627dd7cddfSDavid du Colombier  */
1637dd7cddfSDavid du Colombier void
flushmemscreen(Rectangle r)1647dd7cddfSDavid du Colombier flushmemscreen(Rectangle r)
1657dd7cddfSDavid du Colombier {
1667dd7cddfSDavid du Colombier 	VGAscr *scr;
1677dd7cddfSDavid du Colombier 	uchar *sp, *disp, *sdisp, *edisp;
1687dd7cddfSDavid du Colombier 	int y, len, incs, off, page;
1697dd7cddfSDavid du Colombier 
1707dd7cddfSDavid du Colombier 	scr = &vgascreen[0];
1719a747e4fSDavid du Colombier 	if(scr->dev && scr->dev->flush){
1729a747e4fSDavid du Colombier 		scr->dev->flush(scr, r);
1739a747e4fSDavid du Colombier 		return;
1749a747e4fSDavid du Colombier 	}
1757dd7cddfSDavid du Colombier 	if(scr->gscreen == nil || scr->useflush == 0)
1767dd7cddfSDavid du Colombier 		return;
1777dd7cddfSDavid du Colombier 	if(scr->dev == nil || scr->dev->page == nil)
1787dd7cddfSDavid du Colombier 		return;
1797dd7cddfSDavid du Colombier 
1807dd7cddfSDavid du Colombier 	if(rectclip(&r, scr->gscreen->r) == 0)
1817dd7cddfSDavid du Colombier 		return;
1827dd7cddfSDavid du Colombier 
1837dd7cddfSDavid du Colombier 	incs = scr->gscreen->width * BY2WD;
1847dd7cddfSDavid du Colombier 
1857dd7cddfSDavid du Colombier 	switch(scr->gscreen->depth){
1867dd7cddfSDavid du Colombier 	default:
1877dd7cddfSDavid du Colombier 		len = 0;
1887dd7cddfSDavid du Colombier 		panic("flushmemscreen: depth\n");
1897dd7cddfSDavid du Colombier 		break;
1907dd7cddfSDavid du Colombier 	case 8:
1917dd7cddfSDavid du Colombier 		len = Dx(r);
1927dd7cddfSDavid du Colombier 		break;
1937dd7cddfSDavid du Colombier 	}
1947dd7cddfSDavid du Colombier 	if(len < 1)
1957dd7cddfSDavid du Colombier 		return;
1967dd7cddfSDavid du Colombier 
1977dd7cddfSDavid du Colombier 	off = r.min.y*scr->gscreen->width*BY2WD+(r.min.x*scr->gscreen->depth)/8;
1987dd7cddfSDavid du Colombier 	page = off/scr->apsize;
1997dd7cddfSDavid du Colombier 	off %= scr->apsize;
2004de34a7eSDavid du Colombier 	disp = scr->vaddr;
2017dd7cddfSDavid du Colombier 	sdisp = disp+off;
2027dd7cddfSDavid du Colombier 	edisp = disp+scr->apsize;
2037dd7cddfSDavid du Colombier 
2047dd7cddfSDavid du Colombier 	off = r.min.y*scr->gscreen->width*BY2WD+(r.min.x*scr->gscreen->depth)/8;
2057dd7cddfSDavid du Colombier 
2067dd7cddfSDavid du Colombier 	sp = scr->gscreendata->bdata + off;
2077dd7cddfSDavid du Colombier 
2087dd7cddfSDavid du Colombier 	scr->dev->page(scr, page);
2097dd7cddfSDavid du Colombier 	for(y = r.min.y; y < r.max.y; y++) {
2107dd7cddfSDavid du Colombier 		if(sdisp + incs < edisp) {
2117dd7cddfSDavid du Colombier 			memmove(sdisp, sp, len);
2127dd7cddfSDavid du Colombier 			sp += incs;
2137dd7cddfSDavid du Colombier 			sdisp += incs;
2147dd7cddfSDavid du Colombier 		}
2157dd7cddfSDavid du Colombier 		else {
2167dd7cddfSDavid du Colombier 			off = edisp - sdisp;
2177dd7cddfSDavid du Colombier 			page++;
2187dd7cddfSDavid du Colombier 			if(off <= len){
2197dd7cddfSDavid du Colombier 				if(off > 0)
2207dd7cddfSDavid du Colombier 					memmove(sdisp, sp, off);
2217dd7cddfSDavid du Colombier 				scr->dev->page(scr, page);
2227dd7cddfSDavid du Colombier 				if(len - off > 0)
2237dd7cddfSDavid du Colombier 					memmove(disp, sp+off, len - off);
2247dd7cddfSDavid du Colombier 			}
2257dd7cddfSDavid du Colombier 			else {
2267dd7cddfSDavid du Colombier 				memmove(sdisp, sp, len);
2277dd7cddfSDavid du Colombier 				scr->dev->page(scr, page);
2287dd7cddfSDavid du Colombier 			}
2297dd7cddfSDavid du Colombier 			sp += incs;
2307dd7cddfSDavid du Colombier 			sdisp += incs - scr->apsize;
2317dd7cddfSDavid du Colombier 		}
2327dd7cddfSDavid du Colombier 	}
2337dd7cddfSDavid du Colombier }
2347dd7cddfSDavid du Colombier 
2357dd7cddfSDavid du Colombier void
getcolor(ulong p,ulong * pr,ulong * pg,ulong * pb)2367dd7cddfSDavid du Colombier getcolor(ulong p, ulong* pr, ulong* pg, ulong* pb)
2377dd7cddfSDavid du Colombier {
2387dd7cddfSDavid du Colombier 	VGAscr *scr;
2397dd7cddfSDavid du Colombier 	ulong x;
2407dd7cddfSDavid du Colombier 
2417dd7cddfSDavid du Colombier 	scr = &vgascreen[0];
2427dd7cddfSDavid du Colombier 	if(scr->gscreen == nil)
2437dd7cddfSDavid du Colombier 		return;
2447dd7cddfSDavid du Colombier 
2457dd7cddfSDavid du Colombier 	switch(scr->gscreen->depth){
2467dd7cddfSDavid du Colombier 	default:
2477dd7cddfSDavid du Colombier 		x = 0x0F;
2487dd7cddfSDavid du Colombier 		break;
2497dd7cddfSDavid du Colombier 	case 8:
2507dd7cddfSDavid du Colombier 		x = 0xFF;
2517dd7cddfSDavid du Colombier 		break;
2527dd7cddfSDavid du Colombier 	}
2537dd7cddfSDavid du Colombier 	p &= x;
2547dd7cddfSDavid du Colombier 
2557dd7cddfSDavid du Colombier 	lock(&cursor);
2567dd7cddfSDavid du Colombier 	*pr = scr->colormap[p][0];
2577dd7cddfSDavid du Colombier 	*pg = scr->colormap[p][1];
2587dd7cddfSDavid du Colombier 	*pb = scr->colormap[p][2];
2597dd7cddfSDavid du Colombier 	unlock(&cursor);
2607dd7cddfSDavid du Colombier }
2617dd7cddfSDavid du Colombier 
2627dd7cddfSDavid du Colombier int
setpalette(ulong p,ulong r,ulong g,ulong b)2637dd7cddfSDavid du Colombier setpalette(ulong p, ulong r, ulong g, ulong b)
2647dd7cddfSDavid du Colombier {
2657dd7cddfSDavid du Colombier 	VGAscr *scr;
2667dd7cddfSDavid du Colombier 	int d;
2677dd7cddfSDavid du Colombier 
2687dd7cddfSDavid du Colombier 	scr = &vgascreen[0];
2697dd7cddfSDavid du Colombier 	d = scr->palettedepth;
2707dd7cddfSDavid du Colombier 
2717dd7cddfSDavid du Colombier 	lock(&cursor);
2727dd7cddfSDavid du Colombier 	scr->colormap[p][0] = r;
2737dd7cddfSDavid du Colombier 	scr->colormap[p][1] = g;
2747dd7cddfSDavid du Colombier 	scr->colormap[p][2] = b;
2757dd7cddfSDavid du Colombier 	vgao(PaddrW, p);
2767dd7cddfSDavid du Colombier 	vgao(Pdata, r>>(32-d));
2777dd7cddfSDavid du Colombier 	vgao(Pdata, g>>(32-d));
2787dd7cddfSDavid du Colombier 	vgao(Pdata, b>>(32-d));
2797dd7cddfSDavid du Colombier 	unlock(&cursor);
2807dd7cddfSDavid du Colombier 
2817dd7cddfSDavid du Colombier 	return ~0;
2827dd7cddfSDavid du Colombier }
2837dd7cddfSDavid du Colombier 
2847dd7cddfSDavid du Colombier /*
2857dd7cddfSDavid du Colombier  * On some video cards (e.g. Mach64), the palette is used as the
2867dd7cddfSDavid du Colombier  * DAC registers for >8-bit modes.  We don't want to set them when the user
2877dd7cddfSDavid du Colombier  * is trying to set a colormap and the card is in one of these modes.
2887dd7cddfSDavid du Colombier  */
2897dd7cddfSDavid du Colombier int
setcolor(ulong p,ulong r,ulong g,ulong b)2907dd7cddfSDavid du Colombier setcolor(ulong p, ulong r, ulong g, ulong b)
2917dd7cddfSDavid du Colombier {
2927dd7cddfSDavid du Colombier 	VGAscr *scr;
2937dd7cddfSDavid du Colombier 	int x;
2947dd7cddfSDavid du Colombier 
2957dd7cddfSDavid du Colombier 	scr = &vgascreen[0];
2967dd7cddfSDavid du Colombier 	if(scr->gscreen == nil)
2977dd7cddfSDavid du Colombier 		return 0;
2987dd7cddfSDavid du Colombier 
2997dd7cddfSDavid du Colombier 	switch(scr->gscreen->depth){
3007dd7cddfSDavid du Colombier 	case 1:
3017dd7cddfSDavid du Colombier 	case 2:
3027dd7cddfSDavid du Colombier 	case 4:
3037dd7cddfSDavid du Colombier 		x = 0x0F;
3047dd7cddfSDavid du Colombier 		break;
3057dd7cddfSDavid du Colombier 	case 8:
3067dd7cddfSDavid du Colombier 		x = 0xFF;
3077dd7cddfSDavid du Colombier 		break;
3087dd7cddfSDavid du Colombier 	default:
3097dd7cddfSDavid du Colombier 		return 0;
3107dd7cddfSDavid du Colombier 	}
3117dd7cddfSDavid du Colombier 	p &= x;
3127dd7cddfSDavid du Colombier 
3137dd7cddfSDavid du Colombier 	return setpalette(p, r, g, b);
3147dd7cddfSDavid du Colombier }
3157dd7cddfSDavid du Colombier 
3167dd7cddfSDavid du Colombier int
cursoron(int dolock)3177dd7cddfSDavid du Colombier cursoron(int dolock)
3187dd7cddfSDavid du Colombier {
3197dd7cddfSDavid du Colombier 	VGAscr *scr;
3207dd7cddfSDavid du Colombier 	int v;
3217dd7cddfSDavid du Colombier 
3227dd7cddfSDavid du Colombier 	scr = &vgascreen[0];
3237dd7cddfSDavid du Colombier 	if(scr->cur == nil || scr->cur->move == nil)
3247dd7cddfSDavid du Colombier 		return 0;
3257dd7cddfSDavid du Colombier 
3267dd7cddfSDavid du Colombier 	if(dolock)
3277dd7cddfSDavid du Colombier 		lock(&cursor);
3287dd7cddfSDavid du Colombier 	v = scr->cur->move(scr, mousexy());
3297dd7cddfSDavid du Colombier 	if(dolock)
3307dd7cddfSDavid du Colombier 		unlock(&cursor);
3317dd7cddfSDavid du Colombier 
3327dd7cddfSDavid du Colombier 	return v;
3337dd7cddfSDavid du Colombier }
3347dd7cddfSDavid du Colombier 
3357dd7cddfSDavid du Colombier void
cursoroff(int)3367dd7cddfSDavid du Colombier cursoroff(int)
3377dd7cddfSDavid du Colombier {
3387dd7cddfSDavid du Colombier }
3397dd7cddfSDavid du Colombier 
3407dd7cddfSDavid du Colombier void
setcursor(Cursor * curs)3417dd7cddfSDavid du Colombier setcursor(Cursor* curs)
3427dd7cddfSDavid du Colombier {
3437dd7cddfSDavid du Colombier 	VGAscr *scr;
3447dd7cddfSDavid du Colombier 
3457dd7cddfSDavid du Colombier 	scr = &vgascreen[0];
3467dd7cddfSDavid du Colombier 	if(scr->cur == nil || scr->cur->load == nil)
3477dd7cddfSDavid du Colombier 		return;
3487dd7cddfSDavid du Colombier 
3497dd7cddfSDavid du Colombier 	scr->cur->load(scr, curs);
3507dd7cddfSDavid du Colombier }
3517dd7cddfSDavid du Colombier 
3527dd7cddfSDavid du Colombier int hwaccel = 1;
3539a747e4fSDavid du Colombier int hwblank = 0;	/* turned on by drivers that are known good */
3549a747e4fSDavid du Colombier int panning = 0;
3557dd7cddfSDavid du Colombier 
3567dd7cddfSDavid du Colombier int
hwdraw(Memdrawparam * par)3577dd7cddfSDavid du Colombier hwdraw(Memdrawparam *par)
3587dd7cddfSDavid du Colombier {
3597dd7cddfSDavid du Colombier 	VGAscr *scr;
3604de34a7eSDavid du Colombier 	Memimage *dst, *src, *mask;
36159cc4ca5SDavid du Colombier 	int m;
3627dd7cddfSDavid du Colombier 
3637dd7cddfSDavid du Colombier 	if(hwaccel == 0)
3647dd7cddfSDavid du Colombier 		return 0;
3657dd7cddfSDavid du Colombier 
3667dd7cddfSDavid du Colombier 	scr = &vgascreen[0];
3674de34a7eSDavid du Colombier 	if((dst=par->dst) == nil || dst->data == nil)
3687dd7cddfSDavid du Colombier 		return 0;
3694de34a7eSDavid du Colombier 	if((src=par->src) == nil || src->data == nil)
3704de34a7eSDavid du Colombier 		return 0;
3714de34a7eSDavid du Colombier 	if((mask=par->mask) == nil || mask->data == nil)
3724de34a7eSDavid du Colombier 		return 0;
3734de34a7eSDavid du Colombier 
3744de34a7eSDavid du Colombier 	if(scr->cur == &swcursor){
37558db92f4SDavid du Colombier 		/*
37658db92f4SDavid du Colombier 		 * always calling swcursorhide here doesn't cure
37758db92f4SDavid du Colombier 		 * leaving cursor tracks nor failing to refresh menus
37858db92f4SDavid du Colombier 		 * with the latest libmemdraw/draw.c.
37958db92f4SDavid du Colombier 		 */
3804de34a7eSDavid du Colombier 		if(dst->data->bdata == gscreendata.bdata)
3814de34a7eSDavid du Colombier 			swcursoravoid(par->r);
3824de34a7eSDavid du Colombier 		if(src->data->bdata == gscreendata.bdata)
3834de34a7eSDavid du Colombier 			swcursoravoid(par->sr);
3844de34a7eSDavid du Colombier 		if(mask->data->bdata == gscreendata.bdata)
3854de34a7eSDavid du Colombier 			swcursoravoid(par->mr);
3864de34a7eSDavid du Colombier 	}
3877dd7cddfSDavid du Colombier 
3887dd7cddfSDavid du Colombier 	if(dst->data->bdata != gscreendata.bdata)
3897dd7cddfSDavid du Colombier 		return 0;
3907dd7cddfSDavid du Colombier 
3917dd7cddfSDavid du Colombier 	if(scr->fill==nil && scr->scroll==nil)
3927dd7cddfSDavid du Colombier 		return 0;
3937dd7cddfSDavid du Colombier 
3947dd7cddfSDavid du Colombier 	/*
3957dd7cddfSDavid du Colombier 	 * If we have an opaque mask and source is one opaque
3967dd7cddfSDavid du Colombier 	 * pixel we can convert to the destination format and just
3977dd7cddfSDavid du Colombier 	 * replicate with memset.
3987dd7cddfSDavid du Colombier 	 */
39959cc4ca5SDavid du Colombier 	m = Simplesrc|Simplemask|Fullmask;
4006a9fc400SDavid du Colombier 	if(scr->fill
4016a9fc400SDavid du Colombier 	&& (par->state&m)==m
4026a9fc400SDavid du Colombier 	&& ((par->srgba&0xFF) == 0xFF)
4036a9fc400SDavid du Colombier 	&& (par->op&S) == S)
4047dd7cddfSDavid du Colombier 		return scr->fill(scr, par->r, par->sdval);
4057dd7cddfSDavid du Colombier 
4067dd7cddfSDavid du Colombier 	/*
4077dd7cddfSDavid du Colombier 	 * If no source alpha, an opaque mask, we can just copy the
4087dd7cddfSDavid du Colombier 	 * source onto the destination.  If the channels are the same and
4097dd7cddfSDavid du Colombier 	 * the source is not replicated, memmove suffices.
4107dd7cddfSDavid du Colombier 	 */
4116a9fc400SDavid du Colombier 	m = Simplemask|Fullmask;
4126a9fc400SDavid du Colombier 	if(scr->scroll
4136a9fc400SDavid du Colombier 	&& src->data->bdata==dst->data->bdata
4146a9fc400SDavid du Colombier 	&& !(src->flags&Falpha)
4156a9fc400SDavid du Colombier 	&& (par->state&m)==m
4166a9fc400SDavid du Colombier 	&& (par->op&S) == S)
4177dd7cddfSDavid du Colombier 		return scr->scroll(scr, par->r, par->sr);
4187dd7cddfSDavid du Colombier 
4197dd7cddfSDavid du Colombier 	return 0;
4207dd7cddfSDavid du Colombier }
4217dd7cddfSDavid du Colombier 
4227dd7cddfSDavid du Colombier void
blankscreen(int blank)4237dd7cddfSDavid du Colombier blankscreen(int blank)
4247dd7cddfSDavid du Colombier {
4257dd7cddfSDavid du Colombier 	VGAscr *scr;
4267dd7cddfSDavid du Colombier 
4277dd7cddfSDavid du Colombier 	scr = &vgascreen[0];
4289a747e4fSDavid du Colombier 	if(hwblank){
4299a747e4fSDavid du Colombier 		if(scr->blank)
4307dd7cddfSDavid du Colombier 			scr->blank(scr, blank);
4319a747e4fSDavid du Colombier 		else
4329a747e4fSDavid du Colombier 			vgablank(scr, blank);
4339a747e4fSDavid du Colombier 	}
4347dd7cddfSDavid du Colombier }
4354de34a7eSDavid du Colombier 
4364de34a7eSDavid du Colombier void
vgalinearpciid(VGAscr * scr,int vid,int did)4374de34a7eSDavid du Colombier vgalinearpciid(VGAscr *scr, int vid, int did)
4384de34a7eSDavid du Colombier {
4394de34a7eSDavid du Colombier 	Pcidev *p;
4404de34a7eSDavid du Colombier 
4414de34a7eSDavid du Colombier 	p = nil;
4424de34a7eSDavid du Colombier 	while((p = pcimatch(p, vid, 0)) != nil){
4434de34a7eSDavid du Colombier 		if(p->ccrb != 3)	/* video card */
4444de34a7eSDavid du Colombier 			continue;
4454de34a7eSDavid du Colombier 		if(did != 0 && p->did != did)
4464de34a7eSDavid du Colombier 			continue;
4474de34a7eSDavid du Colombier 		break;
4484de34a7eSDavid du Colombier 	}
4494de34a7eSDavid du Colombier 	if(p == nil)
4504de34a7eSDavid du Colombier 		error("pci video card not found");
4514de34a7eSDavid du Colombier 
4524de34a7eSDavid du Colombier 	scr->pci = p;
4534de34a7eSDavid du Colombier 	vgalinearpci(scr);
4544de34a7eSDavid du Colombier }
4554de34a7eSDavid du Colombier 
4564de34a7eSDavid du Colombier void
vgalinearpci(VGAscr * scr)4574de34a7eSDavid du Colombier vgalinearpci(VGAscr *scr)
4584de34a7eSDavid du Colombier {
4594de34a7eSDavid du Colombier 	ulong paddr;
4604de34a7eSDavid du Colombier 	int i, size, best;
4614de34a7eSDavid du Colombier 	Pcidev *p;
4624de34a7eSDavid du Colombier 
4634de34a7eSDavid du Colombier 	p = scr->pci;
4644de34a7eSDavid du Colombier 	if(p == nil)
4654de34a7eSDavid du Colombier 		return;
4664de34a7eSDavid du Colombier 
4674de34a7eSDavid du Colombier 	/*
4684de34a7eSDavid du Colombier 	 * Scan for largest memory region on card.
4694de34a7eSDavid du Colombier 	 * Some S3 cards (e.g. Savage) have enormous
4704de34a7eSDavid du Colombier 	 * mmio regions (but even larger frame buffers).
4719c06fe1dSDavid du Colombier 	 * Some 3dfx cards (e.g., Voodoo3) have mmio
4729c06fe1dSDavid du Colombier 	 * buffers the same size as the frame buffer,
4739c06fe1dSDavid du Colombier 	 * but only the frame buffer is marked as
4749c06fe1dSDavid du Colombier 	 * prefetchable (bar&8).  If a card doesn't fit
4759c06fe1dSDavid du Colombier 	 * into these heuristics, its driver will have to
4769c06fe1dSDavid du Colombier 	 * call vgalinearaddr directly.
4774de34a7eSDavid du Colombier 	 */
4784de34a7eSDavid du Colombier 	best = -1;
4794de34a7eSDavid du Colombier 	for(i=0; i<nelem(p->mem); i++){
4804de34a7eSDavid du Colombier 		if(p->mem[i].bar&1)	/* not memory */
4814de34a7eSDavid du Colombier 			continue;
4824de34a7eSDavid du Colombier 		if(p->mem[i].size < 640*480)	/* not big enough */
4834de34a7eSDavid du Colombier 			continue;
4849c06fe1dSDavid du Colombier 		if(best==-1
4859c06fe1dSDavid du Colombier 		|| p->mem[i].size > p->mem[best].size
4864baec263SDavid du Colombier 		|| (p->mem[i].size == p->mem[best].size
4874baec263SDavid du Colombier 		  && (p->mem[i].bar&8)
4884baec263SDavid du Colombier 		  && !(p->mem[best].bar&8)))
4894de34a7eSDavid du Colombier 			best = i;
4904de34a7eSDavid du Colombier 	}
4914de34a7eSDavid du Colombier 	if(best >= 0){
4924de34a7eSDavid du Colombier 		paddr = p->mem[best].bar & ~0x0F;
4934de34a7eSDavid du Colombier 		size = p->mem[best].size;
4944de34a7eSDavid du Colombier 		vgalinearaddr(scr, paddr, size);
4954de34a7eSDavid du Colombier 		return;
4964de34a7eSDavid du Colombier 	}
4974de34a7eSDavid du Colombier 	error("no video memory found on pci card");
4984de34a7eSDavid du Colombier }
4994de34a7eSDavid du Colombier 
5004de34a7eSDavid du Colombier void
vgalinearaddr(VGAscr * scr,ulong paddr,int size)5014de34a7eSDavid du Colombier vgalinearaddr(VGAscr *scr, ulong paddr, int size)
5024de34a7eSDavid du Colombier {
5034de34a7eSDavid du Colombier 	int x, nsize;
5044de34a7eSDavid du Colombier 	ulong npaddr;
5054de34a7eSDavid du Colombier 
5064de34a7eSDavid du Colombier 	/*
5074de34a7eSDavid du Colombier 	 * new approach.  instead of trying to resize this
5084de34a7eSDavid du Colombier 	 * later, let's assume that we can just allocate the
5094de34a7eSDavid du Colombier 	 * entire window to start with.
5104de34a7eSDavid du Colombier 	 */
5114de34a7eSDavid du Colombier 
5124de34a7eSDavid du Colombier 	if(scr->paddr == paddr && size <= scr->apsize)
5134de34a7eSDavid du Colombier 		return;
5144de34a7eSDavid du Colombier 
5154de34a7eSDavid du Colombier 	if(scr->paddr){
5164de34a7eSDavid du Colombier 		/*
5174de34a7eSDavid du Colombier 		 * could call vunmap and vmap,
5184de34a7eSDavid du Colombier 		 * but worried about dangling pointers in devdraw
5194de34a7eSDavid du Colombier 		 */
5204de34a7eSDavid du Colombier 		error("cannot grow vga frame buffer");
5214de34a7eSDavid du Colombier 	}
5224de34a7eSDavid du Colombier 
5234de34a7eSDavid du Colombier 	/* round to page boundary, just in case */
5244de34a7eSDavid du Colombier 	x = paddr&(BY2PG-1);
5254de34a7eSDavid du Colombier 	npaddr = paddr-x;
5264de34a7eSDavid du Colombier 	nsize = PGROUND(size+x);
5274de34a7eSDavid du Colombier 
5281bd28109SDavid du Colombier 	/*
5291bd28109SDavid du Colombier 	 * Don't bother trying to map more than 4000x4000x32 = 64MB.
5301bd28109SDavid du Colombier 	 * We only have a 256MB window.
5311bd28109SDavid du Colombier 	 */
5321bd28109SDavid du Colombier 	if(nsize > 64*MB)
5331bd28109SDavid du Colombier 		nsize = 64*MB;
5344de34a7eSDavid du Colombier 	scr->vaddr = vmap(npaddr, nsize);
5354de34a7eSDavid du Colombier 	if(scr->vaddr == 0)
5364de34a7eSDavid du Colombier 		error("cannot allocate vga frame buffer");
5374de34a7eSDavid du Colombier 	scr->vaddr = (char*)scr->vaddr+x;
5384de34a7eSDavid du Colombier 	scr->paddr = paddr;
5394de34a7eSDavid du Colombier 	scr->apsize = nsize;
540*cb8c047aSDavid du Colombier 	/* let mtrr harmlessly fail on old CPUs, e.g., P54C */
541*cb8c047aSDavid du Colombier 	if(!waserror()){
542*cb8c047aSDavid du Colombier 		mtrr(npaddr, nsize, "wc");
543*cb8c047aSDavid du Colombier 		poperror();
544*cb8c047aSDavid du Colombier 	}
5454de34a7eSDavid du Colombier }
5464de34a7eSDavid du Colombier 
5474de34a7eSDavid du Colombier 
5484de34a7eSDavid du Colombier /*
5494de34a7eSDavid du Colombier  * Software cursor.
5504de34a7eSDavid du Colombier  */
5514de34a7eSDavid du Colombier int	swvisible;	/* is the cursor visible? */
5524de34a7eSDavid du Colombier int	swenabled;	/* is the cursor supposed to be on the screen? */
5534de34a7eSDavid du Colombier Memimage*	swback;	/* screen under cursor */
5544de34a7eSDavid du Colombier Memimage*	swimg;	/* cursor image */
5554de34a7eSDavid du Colombier Memimage*	swmask;	/* cursor mask */
5564de34a7eSDavid du Colombier Memimage*	swimg1;
5574de34a7eSDavid du Colombier Memimage*	swmask1;
5584de34a7eSDavid du Colombier 
5594de34a7eSDavid du Colombier Point	swoffset;
5604de34a7eSDavid du Colombier Rectangle	swrect;	/* screen rectangle in swback */
5614de34a7eSDavid du Colombier Point	swpt;	/* desired cursor location */
5624de34a7eSDavid du Colombier Point	swvispt;	/* actual cursor location */
5634de34a7eSDavid du Colombier int	swvers;	/* incremented each time cursor image changes */
5644de34a7eSDavid du Colombier int	swvisvers;	/* the version on the screen */
5654de34a7eSDavid du Colombier 
5664de34a7eSDavid du Colombier /*
5674de34a7eSDavid du Colombier  * called with drawlock locked for us, most of the time.
5684de34a7eSDavid du Colombier  * kernel prints at inopportune times might mean we don't
5694de34a7eSDavid du Colombier  * hold the lock, but memimagedraw is now reentrant so
5704de34a7eSDavid du Colombier  * that should be okay: worst case we get cursor droppings.
5714de34a7eSDavid du Colombier  */
5724de34a7eSDavid du Colombier void
swcursorhide(void)5734de34a7eSDavid du Colombier swcursorhide(void)
5744de34a7eSDavid du Colombier {
5754de34a7eSDavid du Colombier 	if(swvisible == 0)
5764de34a7eSDavid du Colombier 		return;
5774de34a7eSDavid du Colombier 	if(swback == nil)
5784de34a7eSDavid du Colombier 		return;
5794de34a7eSDavid du Colombier 	swvisible = 0;
5804de34a7eSDavid du Colombier 	memimagedraw(gscreen, swrect, swback, ZP, memopaque, ZP, S);
58126d1d1dfSDavid du Colombier 	flushmemscreen(swrect);
5824de34a7eSDavid du Colombier }
5834de34a7eSDavid du Colombier 
5844de34a7eSDavid du Colombier void
swcursoravoid(Rectangle r)5854de34a7eSDavid du Colombier swcursoravoid(Rectangle r)
5864de34a7eSDavid du Colombier {
5874de34a7eSDavid du Colombier 	if(swvisible && rectXrect(r, swrect))
5884de34a7eSDavid du Colombier 		swcursorhide();
5894de34a7eSDavid du Colombier }
5904de34a7eSDavid du Colombier 
5914de34a7eSDavid du Colombier void
swcursordraw(void)5924de34a7eSDavid du Colombier swcursordraw(void)
5934de34a7eSDavid du Colombier {
5944de34a7eSDavid du Colombier 	if(swvisible)
5954de34a7eSDavid du Colombier 		return;
5964de34a7eSDavid du Colombier 	if(swenabled == 0)
5974de34a7eSDavid du Colombier 		return;
5984de34a7eSDavid du Colombier 	if(swback == nil || swimg1 == nil || swmask1 == nil)
5994de34a7eSDavid du Colombier 		return;
6004de34a7eSDavid du Colombier 	assert(!canqlock(&drawlock));
6014de34a7eSDavid du Colombier 	swvispt = swpt;
6024de34a7eSDavid du Colombier 	swvisvers = swvers;
6034de34a7eSDavid du Colombier 	swrect = rectaddpt(Rect(0,0,16,16), swvispt);
6044de34a7eSDavid du Colombier 	memimagedraw(swback, swback->r, gscreen, swpt, memopaque, ZP, S);
6054de34a7eSDavid du Colombier 	memimagedraw(gscreen, swrect, swimg1, ZP, swmask1, ZP, SoverD);
60626d1d1dfSDavid du Colombier 	flushmemscreen(swrect);
6074de34a7eSDavid du Colombier 	swvisible = 1;
6084de34a7eSDavid du Colombier }
6094de34a7eSDavid du Colombier 
6104de34a7eSDavid du Colombier /*
6114de34a7eSDavid du Colombier  * Need to lock drawlock for ourselves.
6124de34a7eSDavid du Colombier  */
6134de34a7eSDavid du Colombier void
swenable(VGAscr *)6144de34a7eSDavid du Colombier swenable(VGAscr*)
6154de34a7eSDavid du Colombier {
6164de34a7eSDavid du Colombier 	swenabled = 1;
6174de34a7eSDavid du Colombier 	if(canqlock(&drawlock)){
6184de34a7eSDavid du Colombier 		swcursordraw();
6194de34a7eSDavid du Colombier 		qunlock(&drawlock);
6204de34a7eSDavid du Colombier 	}
6214de34a7eSDavid du Colombier }
6224de34a7eSDavid du Colombier 
6234de34a7eSDavid du Colombier void
swdisable(VGAscr *)6244de34a7eSDavid du Colombier swdisable(VGAscr*)
6254de34a7eSDavid du Colombier {
6264de34a7eSDavid du Colombier 	swenabled = 0;
6274de34a7eSDavid du Colombier 	if(canqlock(&drawlock)){
6284de34a7eSDavid du Colombier 		swcursorhide();
6294de34a7eSDavid du Colombier 		qunlock(&drawlock);
6304de34a7eSDavid du Colombier 	}
6314de34a7eSDavid du Colombier }
6324de34a7eSDavid du Colombier 
6334de34a7eSDavid du Colombier void
swload(VGAscr *,Cursor * curs)6344de34a7eSDavid du Colombier swload(VGAscr*, Cursor *curs)
6354de34a7eSDavid du Colombier {
6364de34a7eSDavid du Colombier 	uchar *ip, *mp;
6374de34a7eSDavid du Colombier 	int i, j, set, clr;
6384de34a7eSDavid du Colombier 
6394de34a7eSDavid du Colombier 	if(!swimg || !swmask || !swimg1 || !swmask1)
6404de34a7eSDavid du Colombier 		return;
6414de34a7eSDavid du Colombier 	/*
6424de34a7eSDavid du Colombier 	 * Build cursor image and mask.
6434de34a7eSDavid du Colombier 	 * Image is just the usual cursor image
6444de34a7eSDavid du Colombier 	 * but mask is a transparent alpha mask.
6454de34a7eSDavid du Colombier 	 *
6464de34a7eSDavid du Colombier 	 * The 16x16x8 memimages do not have
6474de34a7eSDavid du Colombier 	 * padding at the end of their scan lines.
6484de34a7eSDavid du Colombier 	 */
6494de34a7eSDavid du Colombier 	ip = byteaddr(swimg, ZP);
6504de34a7eSDavid du Colombier 	mp = byteaddr(swmask, ZP);
6514de34a7eSDavid du Colombier 	for(i=0; i<32; i++){
6524de34a7eSDavid du Colombier 		set = curs->set[i];
6534de34a7eSDavid du Colombier 		clr = curs->clr[i];
6544de34a7eSDavid du Colombier 		for(j=0x80; j; j>>=1){
6554de34a7eSDavid du Colombier 			*ip++ = set&j ? 0x00 : 0xFF;
6564de34a7eSDavid du Colombier 			*mp++ = (clr|set)&j ? 0xFF : 0x00;
6574de34a7eSDavid du Colombier 		}
6584de34a7eSDavid du Colombier 	}
6594de34a7eSDavid du Colombier 	swoffset = curs->offset;
6604de34a7eSDavid du Colombier 	swvers++;
6614de34a7eSDavid du Colombier 	memimagedraw(swimg1, swimg1->r, swimg, ZP, memopaque, ZP, S);
6624de34a7eSDavid du Colombier 	memimagedraw(swmask1, swmask1->r, swmask, ZP, memopaque, ZP, S);
6634de34a7eSDavid du Colombier }
6644de34a7eSDavid du Colombier 
6654de34a7eSDavid du Colombier int
swmove(VGAscr *,Point p)6664de34a7eSDavid du Colombier swmove(VGAscr*, Point p)
6674de34a7eSDavid du Colombier {
6684de34a7eSDavid du Colombier 	swpt = addpt(p, swoffset);
6694de34a7eSDavid du Colombier 	return 0;
6704de34a7eSDavid du Colombier }
6714de34a7eSDavid du Colombier 
6724de34a7eSDavid du Colombier void
swcursorclock(void)6734de34a7eSDavid du Colombier swcursorclock(void)
6744de34a7eSDavid du Colombier {
6754de34a7eSDavid du Colombier 	int x;
6764de34a7eSDavid du Colombier 
6774de34a7eSDavid du Colombier 	if(!swenabled)
6784de34a7eSDavid du Colombier 		return;
6794de34a7eSDavid du Colombier 	if(swvisible && eqpt(swpt, swvispt) && swvers==swvisvers)
6804de34a7eSDavid du Colombier 		return;
6814de34a7eSDavid du Colombier 
6824de34a7eSDavid du Colombier 	x = splhi();
6834de34a7eSDavid du Colombier 	if(swenabled)
6844de34a7eSDavid du Colombier 	if(!swvisible || !eqpt(swpt, swvispt) || swvers!=swvisvers)
6854de34a7eSDavid du Colombier 	if(canqlock(&drawlock)){
6864de34a7eSDavid du Colombier 		swcursorhide();
6874de34a7eSDavid du Colombier 		swcursordraw();
6884de34a7eSDavid du Colombier 		qunlock(&drawlock);
6894de34a7eSDavid du Colombier 	}
6904de34a7eSDavid du Colombier 	splx(x);
6914de34a7eSDavid du Colombier }
6924de34a7eSDavid du Colombier 
6934de34a7eSDavid du Colombier void
swcursorinit(void)6944de34a7eSDavid du Colombier swcursorinit(void)
6954de34a7eSDavid du Colombier {
6964de34a7eSDavid du Colombier 	static int init, warned;
6974de34a7eSDavid du Colombier 	VGAscr *scr;
6984de34a7eSDavid du Colombier 
6994de34a7eSDavid du Colombier 	didswcursorinit = 1;
7004de34a7eSDavid du Colombier 	if(!init){
7014de34a7eSDavid du Colombier 		init = 1;
70226ad7229SDavid du Colombier 		addclock0link(swcursorclock, 10);
7034de34a7eSDavid du Colombier 	}
7044de34a7eSDavid du Colombier 	scr = &vgascreen[0];
7054de34a7eSDavid du Colombier 	if(scr==nil || scr->gscreen==nil)
7064de34a7eSDavid du Colombier 		return;
7074de34a7eSDavid du Colombier 
7084de34a7eSDavid du Colombier 	if(scr->dev == nil || scr->dev->linear == nil){
7094de34a7eSDavid du Colombier 		if(!warned){
7104de34a7eSDavid du Colombier 			print("cannot use software cursor on non-linear vga screen\n");
7114de34a7eSDavid du Colombier 			warned = 1;
7124de34a7eSDavid du Colombier 		}
7134de34a7eSDavid du Colombier 		return;
7144de34a7eSDavid du Colombier 	}
7154de34a7eSDavid du Colombier 
7164de34a7eSDavid du Colombier 	if(swback){
7174de34a7eSDavid du Colombier 		freememimage(swback);
7184de34a7eSDavid du Colombier 		freememimage(swmask);
7194de34a7eSDavid du Colombier 		freememimage(swmask1);
7204de34a7eSDavid du Colombier 		freememimage(swimg);
7214de34a7eSDavid du Colombier 		freememimage(swimg1);
7224de34a7eSDavid du Colombier 	}
7234de34a7eSDavid du Colombier 
7244de34a7eSDavid du Colombier 	swback = allocmemimage(Rect(0,0,32,32), gscreen->chan);
7254de34a7eSDavid du Colombier 	swmask = allocmemimage(Rect(0,0,16,16), GREY8);
7264de34a7eSDavid du Colombier 	swmask1 = allocmemimage(Rect(0,0,16,16), GREY1);
7274de34a7eSDavid du Colombier 	swimg = allocmemimage(Rect(0,0,16,16), GREY8);
7284de34a7eSDavid du Colombier 	swimg1 = allocmemimage(Rect(0,0,16,16), GREY1);
7294de34a7eSDavid du Colombier 	if(swback==nil || swmask==nil || swmask1==nil || swimg==nil || swimg1 == nil){
730dc4ee190SDavid du Colombier 		print("software cursor: allocmemimage fails");
7314de34a7eSDavid du Colombier 		return;
7324de34a7eSDavid du Colombier 	}
7334de34a7eSDavid du Colombier 
7344de34a7eSDavid du Colombier 	memfillcolor(swmask, DOpaque);
7354de34a7eSDavid du Colombier 	memfillcolor(swmask1, DOpaque);
7364de34a7eSDavid du Colombier 	memfillcolor(swimg, DBlack);
7374de34a7eSDavid du Colombier 	memfillcolor(swimg1, DBlack);
7384de34a7eSDavid du Colombier }
7394de34a7eSDavid du Colombier 
7404de34a7eSDavid du Colombier VGAcur swcursor =
7414de34a7eSDavid du Colombier {
7424de34a7eSDavid du Colombier 	"soft",
7434de34a7eSDavid du Colombier 	swenable,
7444de34a7eSDavid du Colombier 	swdisable,
7454de34a7eSDavid du Colombier 	swload,
7464de34a7eSDavid du Colombier 	swmove,
7474de34a7eSDavid du Colombier };
7484de34a7eSDavid du Colombier 
749