plan 9 kernel history: overview | file list | diff list

1998/0803/pc/vgamach64xx.c (diff list | history)

1998/0507/sys/src/9/pc/vgamach64xx.c:12,181998/0508/sys/src/9/pc/vgamach64xx.c:12,18 (short | long)
Add support for more cards.
rsc Fri Mar 4 12:44:25 2005
1998/0507    
#include "screen.h" 
 
/* 
 * ATI Mach64. 
1998/0508    
 * ATI Mach64(CT|ET|GP|GT|GU|VT|VU). 
1998/0507    
 */ 
static ushort mach64xxdid[] = { 
	('C'<<8)|'T', 
1998/0507/sys/src/9/pc/vgamach64xx.c:35,461998/0508/sys/src/9/pc/vgamach64xx.c:35,44
1998/0507    
		return nil; 
	for(did = mach64xxdid; *did; did++){ 
		if(*did == p->did) 
			break; 
1998/0508    
			return p; 
1998/0507    
	} 
	if(*did == 0) 
		return nil; 
 
	return p; 
1998/0508    
	return nil; 
1998/0507    
} 
 
static void 
1998/0507/sys/src/9/pc/vgamach64xx.c:53,601998/0508/sys/src/9/pc/vgamach64xx.c:51,67
1998/0507    
	 */ 
	if(scr->io) 
		return; 
	if(p = mach64xxpci()) 
		scr->io = p->mem[1].bar & ~0x01; 
1998/0508    
	if(p = mach64xxpci()){ 
		/* 
		 * The CT doesn't always have the I/O base address 
		 * in the PCI base registers. There is a way to find 
		 * it via the vendor-specific PCI config space but 
		 * this will do for now. 
		 */ 
		scr->io = p->mem[1].bar & ~0x03; 
		if(scr->io == 0 && p->did == ('C'<<8)|'T') 
			scr->io = 0x2EC; 
	} 
1998/0507    
} 
 
static ulong 
1998/0507/sys/src/9/pc/vgamach64xx.c:89,1141998/0508/sys/src/9/pc/vgamach64xx.c:96,137
1998/0507    
	return aperture; 
} 
 
enum {					/* I/O select */ 
	CurClr0		= 0x18, 
	CurClr1		= 0x19, 
	CurOffset	= 0x1a, 
	CurHVposn	= 0x1b, 
	CurHVoff	= 0x1c, 
1998/0508    
enum {					/* MM offset */ 
1998/0507    
 
	GenTestCntl	= 0x34, 
1998/0508    
	CurClr0		= 0x0B,		/* I/O Select */ 
	CurClr1		= 0x0C, 
	CurOffset	= 0x0D, 
	CurHVposn	= 0x0E, 
	CurHVoff	= 0x0F, 
 
	GenTestCntl	= 0x19, 
1998/0507    
}; 
 
1998/0508    
static uchar mmoffset[] = { 
	[CurClr0]	0x18, 
	[CurClr1]	0x19, 
	[CurOffset]	0x1a, 
	[CurHVposn]	0x1b, 
	[CurHVoff]	0x1c, 
 
	[GenTestCntl]	0x34, 
}; 
 
1998/0507    
static ulong 
ior32(VGAscr* scr, int r) 
{ 
	return inl((r<<2)+scr->io); 
1998/0508    
	if(scr->io == 0x2EC || scr->io == 0x1C8) 
		return inl((r<<10)+scr->io); 
	return inl((mmoffset[r]<<2)+scr->io); 
1998/0507    
} 
 
static void 
iow32(VGAscr* scr, int r, ulong l) 
{ 
	outl(((r)<<2)+scr->io, l); 
1998/0508    
	if(scr->io == 0x2EC || scr->io == 0x1C8) 
		outl(((r)<<10)+scr->io, l); 
	else 
		outl((mmoffset[r]<<2)+scr->io, l); 
1998/0507    
} 
 
static void 
1998/0508/sys/src/9/pc/vgamach64xx.c:96,1031998/0511/sys/src/9/pc/vgamach64xx.c:96,102 (short | long)
Comment edit. Uppercase hex.
rsc Fri Mar 4 12:44:25 2005
1998/0507    
	return aperture; 
} 
 
1998/0508    
enum {					/* MM offset */ 
1998/0507    
                 
1998/0511    
enum { 
1998/0508    
	CurClr0		= 0x0B,		/* I/O Select */ 
	CurClr1		= 0x0C, 
	CurOffset	= 0x0D, 
1998/0508/sys/src/9/pc/vgamach64xx.c:110,1181998/0511/sys/src/9/pc/vgamach64xx.c:109,117
1998/0508    
static uchar mmoffset[] = { 
	[CurClr0]	0x18, 
	[CurClr1]	0x19, 
	[CurOffset]	0x1a, 
	[CurHVposn]	0x1b, 
	[CurHVoff]	0x1c, 
1998/0511    
	[CurOffset]	0x1A, 
	[CurHVposn]	0x1B, 
	[CurHVoff]	0x1C, 
1998/0508    
 
	[GenTestCntl]	0x34, 
}; 
1998/0508/sys/src/9/pc/vgamach64xx.c:159,1641998/0511/sys/src/9/pc/vgamach64xx.c:158,173
1998/0507    
	p = KADDR(scr->aperture); 
	p += scr->storage; 
 
1998/0511    
	/* 
	 * Initialise the 64x64 cursor RAM array. 
	 * The cursor mode gives the following truth table: 
	 *	p1 p0	colour 
	 *	 0  0	Cursor Colour 0 
	 *	 0  1	Cursor Colour 1 
	 *	 1  0	Transparent 
	 *	 1  1	Complement 
	 * Put the cursor into the top-right of the 64x64 array. 
	 */ 
1998/0507    
	for(y = 0; y < 16; y++){ 
		for(i = 0; i < (64-16)/8; i++){ 
			*p++ = 0xAA; 
1998/0511/sys/src/9/pc/vgamach64xx.c:12,231998/0803/sys/src/9/pc/vgamach64xx.c:12,27 (short | long)
Add more card types.
rsc Fri Mar 4 12:44:25 2005
1998/0507    
#include "screen.h" 
 
/* 
1998/0508    
 * ATI Mach64(CT|ET|GP|GT|GU|VT|VU). 
1998/0803    
 * ATI Mach64(CT|ET|G*|VT|VU). 
1998/0507    
 */ 
static ushort mach64xxdid[] = { 
	('C'<<8)|'T', 
	('E'<<8)|'T', 
1998/0803    
	('G'<<8)|'B', 
	('G'<<8)|'D', 
	('G'<<8)|'I', 
1998/0507    
	('G'<<8)|'P', 
1998/0803    
	('G'<<8)|'Q', 
1998/0507    
	('G'<<8)|'T', 
	('G'<<8)|'U', 
	('V'<<8)|'T', 
1998/0803/sys/src/9/pc/vgamach64xx.c:9,141999/0119/sys/src/9/pc/vgamach64xx.c:9,15 (short | long)
1998/0507    
#define	Image	IMAGE 
#include <draw.h> 
#include <memdraw.h> 
1999/0119    
#include <cursor.h> 
1998/0507    
#include "screen.h" 
 
/* 
1999/0119/sys/src/9/pc/vgamach64xx.c:25,301999/0909/sys/src/9/pc/vgamach64xx.c:25,31 (short | long)
1998/0803    
	('G'<<8)|'Q', 
1998/0507    
	('G'<<8)|'T', 
	('G'<<8)|'U', 
1999/0909    
	('G'<<8)|'Z', 
1998/0507    
	('V'<<8)|'T', 
	('V'<<8)|'U', 
	0, 
1999/0909/sys/src/9/pc/vgamach64xx.c:25,301999/0911/sys/src/9/pc/vgamach64xx.c:25,31 (short | long)
1998/0803    
	('G'<<8)|'Q', 
1998/0507    
	('G'<<8)|'T', 
	('G'<<8)|'U', 
1999/0911    
	('G'<<8)|'V', 
1999/0909    
	('G'<<8)|'Z', 
1998/0507    
	('V'<<8)|'T', 
	('V'<<8)|'U', 
1999/0911/sys/src/9/pc/vgamach64xx.c:13,191999/1005/sys/src/9/pc/vgamach64xx.c:13,19 (short | long)
1998/0507    
#include "screen.h" 
 
/* 
1998/0803    
 * ATI Mach64(CT|ET|G*|VT|VU). 
1999/1005    
 * ATI Mach64(CT|ET|G*|VT|VU|LP). 
1998/0507    
 */ 
static ushort mach64xxdid[] = { 
	('C'<<8)|'T', 
1999/0911/sys/src/9/pc/vgamach64xx.c:25,371999/1005/sys/src/9/pc/vgamach64xx.c:25,40
1998/0803    
	('G'<<8)|'Q', 
1998/0507    
	('G'<<8)|'T', 
	('G'<<8)|'U', 
1999/0911    
	('G'<<8)|'V', 
1999/0909    
	('G'<<8)|'Z', 
1998/0507    
	('V'<<8)|'T', 
	('V'<<8)|'U', 
1999/1005    
	('L'<<8)|'P', 
1998/0507    
	0, 
}; 
 
1999/1005    
static int hwfill(VGAscr*, Rectangle, ulong); 
static int hwscroll(VGAscr*, Rectangle, Rectangle); 
static void initengine(VGAscr*); 
 
1998/0507    
static Pcidev* 
mach64xxpci(void) 
{ 
1999/0911/sys/src/9/pc/vgamach64xx.c:66,711999/1005/sys/src/9/pc/vgamach64xx.c:69,75
1998/0508    
		 * this will do for now. 
		 */ 
		scr->io = p->mem[1].bar & ~0x03; 
1999/1005    
 
1998/0508    
		if(scr->io == 0 && p->did == ('C'<<8)|'T') 
			scr->io = 0x2EC; 
	} 
1999/0911/sys/src/9/pc/vgamach64xx.c:74,831999/1005/sys/src/9/pc/vgamach64xx.c:78,89
1998/0507    
static ulong 
mach64xxlinear(VGAscr* scr, int* size, int* align) 
{ 
	ulong aperture, oaperture; 
1999/1005    
	ulong aperture, osize, oaperture; 
1998/0507    
	int oapsize, wasupamem; 
	Pcidev *p; 
1999/1005    
	Physseg seg; 
1998/0507    
 
1999/1005    
	osize = *size; 
1998/0507    
	oaperture = scr->aperture; 
	oapsize = scr->apsize; 
	wasupamem = scr->isupamem; 
1999/0911/sys/src/9/pc/vgamach64xx.c:100,1261999/1005/sys/src/9/pc/vgamach64xx.c:106,231
1998/0507    
	else 
		scr->isupamem = 1; 
 
1999/1005    
	scr->mmio = (ulong*)(aperture+osize-0x400); 
	if(oaperture) 
		print("warning (BUG): redefinition of aperture does not change mach64mmio segment\n"); 
	memset(&seg, 0, sizeof(seg)); 
	seg.attr = SG_PHYSICAL; 
	seg.name = smalloc(NAMELEN); 
	snprint(seg.name, NAMELEN, "mach64mmio"); 
	seg.pa = aperture+osize - BY2PG; 
	seg.size = BY2PG; 
	addphysseg(&seg); 
 
	seg.name = smalloc(NAMELEN); 
	snprint(seg.name, NAMELEN, "mach64screen"); 
	seg.pa = aperture; 
	seg.size = osize; 
	addphysseg(&seg); 
 
1998/0507    
	return aperture; 
} 
 
1998/0511    
enum { 
1999/1005    
	CrtcOffPitch	= 0x05, 
	CrtcGenCtl	= 0x07, 
1998/0508    
	CurClr0		= 0x0B,		/* I/O Select */ 
	CurClr1		= 0x0C, 
	CurOffset	= 0x0D, 
	CurHVposn	= 0x0E, 
	CurHVoff	= 0x0F, 
                 
1999/1005    
	BusCntl	= 0x13, 
1998/0508    
	GenTestCntl	= 0x19, 
1999/1005    
 
	ContextMask	= 0x100,	/* not accessible via I/O */ 
	FifoStat, 
	GuiStat, 
	DpFrgdClr, 
	DpBkgdClr, 
	DpWriteMask, 
	DpMix, 
	DpPixWidth, 
	DpSrc, 
	ClrCmpCntl, 
	GuiTrajCntl, 
	ScLeftRight, 
	ScTopBottom, 
	DstOffPitch, 
	DstYX, 
	DstHeightWidth, 
	DstCntl, 
	DstHeight, 
	DstBresErr, 
	DstBresInc, 
	DstBresDec, 
	SrcCntl, 
	SrcHeight1Width1, 
	SrcHeight2Width2, 
	SrcYX, 
	SrcWidth1, 
	SrcYXstart, 
	HostCntl, 
	PatReg0, 
	PatReg1, 
	PatCntl, 
	ScBottom, 
	ScLeft, 
	ScRight, 
	ScTop, 
	ClrCmpClr, 
	ClrCmpMask, 
	DpChainMask, 
	SrcOffPitch,	 
1998/0507    
}; 
 
1998/0508    
static uchar mmoffset[] = { 
1999/1005    
	[CrtcOffPitch]	0x05, 
1998/0508    
	[CurClr0]	0x18, 
	[CurClr1]	0x19, 
1998/0511    
	[CurOffset]	0x1A, 
	[CurHVposn]	0x1B, 
	[CurHVoff]	0x1C, 
1998/0508    
                 
1999/1005    
	[BusCntl]		0x28, 
1998/0508    
	[GenTestCntl]	0x34, 
1999/1005    
	[DstOffPitch]	0x40, 
	[DstYX]		0x43, 
	[DstHeight]	0x45, 
	[DstHeightWidth]	0x46, 
	[DstBresErr]	0x49, 
	[DstBresInc]	0x4A, 
	[DstBresDec]	0x4B, 
	[DstCntl]		0x4C, 
	[SrcOffPitch]	0x60, 
	[SrcYX]	0x63, 
	[SrcWidth1]	0x64, 
	[SrcYXstart]	0x69, 
	[SrcHeight1Width1]	0x66, 
	[SrcHeight2Width2]	0x6C, 
	[SrcCntl]		0x6D, 
	[HostCntl]	0x90, 
	[PatReg0]	0xA0, 
	[PatReg1]	0xA1, 
	[PatCntl]	0xA2, 
	[ScLeft]	0xA8, 
	[ScRight]	0xA9, 
	[ScLeftRight]	0xAA, 
	[ScTop]	0xAB, 
	[ScBottom] 0xAC, 
	[ScTopBottom]	0xAD, 
	[DpBkgdClr]	0xB0, 
	[DpFrgdClr]	0xB1, 
	[DpWriteMask]	0xB2, 
	[DpChainMask]	0xB3, 
	[DpPixWidth]	0xB4, 
	[DpMix]		0xB5, 
	[DpSrc]		0xB6, 
	[ClrCmpClr]	0xC0, 
	[ClrCmpMask]	0xC1, 
	[ClrCmpCntl]	0xC2, 
	[FifoStat]		0xC4, 
	[ContextMask]	0xC8, 
	[GuiTrajCntl]	0xCC, 
	[GuiStat]		0xCE, 
1998/0508    
}; 
 
1998/0507    
static ulong 
1999/0911/sys/src/9/pc/vgamach64xx.c:128,1331999/1005/sys/src/9/pc/vgamach64xx.c:233,240
1998/0507    
{ 
1998/0508    
	if(scr->io == 0x2EC || scr->io == 0x1C8) 
		return inl((r<<10)+scr->io); 
1999/1005    
	if(r >= 0x100 && scr->mmio != nil) 
		return scr->mmio[mmoffset[r]]; 
1998/0508    
	return inl((mmoffset[r]<<2)+scr->io); 
1998/0507    
} 
 
1999/0911/sys/src/9/pc/vgamach64xx.c:136,1411999/1005/sys/src/9/pc/vgamach64xx.c:243,250
1998/0507    
{ 
1998/0508    
	if(scr->io == 0x2EC || scr->io == 0x1C8) 
		outl(((r)<<10)+scr->io, l); 
1999/1005    
	else if(r >= 0x100 && scr->mmio != nil) 
		scr->mmio[mmoffset[r]] = l; 
1998/0508    
	else 
		outl((mmoffset[r]<<2)+scr->io, l); 
1998/0507    
} 
1999/0911/sys/src/9/pc/vgamach64xx.c:208,2181999/1005/sys/src/9/pc/vgamach64xx.c:317,393
1998/0507    
} 
 
static int 
1999/1005    
ptalmostinrect(Point p, Rectangle r) 
{ 
	return p.x>=r.min.x && p.x<=r.max.x && 
	       p.y>=r.min.y && p.y<=r.max.y; 
} 
 
/* 
 * If necessary, translate the rectangle physr 
 * some multiple of [dx dy] so that it includes p. 
 * Return 1 if the rectangle changed. 
 */ 
static int 
screenpan(Point p, Rectangle *physr, int dx, int dy) 
{ 
	int d; 
 
	if(ptalmostinrect(p, *physr)) 
		return 0; 
 
	if(p.y < physr->min.y){ 
		d = physr->min.y - (p.y&~(dy-1)); 
		physr->min.y -= d; 
		physr->max.y -= d; 
	} 
	if(p.y > physr->max.y){ 
		d = ((p.y+dy-1)&~(dy-1)) - physr->max.y; 
		physr->min.y += d; 
		physr->max.y += d; 
	} 
 
	if(p.x < physr->min.x){ 
		d = physr->min.x - (p.x&~(dx-1)); 
		physr->min.x -= d; 
		physr->max.x -= d; 
	} 
	if(p.x > physr->max.x){ 
		d = ((p.x+dx-1)&~(dx-1)) - physr->max.x; 
		physr->min.x += d; 
		physr->max.x += d; 
	} 
	return 1; 
} 
 
static int 
1998/0507    
mach64xxcurmove(VGAscr* scr, Point p) 
{ 
	int x, xo, y, yo; 
1999/1005    
	int dx; 
	ulong off, pitch; 
1998/0507    
 
	/* 
1999/1005    
	 * If the point we want to display is outside the current 
	 * screen rectangle, pan the screen to display it. 
	 * 
	 * We have to move in 64-bit chunks. 
	 */ 
	if(scr->gscreen->depth == 24) 
		dx = (64*3)/24; 
	else 
		dx = 64 / scr->gscreen->depth; 
 
	if(screenpan(p, &physgscreenr, dx, 1)){ 
		off = (physgscreenr.min.y*Dx(scr->gscreen->r)+physgscreenr.min.x)/dx; 
		pitch = Dx(scr->gscreen->r)/8; 
		iow32(scr, CrtcOffPitch, (pitch<<22)|off); 
	} 
 
	p.x -= physgscreenr.min.x; 
	p.y -= physgscreenr.min.y; 
 
	/* 
1998/0507    
	 * Mustn't position the cursor offscreen even partially, 
	 * or it disappears. Therefore, if x or y is -ve, adjust the 
	 * cursor presets instead. If y is negative also have to 
1999/0911/sys/src/9/pc/vgamach64xx.c:276,2811999/1005/sys/src/9/pc/vgamach64xx.c:451,669
1998/0507    
	iow32(scr, GenTestCntl, 0x80|r); 
} 
 
1999/1005    
static void 
waitforfifo(VGAscr *scr, int entries) 
{ 
	int x; 
	x = 0; 
	while((ior32(scr, FifoStat)&0xFF) > (0x8000>>entries) && x++ < 1000000) 
		; 
	if(x >= 1000000) 
		iprint("fifo %d stat %.8lux %.8lux scrio %.8lux mmio %p scr %p pc %luX\n", entries, ior32(scr, FifoStat), scr->mmio[mmoffset[FifoStat]], scr->io, scr->mmio, scr, getcallerpc(&scr)); 
} 
 
static void 
waitforidle(VGAscr *scr) 
{ 
	int x; 
	waitforfifo(scr, 16); 
	x = 0; 
	while((ior32(scr, GuiStat)&1) && x++ < 1000000) 
		; 
	if(x >= 1000000) 
		iprint("idle stat %.8lux %.8lux scrio %.8lux mmio %p scr %p pc %luX\n", ior32(scr, GuiStat), scr->mmio[mmoffset[GuiStat]], scr->io, scr->mmio, scr, getcallerpc(&scr)); 
} 
 
static void 
resetengine(VGAscr *scr) 
{ 
	ulong x; 
	x = ior32(scr, GenTestCntl); 
	iow32(scr, GenTestCntl, x&~0x100); 
	iow32(scr, GenTestCntl, x|0x100); 
	iow32(scr, BusCntl, ior32(scr, BusCntl)|0x00A00000); 
} 
 
static void 
initengine(VGAscr *scr) 
{ 
	ulong pitch; 
 
	pitch = Dx(scr->gscreen->r)/8; 
	if(scr->gscreen->depth == 24) 
		pitch *= 3; 
 
	resetengine(scr); 
	waitforfifo(scr, 14); 
	iow32(scr, ContextMask, ~0); 
	iow32(scr, DstOffPitch, pitch<<22); 
	iow32(scr, DstYX, 0); 
	iow32(scr, DstHeight, 0); 
	iow32(scr, DstBresErr, 0); 
	iow32(scr, DstBresInc, 0); 
	iow32(scr, DstBresDec, 0); 
	iow32(scr, DstCntl, 0x23); 
	iow32(scr, SrcOffPitch, pitch<<22); 
	iow32(scr, SrcYX, 0); 
	iow32(scr, SrcHeight1Width1, 1); 
	iow32(scr, SrcYXstart, 0); 
	iow32(scr, SrcHeight2Width2, 1); 
	iow32(scr, SrcCntl, 0x01); 
 
	waitforfifo(scr, 13); 
	iow32(scr, HostCntl, 0); 
	iow32(scr, PatReg0, 0); 
	iow32(scr, PatReg1, 0); 
	iow32(scr, PatCntl, 0); 
	iow32(scr, ScLeft, 0); 
	iow32(scr, ScTop, 0); 
	iow32(scr, ScBottom, 0xFFFF); 
	iow32(scr, ScRight, 0xFFFF); 
	iow32(scr, DpBkgdClr, 0); 
	iow32(scr, DpFrgdClr, ~0); 
	iow32(scr, DpWriteMask, ~0); 
	iow32(scr, DpMix, 0x70003); 
	iow32(scr, DpSrc, 0x00010100); 
 
	waitforfifo(scr, 3); 
	iow32(scr, ClrCmpClr, 0); 
	iow32(scr, ClrCmpMask, ~0); 
	iow32(scr, ClrCmpCntl, 0); 
 
	waitforfifo(scr, 2); 
	switch(scr->gscreen->depth){ 
	case 8: 
	case 24:	/* [sic] */ 
		iow32(scr, DpPixWidth, 0x00020202); 
		iow32(scr, DpChainMask, 0x8080); 
		break; 
	case 16: 
		iow32(scr, DpPixWidth, 0x00040404); 
		iow32(scr, DpChainMask, 0x8410); 
		break; 
	case 32: 
		iow32(scr, DpPixWidth, 0x00060606); 
		iow32(scr, DpChainMask, 0x8080); 
		break; 
	} 
 
	waitforidle(scr); 
} 
 
static int 
mach64hwfill(VGAscr *scr, Rectangle r, ulong sval) 
{ 
	ulong pitch; 
	ulong ctl; 
 
if(drawdebug) 
	iprint("hwfill %R val %lux...\n", r, sval); 
 
	/* shouldn't happen */ 
	if(scr->io == 0x2EC || scr->io == 0x1C8 || scr->io == 0) 
		return 0; 
 
	pitch = Dx(scr->gscreen->r)/8; 
	ctl = 1|2;	/* left-to-right, top-to-bottom */ 
	if(scr->gscreen->depth == 24){ 
		r.min.x *= 3; 
		r.max.x *= 3; 
		pitch *= 3; 
		ctl |= (1<<7)|(((r.min.x/4)%6)<<8); 
	} 
 
	waitforfifo(scr, 11); 
	iow32(scr, DpFrgdClr, sval); 
	iow32(scr, DpWriteMask, 0xFFFFFFFF); 
	iow32(scr, DpMix, 0x00070003); 
	iow32(scr, DpSrc, 0x00000111); 
	iow32(scr, ClrCmpCntl, 0x00000000); 
	iow32(scr, ScLeftRight, 0x1FFF0000); 
	iow32(scr, ScTopBottom, 0x1FFF0000); 
	iow32(scr, DstOffPitch, pitch<<22); 
	iow32(scr, DstCntl, ctl); 
	iow32(scr, DstYX, (r.min.x<<16)|r.min.y); 
	iow32(scr, DstHeightWidth, (Dx(r)<<16)|Dy(r)); 
 
	waitforidle(scr); 
	return 1; 
} 
 
static int 
mach64hwscroll(VGAscr *scr, Rectangle r, Rectangle sr) 
{ 
	ulong pitch; 
	Point dp, sp; 
	ulong ctl; 
	int dx, dy; 
 
	dx = Dx(r); 
	dy = Dy(r); 
	pitch = Dx(scr->gscreen->r)/8; 
	if(scr->gscreen->depth == 24){ 
		dx *= 3; 
		pitch *= 3; 
		r.min.x *= 3; 
		sr.min.x *= 3; 
	} 
 
	ctl = 0; 
	if(r.min.x <= sr.min.x){ 
		ctl |= 1; 
		dp.x = r.min.x; 
		sp.x = sr.min.x; 
	}else{ 
		dp.x = r.min.x+dx-1; 
		sp.x = sr.min.x+dx-1; 
	} 
 
	if(r.min.y <= sr.min.y){ 
		ctl |= 2; 
		dp.y = r.min.y; 
		sp.y = sr.min.y; 
	}else{ 
		dp.y = r.min.y+dy-1; 
		sp.y = sr.min.y+dy-1; 
	} 
 
	if(scr->gscreen->depth == 24) 
		ctl |= (1<<7)|(((dp.x/4)%6)<<8); 
 
	waitforfifo(scr, 6); 
	iow32(scr, ScLeftRight, 0x1FFF0000); 
	iow32(scr, ScTopBottom, 0x1FFF0000); 
	iow32(scr, DpWriteMask, 0xFFFFFFFF); 
	iow32(scr, DpMix, 0x00070003); 
	iow32(scr, DpSrc, 0x00000300); 
	iow32(scr, ClrCmpCntl, 0x00000000); 
 
	waitforfifo(scr, 8); 
	iow32(scr, SrcOffPitch, pitch<<22); 
	iow32(scr, SrcCntl, 0x00000000); 
	iow32(scr, SrcYX, (sp.x<<16)|sp.y); 
	iow32(scr, SrcWidth1, dx); 
	iow32(scr, DstOffPitch, pitch<<22); 
	iow32(scr, DstCntl, ctl); 
 
	iow32(scr, DstYX, (dp.x<<16)|dp.y); 
	iow32(scr, DstHeightWidth, (dx<<16)|dy); 
 
	waitforidle(scr); 
 
	return 1; 
} 
 
static void 
mach64xxdrawinit(VGAscr *scr) 
{ 
	if(scr->io > 0x2FF){ 
		initengine(scr); 
		scr->fill = mach64hwfill; 
		scr->scroll = mach64hwscroll; 
	} 
} 
 
 
1998/0507    
VGAdev vgamach64xxdev = { 
	"mach64xx", 
 
1999/0911/sys/src/9/pc/vgamach64xx.c:283,2881999/1005/sys/src/9/pc/vgamach64xx.c:671,677
1998/0507    
	0,				/* disable */ 
	0,				/* page */ 
	mach64xxlinear,			/* linear */ 
1999/1005    
	mach64xxdrawinit,	/* drawinit */ 
1998/0507    
}; 
 
VGAcur vgamach64xxcur = { 
1999/0911/sys/src/9/pc/vgamach64xx.c:292,2951999/1005/sys/src/9/pc/vgamach64xx.c:681,686
1998/0507    
	mach64xxcurdisable,		/* disable */ 
	mach64xxcurload,		/* load */ 
	mach64xxcurmove,		/* move */ 
1999/1005    
 
	1					/* doespanning */ 
1998/0507    
}; 
1999/1005/sys/src/9/pc/vgamach64xx.c:27,321999/1102/sys/src/9/pc/vgamach64xx.c:27,33 (short | long)
1998/0507    
	('G'<<8)|'U', 
	('V'<<8)|'T', 
	('V'<<8)|'U', 
1999/1102    
	('L'<<8)|'I', 
1999/1005    
	('L'<<8)|'P', 
1998/0507    
	0, 
}; 
1999/1102/sys/src/9/pc/vgamach64xx.c:138,1432000/0330/sys/src/9/pc/vgamach64xx.c:138,146 (short | long)
1999/1005    
	BusCntl	= 0x13, 
1998/0508    
	GenTestCntl	= 0x19, 
1999/1005    
 
2000/0330    
	CrtcHsyncDis	= 0x04, 
	CrtcVsyncDis	= 0x08, 
 
1999/1005    
	ContextMask	= 0x100,	/* not accessible via I/O */ 
	FifoStat, 
	GuiStat, 
1999/1102/sys/src/9/pc/vgamach64xx.c:654,6602000/0330/sys/src/9/pc/vgamach64xx.c:657,677
1999/1005    
	return 1; 
} 
 
2000/0330    
/* 
 * This should work, but doesn't. 
 */ 
1999/1005    
static void 
2000/0330    
mach64blank(VGAscr *scr, int blank) 
{ 
	ulong ctl; 
 
	ctl = ior32(scr, CrtcGenCtl) & ~(CrtcHsyncDis|CrtcVsyncDis); 
	if(blank) 
		ctl |= CrtcHsyncDis|CrtcVsyncDis; 
	iow32(scr, CrtcGenCtl, ctl); 
} 
 
static void 
1999/1005    
mach64xxdrawinit(VGAscr *scr) 
{ 
	if(scr->io > 0x2FF){ 
1999/1102/sys/src/9/pc/vgamach64xx.c:662,6672000/0330/sys/src/9/pc/vgamach64xx.c:679,685
1999/1005    
		scr->fill = mach64hwfill; 
		scr->scroll = mach64hwscroll; 
	} 
2000/0330    
/*	scr->blank = mach64blank; */ 
1999/1005    
} 
 
 
2000/0330/sys/src/9/pc/vgamach64xx.c:28,332000/0413/sys/src/9/pc/vgamach64xx.c:28,34 (short | long)
1998/0507    
	('V'<<8)|'T', 
	('V'<<8)|'U', 
1999/1102    
	('L'<<8)|'I', 
2000/0413    
	('L'<<8)|'M', 
1999/1005    
	('L'<<8)|'P', 
1998/0507    
	0, 
}; 
2000/0413/sys/src/9/pc/vgamach64xx.c:64,692000/0504/sys/src/9/pc/vgamach64xx.c:64,71 (short | long)
1998/0507    
	if(scr->io) 
		return; 
1998/0508    
	if(p = mach64xxpci()){ 
2000/0504    
		scr->id = p->did; 
 
1998/0508    
		/* 
		 * The CT doesn't always have the I/O base address 
		 * in the PCI base registers. There is a way to find 
2000/0413/sys/src/9/pc/vgamach64xx.c:181,1882000/0504/sys/src/9/pc/vgamach64xx.c:183,206
1999/1005    
	ClrCmpMask, 
	DpChainMask, 
	SrcOffPitch,	 
2000/0504    
	LcdIndex, 
	LcdData, 
1998/0507    
}; 
 
2000/0504    
enum { 
	LCD_ConfigPanel = 0, 
	LCD_GenCtrl, 
	LCD_DstnCntl, 
	LCD_HfbPitchAddr, 
	LCD_HorzStretch, 
	LCD_VertStretch, 
	LCD_ExtVertStretch, 
	LCD_LtGio, 
	LCD_PowerMngmnt, 
	LCD_ZvgPio, 
	Nlcd, 
}; 
 
1998/0508    
static uchar mmoffset[] = { 
1999/1005    
	[CrtcOffPitch]	0x05, 
1998/0508    
	[CurClr0]	0x18, 
2000/0413/sys/src/9/pc/vgamach64xx.c:191,1962000/0504/sys/src/9/pc/vgamach64xx.c:209,216
1998/0511    
	[CurHVposn]	0x1B, 
	[CurHVoff]	0x1C, 
1999/1005    
	[BusCntl]		0x28, 
2000/0504    
	[LcdIndex]	0x29, 
	[LcdData]	0x2A, 
1998/0508    
	[GenTestCntl]	0x34, 
1999/1005    
	[DstOffPitch]	0x40, 
	[DstYX]		0x43, 
2000/0413/sys/src/9/pc/vgamach64xx.c:254,2602000/0504/sys/src/9/pc/vgamach64xx.c:274,300
1998/0508    
		outl((mmoffset[r]<<2)+scr->io, l); 
1998/0507    
} 
 
2000/0504    
static ulong 
lcdr32(VGAscr *scr, ulong r) 
{ 
	ulong or; 
 
	or = ior32(scr, LcdIndex); 
	iow32(scr, LcdIndex, (or&~0x0F) | (r&0x0F)); 
	return ior32(scr, LcdData); 
} 
 
1998/0507    
static void 
2000/0504    
lcdw32(VGAscr *scr, ulong r, ulong v) 
{ 
	ulong or; 
 
	or = ior32(scr, LcdIndex); 
	iow32(scr, LcdIndex, (or&~0x0F) | (r&0x0F)); 
	iow32(scr, LcdData, v); 
} 
 
static void 
1998/0507    
mach64xxcurdisable(VGAscr* scr) 
{ 
	ulong r; 
2000/0413/sys/src/9/pc/vgamach64xx.c:660,6652000/0504/sys/src/9/pc/vgamach64xx.c:700,706
1999/1005    
 
2000/0330    
/* 
 * This should work, but doesn't. 
2000/0504    
 * It messes up the screen timings for some reason. 
2000/0330    
 */ 
1999/1005    
static void 
2000/0330    
mach64blank(VGAscr *scr, int blank) 
2000/0413/sys/src/9/pc/vgamach64xx.c:672,6782000/0504/sys/src/9/pc/vgamach64xx.c:713,750
2000/0330    
	iow32(scr, CrtcGenCtl, ctl); 
} 
 
2000/0504    
/* 
 * We squirrel away whether the LCD and/or CRT were 
 * on when we were called to blank the screen, and 
 * restore the old state.  If we are called to blank the 
 * screen when it is already blank, we don't update the state. 
 * Such a call sequence should not happen, though. 
 * 
 * We could try forcing the chip into power management 
 * mode instead, but I'm not sure how that would interact 
 * with screen updates going on while the screen is blanked. 
 */ 
2000/0330    
static void 
2000/0504    
mach64lcdblank(VGAscr *scr, int blank) 
{ 
	static int crtlcd; 
	ulong x; 
 
	if(blank) { 
		x = lcdr32(scr, LCD_GenCtrl); 
		if(x & 3) { 
			crtlcd = x & 3; 
			lcdw32(scr, LCD_GenCtrl,  x&~3); 
		} 
	} else { 
		if(crtlcd == 0) 
			crtlcd = 2;	/* lcd only */ 
		x = lcdr32(scr, LCD_GenCtrl); 
		lcdw32(scr, LCD_GenCtrl, x | crtlcd); 
	} 
} 
 
static void 
1999/1005    
mach64xxdrawinit(VGAscr *scr) 
{ 
	if(scr->io > 0x2FF){ 
2000/0413/sys/src/9/pc/vgamach64xx.c:681,6882000/0504/sys/src/9/pc/vgamach64xx.c:753,761
1999/1005    
		scr->scroll = mach64hwscroll; 
	} 
2000/0330    
/*	scr->blank = mach64blank; */ 
2000/0504    
	if(scr->id == ('L'<<8)|'P')	/* Rage LT PRO */ 
		scr->blank = mach64lcdblank; 
1999/1005    
} 
                 
 
1998/0507    
VGAdev vgamach64xxdev = { 
	"mach64xx", 
2000/0504/sys/src/9/pc/vgamach64xx.c:25,302000/0606/sys/src/9/pc/vgamach64xx.c:25,32 (short | long)
1998/0803    
	('G'<<8)|'Q', 
1998/0507    
	('G'<<8)|'T', 
	('G'<<8)|'U', 
2000/0606    
	('G'<<8)|'V', 
	('G'<<8)|'Z', 
1998/0507    
	('V'<<8)|'T', 
	('V'<<8)|'U', 
1999/1102    
	('L'<<8)|'I', 
2000/0606/sys/src/9/pc/vgamach64xx.c:85,912000/0611/sys/src/9/pc/vgamach64xx.c:85,91 (short | long)
1998/0507    
mach64xxlinear(VGAscr* scr, int* size, int* align) 
{ 
1999/1005    
	ulong aperture, osize, oaperture; 
1998/0507    
	int oapsize, wasupamem; 
2000/0611    
	int i, oapsize, wasupamem; 
1998/0507    
	Pcidev *p; 
1999/1005    
	Physseg seg; 
1998/0507    
 
2000/0606/sys/src/9/pc/vgamach64xx.c:93,1082000/0611/sys/src/9/pc/vgamach64xx.c:93,118
1998/0507    
	oaperture = scr->aperture; 
	oapsize = scr->apsize; 
	wasupamem = scr->isupamem; 
	if(wasupamem) 
		upafree(oaperture, oapsize); 
	scr->isupamem = 0; 
 
	if(p = mach64xxpci()){ 
		aperture = p->mem[0].bar & ~0x0F; 
		*size = p->mem[0].size; 
2000/0611    
		for(i=0; i<nelem(p->mem); i++){ 
			if(p->mem[i].size >= *size 
			&& ((p->mem[i].bar & ~0x0F) & (*align-1)) == 0) 
				break; 
		} 
		if(i >= nelem(p->mem)){ 
			print("vgamach64xx: aperture not found\n"); 
			return 0; 
		} 
		aperture = p->mem[i].bar & ~0x0F; 
		*size = p->mem[i].size; 
1998/0507    
	} 
	else 
		aperture = 0; 
2000/0611    
 
	if(wasupamem) 
		upafree(oaperture, oapsize); 
	scr->isupamem = 0; 
1998/0507    
 
	aperture = upamalloc(aperture, *size, *align); 
	if(aperture == 0){ 
2000/0611/sys/src/9/pc/vgamach64xx.c:122,1282000/0613/sys/src/9/pc/vgamach64xx.c:122,128 (short | long)
1998/0507    
	else 
		scr->isupamem = 1; 
 
1999/1005    
	scr->mmio = (ulong*)(aperture+osize-0x400); 
2000/0613    
	scr->mmio = KADDR(aperture+osize-0x400); 
1999/1005    
	if(oaperture) 
		print("warning (BUG): redefinition of aperture does not change mach64mmio segment\n"); 
	memset(&seg, 0, sizeof(seg)); 
2000/0613/sys/src/9/pc/vgamach64xx.c:13,192000/0614/sys/src/9/pc/vgamach64xx.c:13,19 (short | long)
1998/0507    
#include "screen.h" 
 
/* 
1999/1005    
 * ATI Mach64(CT|ET|G*|VT|VU|LP). 
2000/0614    
 * ATI Mach64(CT|ET|G*|VT|VU|L*). 
1998/0507    
 */ 
static ushort mach64xxdid[] = { 
	('C'<<8)|'T', 
2000/0613/sys/src/9/pc/vgamach64xx.c:29,342000/0614/sys/src/9/pc/vgamach64xx.c:29,35
2000/0606    
	('G'<<8)|'Z', 
1998/0507    
	('V'<<8)|'T', 
	('V'<<8)|'U', 
2000/0614    
	('L'<<8)|'B', 
1999/1102    
	('L'<<8)|'I', 
2000/0413    
	('L'<<8)|'M', 
1999/1005    
	('L'<<8)|'P', 
2000/0613/sys/src/9/pc/vgamach64xx.c:765,7722000/0614/sys/src/9/pc/vgamach64xx.c:766,781
1999/1005    
		scr->scroll = mach64hwscroll; 
	} 
2000/0330    
/*	scr->blank = mach64blank; */ 
2000/0504    
	if(scr->id == ('L'<<8)|'P')	/* Rage LT PRO */ 
2000/0614    
	switch(scr->id){ 
	default: 
		break; 
	case ('L'<<8)|'B':		/* 4C42: Rage 3D LTPro */ 
	case ('L'<<8)|'I':		/* 4C49: Rage 3D LTPro */ 
	case ('L'<<8)|'M':		/* 4C4D: Rage Mobility */ 
	case ('L'<<8)|'P':		/* 4C50: Rage 3D LTPro */ 
2000/0504    
		scr->blank = mach64lcdblank; 
2000/0614    
		break; 
	} 
1999/1005    
} 
 
1998/0507    
VGAdev vgamach64xxdev = { 
2000/0614/sys/src/9/pc/vgamach64xx.c:13,192000/0727/sys/src/9/pc/vgamach64xx.c:13,19 (short | long)
1998/0507    
#include "screen.h" 
 
/* 
2000/0614    
 * ATI Mach64(CT|ET|G*|VT|VU|L*). 
2000/0727    
 * ATI Mach64(CT|ET|G*|V*|L*). 
1998/0507    
 */ 
static ushort mach64xxdid[] = { 
	('C'<<8)|'T', 
2000/0614/sys/src/9/pc/vgamach64xx.c:29,342000/0727/sys/src/9/pc/vgamach64xx.c:29,35
2000/0606    
	('G'<<8)|'Z', 
1998/0507    
	('V'<<8)|'T', 
	('V'<<8)|'U', 
2000/0727    
	('V'<<8)|'V', 
2000/0614    
	('L'<<8)|'B', 
1999/1102    
	('L'<<8)|'I', 
2000/0413    
	('L'<<8)|'M', 
2000/0727/sys/src/9/pc/vgamach64xx.c:78,842000/0812/sys/src/9/pc/vgamach64xx.c:78,84 (short | long)
1998/0508    
		 */ 
		scr->io = p->mem[1].bar & ~0x03; 
1999/1005    
 
1998/0508    
		if(scr->io == 0 && p->did == ('C'<<8)|'T') 
2000/0812    
		if(scr->io == 0) 
1998/0508    
			scr->io = 0x2EC; 
	} 
1998/0507    
} 
2000/0812/sys/src/9/pc/vgamach64xx.c:21,262000/0906/sys/src/9/pc/vgamach64xx.c:21,27 (short | long)
1998/0803    
	('G'<<8)|'B', 
	('G'<<8)|'D', 
	('G'<<8)|'I', 
2000/0906    
	('G'<<8)|'M', 
1998/0507    
	('G'<<8)|'P', 
1998/0803    
	('G'<<8)|'Q', 
1998/0507    
	('G'<<8)|'T', 
2000/0812/sys/src/9/pc/vgamach64xx.c:799,8012000/0906/sys/src/9/pc/vgamach64xx.c:800,803
1999/1005    
 
	1					/* doespanning */ 
1998/0507    
}; 
2000/0906    
 
2000/0906/sys/src/9/pc/vgamach64xx.c:12,412001/0505/sys/src/9/pc/vgamach64xx.c:12,142 (short | long)
1999/0119    
#include <cursor.h> 
1998/0507    
#include "screen.h" 
 
2001/0505    
char Eunsupportedformat[] = "unsupported video format"; 
char Enotconfigured[] = "device not configured"; 
 
#define SCALE_ZERO_EXTEND           	0x0 
#define SCALE_DYNAMIC               		0x1 
#define SCALE_RED_TEMP_6500K        	0x0 
#define SCALE_RED_TEMP_9800K        	0x2 
#define SCALE_HORZ_BLEND            	0x0 
#define SCALE_HORZ_REP              		0x4 
#define SCALE_VERT_BLEND            		0x0 
#define SCALE_VERT_REP              		0x8 
#define SCALE_BANDWIDTH_NORMAL     0x0 
#define SCALE_BANDWIDTH_EXCEEDED  0x4000000 
#define SCALE_BANDWIDTH_RESET       	0x4000000 
#define SCALE_CLK_ACTIVITY          	0x0 
#define SCALE_CLK_CONTINUOUS        	0x20000000 
#define OVERLAY_DISABLE             		0x0 
#define OVERLAY_ENABLE              		0x40000000 
#define SCALE_DISABLE               		0x0 
#define SCALE_ENABLE                		0x80000000 
 
#define SCALER_FRAME_READ_MODE_FULL 	0x0 
#define SCALER_BUF_MODE_SINGLE      		0x0 
#define SCALER_BUF_MODE_DOUBLE      		0x40000 
#define SCALER_BUF_NEXT_0           		0x0 
#define SCALER_BUF_NEXT_1           		0x80000 
#define SCALER_BUF_STATUS_0         		0x0 
#define SCALER_BUF_STATUS_1         		0x100000 
 
#define OVERLAY_MIX_G_CMP           		0x0 
#define OVERLAY_MIX_ALWAYS_G        		0x100 
#define OVERLAY_MIX_ALWAYS_V        		0x200 
#define OVERLAY_MIX_NOT_G           		0x300 
#define OVERLAY_MIX_NOT_V           		0x400 
#define OVERLAY_MIX_G_XOR_V         		0x500 
#define OVERLAY_MIX_NOT_G_XOR_V     	0x600 
#define OVERLAY_MIX_V_CMP           		0x700 
#define OVERLAY_MIX_NOT_G_OR_NOT_V	0x800 
#define OVERLAY_MIX_G_OR_NOT_V      	0x900 
#define OVERLAY_MIX_NOT_G_OR_V      	0xA00 
#define OVERLAY_MIX_G_OR_V          		0xB00 
#define OVERLAY_MIX_G_AND_V         		0xC00 
#define OVERLAY_MIX_NOT_G_AND_V     	0xD00 
#define OVERLAY_MIX_G_AND_NOT_V     	0xE00 
#define OVERLAY_MIX_NOT_G_AND_NOT_V 	0xF00 
#define OVERLAY_EXCLUSIVE_NORMAL    	0x0 
#define OVERLAY_EXCLUSIVE_V_ONLY    	0x80000000 
 
#define VIDEO_IN_8BPP               			0x2 
#define VIDEO_IN_16BPP              			0x4 
#define VIDEO_IN_32BPP              			0x6 
#define VIDEO_IN_VYUY422            			0xB         		/*16 bpp */ 
#define VIDEO_IN_YVYU422            			0xC         		/* 16 bpp */ 
#define SCALE_IN_15BPP              			0x30000     	/* aRGB 1555 */ 
#define SCALE_IN_16BPP              			0x40000     	/* RGB 565 */ 
#define SCALE_IN_32BPP              			0x60000     	/* aRGB 8888 */ 
#define SCALE_IN_YUV9               			0x90000     	/* planar */ 
#define SCALE_IN_YUV12              			0xA0000     	/* planar */ 
#define SCALE_IN_VYUY422            			0xB0000     	/* 16 bpp */ 
#define SCALE_IN_YVYU422            			0xC0000     	/* 16 bpp */ 
#define HOST_YUV_APERTURE_UPPER     		0x0 
#define HOST_YUV_APERTURE_LOWER     	0x20000000 
#define HOST_MEM_MODE_Y             		0x40000000 
#define HOST_MEM_MODE_U             		0x80000000 
#define HOST_MEM_MODE_V             		0xC0000000 
#define HOST_MEM_MODE_NORMAL     		HOST_YUV_APERTURE_UPPER  
 
static Chan *ovl_chan;	/* Channel of controlling process */ 
static int ovl_width;		/* Width of input overlay buffer */ 
static int ovl_height;		/* Height of input overlay buffer */ 
static int ovl_format;	/* Overlay format */ 
static ulong ovl_fib;		/* Frame in bytes */ 
 
enum { 
	 VTGTB1S1        = 0x01,            //  Asic description for VTB1S1 and GTB1S1. 
	 VT4GTIIC        	= 0x3A,            // asic descr for VT4 and RAGE IIC 
	 GTB1U1          	= 0x19,            //  Asic description for GTB1U1. 
	 GTB1S2          	= 0x41,            //  Asic description for GTB1S2. 
	 GTB2U1          	= 0x1A, 
	 GTB2U2          	= 0x5A, 
	 GTB2U3          	= 0x9A, 
	 GTIIIC1U1       	= 0x1B,            // 3D RAGE PRO asic descrp. 
	 GTIIIC1U2       	= 0x5B,            // 3D RAGE PRO asic descrp. 
	 GTIIIC2U1       	= 0x1C,            // 3D RAGE PRO asic descrp. 
	 GTIIIC2U2       	= 0x5C,           // 3D RAGE PRO asic descrp. 
	 GTIIIC2U3       	= 0x7C,            // 3D RAGE PRO asic descrp. 
	 GTBC            	= 0x3A,            // 3D RAGE IIC asic descrp. 
	 LTPRO           	= 0x9C,            // 3D RAGE LT PRO 
}; 
 
1998/0507    
/* 
2000/0727    
 * ATI Mach64(CT|ET|G*|V*|L*). 
1998/0507    
 */ 
static ushort mach64xxdid[] = { 
	('C'<<8)|'T', 
	('E'<<8)|'T', 
1998/0803    
	('G'<<8)|'B', 
	('G'<<8)|'D', 
	('G'<<8)|'I', 
2000/0906    
	('G'<<8)|'M', 
1998/0507    
	('G'<<8)|'P', 
1998/0803    
	('G'<<8)|'Q', 
1998/0507    
	('G'<<8)|'T', 
	('G'<<8)|'U', 
2000/0606    
	('G'<<8)|'V', 
	('G'<<8)|'Z', 
1998/0507    
	('V'<<8)|'T', 
	('V'<<8)|'U', 
2000/0727    
	('V'<<8)|'V', 
2000/0614    
	('L'<<8)|'B', 
1999/1102    
	('L'<<8)|'I', 
2000/0413    
	('L'<<8)|'M', 
1999/1005    
	('L'<<8)|'P', 
1998/0507    
	0, 
2001/0505    
typedef struct { 
	ushort 	m64_id;			/* Chip ID */ 
	int 		m64_vtgt;		/* Is this a VT or GT chipset? */ 
	double	m64_ovlclock;		/* Max. overlay clock frequency */ 
	int		m64_pro;			/* Is this a PRO? */ 
} mach64types; 
 
static double mach64refclock; 
static mach64types *mach64type; 
static int mach64revb;			/* Revision B or greater? */ 
static ulong mach64overlay;		/* Overlay buffer */ 
 
static mach64types mach64s[] = { 
	('C'<<8)|'T',	0,	0.,		0,	/* 4354: CT */ 
	('E'<<8)|'T',	0,	0.,		0,	/* 4554: ET */ 
	('G'<<8)|'B',	1,	125.,		1, 	/* 4742: 264GT PRO */ 
	('G'<<8)|'D',	1,	125.,		1, 	/* 4744: 264GT PRO */ 
	('G'<<8)|'I',	1,	125.,		1, 	/* 4749: 264GT PRO */ 
	('G'<<8)|'M',	0,	135.,		0,	/* 474D: Rage XL */ 
	('G'<<8)|'P',	1,	125.,		1, 	/* 4750: 264GT PRO */ 
	('G'<<8)|'Q',	1,	125.,		1,	/* 4751: 264GT PRO */ 
	('G'<<8)|'T',	1,	80.,		0,	/* 4754: 264GT[B] */ 
	('G'<<8)|'U',	1,	100.,		0,	/* 4755: 264GT DVD */ 
	('G'<<8)|'V',	1,	100.,		0,	/* 4756: Rage2C */ 
	('G'<<8)|'Z',	1,	100.,		0,	/* 475A: Rage2C */ 
	('V'<<8)|'T',	1,	80.,		0,	/* 5654: 264VT/GT/VTB */ 
	('V'<<8)|'U',	1,	80.,		0,	/* 5655: 264VT3 */ 
	('V'<<8)|'V',	1,	100.,		0,	/* 5656: 264VT4 */ 
	('L'<<8)|'B',	0,	135.,		1,	/* 4C42: Rage LTPro AGP */ 
	('L'<<8)|'I',		0,	135.,		0,	/* 4C49: Rage LTPro AGP */ 
	('L'<<8)|'M',	0,	135.,		0,	/* 4C4D: Rage Mobility */ 
	('L'<<8)|'P',	0,	135.,		1,	/* 4C50: 264LT PRO */ 
1998/0507    
}; 
 
1999/1005    
static int hwfill(VGAscr*, Rectangle, ulong); 
2000/0906/sys/src/9/pc/vgamach64xx.c:46,602001/0505/sys/src/9/pc/vgamach64xx.c:147,162
1998/0507    
mach64xxpci(void) 
{ 
	Pcidev *p; 
	ushort *did; 
2001/0505    
	int i; 
1998/0507    
 
	if((p = pcimatch(nil, 0x1002, 0)) == nil) 
		return nil; 
	for(did = mach64xxdid; *did; did++){ 
		if(*did == p->did) 
1998/0508    
			return p; 
1998/0507    
	} 
 
2001/0505    
	for (i = 0; i != nelem(mach64s); i++) 
		if (mach64s[i].m64_id == p->did) { 
			mach64type = &mach64s[i]; 
			return p; 
		} 
1998/0508    
	return nil; 
1998/0507    
} 
 
2000/0906/sys/src/9/pc/vgamach64xx.c:70,752001/0505/sys/src/9/pc/vgamach64xx.c:172,178
1998/0507    
		return; 
1998/0508    
	if(p = mach64xxpci()){ 
2000/0504    
		scr->id = p->did; 
2001/0505    
         	// iprint("mach64xxenable: found x%.4X\n", p->did); 
2000/0504    
 
1998/0508    
		/* 
		 * The CT doesn't always have the I/O base address 
2000/0906/sys/src/9/pc/vgamach64xx.c:200,2052001/0505/sys/src/9/pc/vgamach64xx.c:303,331
1999/1005    
	SrcOffPitch,	 
2000/0504    
	LcdIndex, 
	LcdData, 
2001/0505    
	ClockCntl, 
	OverlayScaleCntl, 
	ConfigChipId, 
	Buf0Pitch, 
	ScalerBuf0Pitch, 
	CaptureConfig, 
	OverlayKeyCntl, 
	ScalerColourCntl, 
	ScalerHCoef0, 
	ScalerHCoef1, 
	ScalerHCoef2, 
	ScalerHCoef3, 
	ScalerHCoef4, 
	VideoFormat, 
	Buf0Offset, 
	ScalerBuf0Offset, 
	CrtcGenCntl, 
	OverlayScaleInc, 
	OverlayYX, 
	OverlayYXEnd, 
	ScalerHeightWidth, 
	HTotalDisp, 
	VTotalDisp, 
1998/0507    
}; 
 
2000/0504    
enum { 
2000/0906/sys/src/9/pc/vgamach64xx.c:216,2712001/0505/sys/src/9/pc/vgamach64xx.c:342,424
2000/0504    
	Nlcd, 
}; 
 
1998/0508    
static uchar mmoffset[] = { 
1999/1005    
	[CrtcOffPitch]	0x05, 
1998/0508    
	[CurClr0]	0x18, 
	[CurClr1]	0x19, 
1998/0511    
	[CurOffset]	0x1A, 
	[CurHVposn]	0x1B, 
	[CurHVoff]	0x1C, 
1999/1005    
	[BusCntl]		0x28, 
2000/0504    
	[LcdIndex]	0x29, 
	[LcdData]	0x2A, 
1998/0508    
	[GenTestCntl]	0x34, 
1999/1005    
	[DstOffPitch]	0x40, 
	[DstYX]		0x43, 
	[DstHeight]	0x45, 
2001/0505    
#define Bank1			(-0x100)		/* 1KB */ 
 
static int mmoffset[] = { 
	[HTotalDisp]		0x00, 
	[VTotalDisp]		0x02, 
	[CrtcOffPitch]		0x05, 
	[CrtcGenCntl]		0x07, 
	[CurClr0]			0x18, 
	[CurClr1]			0x19, 
	[CurOffset]		0x1A, 
	[CurHVposn]		0x1B, 
	[CurHVoff]		0x1C, 
	[ClockCntl]		0x24, 
	[BusCntl]			0x28, 
	[LcdIndex]		0x29, 
	[LcdData]			0x2A, 
	[GenTestCntl]		0x34, 
	[ConfigChipId]		0x38, 
	[DstOffPitch]		0x40, 
	[DstYX]			0x43, 
	[DstHeight]		0x45, 
1999/1005    
	[DstHeightWidth]	0x46, 
	[DstBresErr]	0x49, 
	[DstBresInc]	0x4A, 
	[DstBresDec]	0x4B, 
	[DstCntl]		0x4C, 
	[SrcOffPitch]	0x60, 
	[SrcYX]	0x63, 
	[SrcWidth1]	0x64, 
	[SrcYXstart]	0x69, 
2001/0505    
	[DstBresErr]		0x49, 
	[DstBresInc]		0x4A, 
	[DstBresDec]		0x4B, 
	[DstCntl]			0x4C, 
	[SrcOffPitch]		0x60, 
	[SrcYX]			0x63, 
	[SrcWidth1]		0x64, 
	[SrcYXstart]		0x69, 
1999/1005    
	[SrcHeight1Width1]	0x66, 
	[SrcHeight2Width2]	0x6C, 
	[SrcCntl]		0x6D, 
	[HostCntl]	0x90, 
	[PatReg0]	0xA0, 
	[PatReg1]	0xA1, 
	[PatCntl]	0xA2, 
	[ScLeft]	0xA8, 
	[ScRight]	0xA9, 
	[ScLeftRight]	0xAA, 
	[ScTop]	0xAB, 
	[ScBottom] 0xAC, 
	[ScTopBottom]	0xAD, 
	[DpBkgdClr]	0xB0, 
	[DpFrgdClr]	0xB1, 
	[DpWriteMask]	0xB2, 
	[DpChainMask]	0xB3, 
	[DpPixWidth]	0xB4, 
	[DpMix]		0xB5, 
	[DpSrc]		0xB6, 
	[ClrCmpClr]	0xC0, 
	[ClrCmpMask]	0xC1, 
	[ClrCmpCntl]	0xC2, 
	[FifoStat]		0xC4, 
	[ContextMask]	0xC8, 
	[GuiTrajCntl]	0xCC, 
	[GuiStat]		0xCE, 
2001/0505    
	[SrcCntl]			0x6D, 
	[HostCntl]			0x90, 
	[PatReg0]			0xA0, 
	[PatReg1]			0xA1, 
	[PatCntl]			0xA2, 
	[ScLeft]			0xA8, 
	[ScRight]			0xA9, 
	[ScLeftRight]		0xAA, 
	[ScTop]			0xAB, 
	[ScBottom] 		0xAC, 
	[ScTopBottom]		0xAD, 
	[DpBkgdClr]		0xB0, 
	[DpFrgdClr]		0xB1, 
	[DpWriteMask]		0xB2, 
	[DpChainMask]		0xB3, 
	[DpPixWidth]		0xB4, 
	[DpMix]			0xB5, 
	[DpSrc]			0xB6, 
	[ClrCmpClr]		0xC0, 
	[ClrCmpMask]		0xC1, 
	[ClrCmpCntl]		0xC2, 
	[FifoStat]			0xC4, 
	[ContextMask]		0xC8, 
	[GuiTrajCntl]		0xCC, 
	[GuiStat]			0xCE, 
 
	/* Bank1 */ 
	[OverlayYX]		Bank1 + 0x00, 
	[OverlayYXEnd]		Bank1 + 0x01, 
	[OverlayKeyCntl]	Bank1 + 0x06, 
	[OverlayScaleInc]	Bank1 + 0x08, 
	[OverlayScaleCntl]	Bank1 + 0x09, 
	[ScalerHeightWidth]	Bank1 + 0x0A, 
	[ScalerBuf0Offset]	Bank1 + 0x0D, 
	[ScalerBuf0Pitch]	Bank1 + 0x0F, 
	[VideoFormat]		Bank1 + 0x12, 
	[CaptureConfig]	Bank1 + 0x14, 
	[Buf0Offset]		Bank1 + 0x20, 
	[Buf0Pitch]		Bank1 + 0x23, 
	[ScalerColourCntl]	Bank1 + 0x54, 
	[ScalerHCoef0]		Bank1 + 0x55, 
	[ScalerHCoef1]		Bank1 + 0x56, 
	[ScalerHCoef2]		Bank1 + 0x57, 
	[ScalerHCoef3]		Bank1 + 0x58, 
	[ScalerHCoef4]		Bank1 + 0x59, 
1998/0508    
}; 
 
1998/0507    
static ulong 
2000/0906/sys/src/9/pc/vgamach64xx.c:545,5532001/0505/sys/src/9/pc/vgamach64xx.c:698,743
1999/1005    
} 
 
static void 
2001/0505    
init_overlayclock(VGAscr *scr) 
{ 
	uchar *cc, save, pll_ref_div, pll_vclk_cntl, vclk_post_div,  
			vclk_fb_div, ecp_div; 
	int i; 
	double dotclock; 
 
	/* Taken from GLX */ 
	/* Get monitor dotclock, check for Overlay Scaler clock limit */ 
 	cc = (uchar *)&scr->mmio[mmoffset[ClockCntl]]; 
  	save = cc[1]; i = cc[0] & 3; 
  	cc[1] = 2<<2; pll_ref_div = cc[2]; 
  	cc[1] = 5<<2; pll_vclk_cntl = cc[2]; 
  	cc[1] = 6<<2; vclk_post_div = (cc[2]>>(i+i)) & 3; 
  	cc[1] = (7+i)<<2; vclk_fb_div = cc[2]; 
 
  	dotclock = 2.0 * mach64refclock * vclk_fb_div /  
			(pll_ref_div * (1 << vclk_post_div)); 
	/* ecp_div: 0=dotclock, 1=dotclock/2, 2=dotclock/4 */ 
  	ecp_div = dotclock / mach64type->m64_ovlclock; 
  	if (ecp_div>2) ecp_div = 2; 
 
  	/* Force a scaler clock factor of 1 if refclock * 
   	  * is unknown (VCLK_SRC not PLLVCLK)  */ 
  	if ((pll_vclk_cntl & 0x03) != 0x03) dotclock = ecp_div = 0; 
  	if ((pll_vclk_cntl & 0x30) != ecp_div<<4) { 
    		cc[1] = (5<<2)|2; 
    		cc[2] = (pll_vclk_cntl&0xCF) | (ecp_div<<4); 
	} 
 
  	/* Restore PLL Register Index */ 
  	cc[1] = save; 
} 
 
static void 
1999/1005    
initengine(VGAscr *scr) 
{ 
	ulong pitch; 
2001/0505    
	uchar *bios; 
	ushort table; 
1999/1005    
 
	pitch = Dx(scr->gscreen->r)/8; 
	if(scr->gscreen->depth == 24) 
2000/0906/sys/src/9/pc/vgamach64xx.c:607,6132001/0505/sys/src/9/pc/vgamach64xx.c:797,848
1999/1005    
		break; 
	} 
 
2001/0505    
	/* Get the base freq from the BIOS */ 
	bios  = KADDR(0xC000); 
	table = *(ushort *)(bios + 0x48); 
	table = *(ushort *)(bios + table + 0x10); 
	switch (*(ushort *)(bios + table + 0x08)) { 
      	case 2700:  
		mach64refclock = 27.0;  
		break; 
      	case 2863:  
      	case 2864:  
		mach64refclock = 28.63636;  
		break; 
      	case 2950:  
		mach64refclock = 29.498928713;  
		break; 
    	case 1432:  
	default: 
		mach64refclock = 14.31818;  
		break ;	 
	} 
	 
	/* Figure out which revision this chip is */ 
	switch ((scr->mmio[mmoffset[ConfigChipId]] >> 24) & 0xFF) { 
	case VTGTB1S1: 
	case GTB1U1: 
	case GTB1S2: 
	case GTB2U1: 
	case GTB2U2: 
	case GTB2U3: 
	case GTBC: 
	case GTIIIC1U1: 
	case GTIIIC1U2: 
	case GTIIIC2U1: 
	case GTIIIC2U2:  
	case GTIIIC2U3:  
	case LTPRO: 
			mach64revb = 1; 
			break; 
	default:  
			mach64revb = 0; 
			break; 
	} 
 
	init_overlayclock(scr); 
1999/1005    
	waitforidle(scr); 
2001/0505    
	 
1999/1005    
} 
 
static int 
2000/0906/sys/src/9/pc/vgamach64xx.c:761,7672001/0505/sys/src/9/pc/vgamach64xx.c:996,1002
2000/0504    
 
static void 
1999/1005    
mach64xxdrawinit(VGAscr *scr) 
{ 
2001/0505    
{  
1999/1005    
	if(scr->io > 0x2FF){ 
		initengine(scr); 
		scr->fill = mach64hwfill; 
2000/0906/sys/src/9/pc/vgamach64xx.c:780,7932001/0505/sys/src/9/pc/vgamach64xx.c:1015,1230
2000/0614    
	} 
1999/1005    
} 
 
2001/0505    
static void 
ovl_configure(VGAscr *scr, Chan *c, int nfields, char **field) 
{ 
	int w, h; 
	char *format; 
 
	if (nfields != 4) error(Ebadarg); 
 
	w = (int)strtol(field[1], nil, 0); 
	h = (int)strtol(field[2], nil, 0); 
	format = field[3]; 
 
	if (c != ovl_chan) error(Einuse); 
	if (strcmp(format, "YUYV")) 
		error(Eunsupportedformat); 
	 
	ovl_width  = w; 
	ovl_height = h; 
	ovl_fib       = w * h * sizeof(ushort); 
 
	waitforidle(scr); 
	scr->mmio[mmoffset[BusCntl]] |= 0x08000000;	/* Enable regblock 1 */ 
	scr->mmio[mmoffset[OverlayScaleCntl]] =  
		SCALE_ZERO_EXTEND|SCALE_RED_TEMP_6500K| 
		SCALE_HORZ_BLEND|SCALE_VERT_BLEND; 
	scr->mmio[mmoffset[!mach64revb? Buf0Pitch: ScalerBuf0Pitch]] = w; 
	scr->mmio[mmoffset[CaptureConfig]] =  
		SCALER_FRAME_READ_MODE_FULL| 
		SCALER_BUF_MODE_SINGLE| 
		SCALER_BUF_NEXT_0; 
	scr->mmio[mmoffset[OverlayKeyCntl]] = !mach64revb? 
		OVERLAY_MIX_ALWAYS_V|(OVERLAY_EXCLUSIVE_NORMAL << 28):  
		0x011; 
 
	if (mach64type->m64_pro) { 
		waitforfifo(scr, 6); 
 
		/* set the scaler co-efficient registers */ 
		scr->mmio[mmoffset[ScalerColourCntl]] =  
			(0x00) | (0x10 << 8) | (0x10 << 16); 
		scr->mmio[mmoffset[ScalerHCoef0]] =  
			(0x00) | (0x20 << 8); 
		scr->mmio[mmoffset[ScalerHCoef1]] =  
			(0x0D) | (0x20 << 8) | (0x06 << 16) | (0x0D << 24); 
		scr->mmio[mmoffset[ScalerHCoef2]] =  
			(0x0D) | (0x1C << 8) | (0x0A << 16) | (0x0D << 24); 
		scr->mmio[mmoffset[ScalerHCoef3]] =  
			(0x0C) | (0x1A << 8) | (0x0E << 16) | (0x0C << 24); 
		scr->mmio[mmoffset[ScalerHCoef4]] =  
			(0x0C) | (0x14 << 8) | (0x14 << 16) | (0x0C << 24); 
	} 
	 
	waitforfifo(scr, 3); 
	scr->mmio[mmoffset[VideoFormat]] = SCALE_IN_YVYU422 | 
		(!mach64revb? 0xC: 0); 
 
	if (mach64overlay == 0) 
		mach64overlay = scr->storage + 64 * 64 * sizeof(uchar); 
	scr->mmio[mmoffset[!mach64revb? Buf0Offset: ScalerBuf0Offset]] =  
		mach64overlay; 
} 
 
static void 
ovl_enable(VGAscr *scr, Chan *c, int nfields, char **field) 
{ 
	int x, y, w, h; 
	long h_inc, v_inc; 
 
	if (nfields != 5) error(Ebadarg); 
 
	x = (int)strtol(field[1], nil, 0); 
	y = (int)strtol(field[2], nil, 0); 
	w = (int)strtol(field[3], nil, 0); 
	h = (int)strtol(field[4], nil, 0); 
 
	if (x < 0 || x + w > physgscreenr.max.x || 
	     y < 0 || y + h > physgscreenr.max.y) 
		error(Ebadarg); 
 
	if (c != ovl_chan) error(Einuse); 
	if (scr->mmio[mmoffset[CrtcGenCntl]] & 1) {	/* double scan enable */ 
		y *= 2; 
		h *= 2; 
	} 
 
	waitforfifo(scr, 2); 
	scr->mmio[mmoffset[OverlayYX]] =  
			((x & 0xFFFF) << 16) | (y & 0xFFFF); 
	scr->mmio[mmoffset[OverlayYXEnd]] =  
			(((x + w) & 0xFFFF) << 16) | ((y + h) & 0xFFFF); 
 
	h_inc = (ovl_width << 12) / (w >> 1);  /* ??? */ 
	v_inc = (ovl_height << 12) / h; 
	waitforfifo(scr, 2); 
	scr->mmio[mmoffset[OverlayScaleInc]] =  
			((h_inc & 0xFFFF) << 16) | (v_inc & 0xFFFF); 
	scr->mmio[mmoffset[ScalerHeightWidth]] =  
			((ovl_width & 0xFFFF) << 16) | (ovl_height & 0xFFFF); 
	waitforidle(scr); 
	scr->mmio[mmoffset[OverlayScaleCntl]] |=  
			(SCALE_ENABLE|OVERLAY_ENABLE); 
} 
 
static void 
ovl_status(VGAscr *scr, Chan *, int nfields, char **field) 
{ 
	if (nfields != 1) error(Ebadarg); 
 
	pprint("%s: %s %.4uX, VT/GT %s, PRO %s, ovlclock %d, rev B %s, refclock %d\n", 
		   scr->dev->name, field[0], mach64type->m64_id, 
		   mach64type->m64_vtgt? "yes": "no", 
		   mach64type->m64_pro? "yes": "no", 
		   (int)(mach64type->m64_ovlclock  * 10000.), 
		   mach64revb? "yes": "no", 
		   (int)(mach64refclock * 10000.)); 
	pprint("%s: storage @%.8luX, aperture @%8.ulX, ovl buf @%.8ulX\n", 
		   scr->dev->name, scr->storage, scr->aperture, 
		   mach64overlay); 
} 
	 
static void 
ovl_openctl(VGAscr *, Chan *c, int nfields, char **) 
{ 
	if (nfields != 1) error(Ebadarg); 
	if (ovl_chan) error(Einuse); 
	ovl_chan = c; 
} 
 
static void 
ovl_closectl(VGAscr *scr, Chan *c, int nfields, char **) 
{ 
	if (c != ovl_chan || nfields != 1) return; 
 
	waitforidle(scr); 
	scr->mmio[mmoffset[OverlayScaleCntl]] &= 
			~(SCALE_ENABLE|OVERLAY_ENABLE); 
	ovl_chan = nil; 
	ovl_width = ovl_height = ovl_fib = 0; 
} 
 
static struct { 
	char *ovl_command; 
	void	 (*ovl_f)(VGAscr *, Chan *, int, char **); 
} ovl_cmds[] = { 
	{	"openctl",		ovl_openctl	}, 
	{	"configure", 	ovl_configure,	}, 
	{	"enable",		ovl_enable,	}, 
	{	"closectl",		ovl_closectl	}, 
	{	"status",		ovl_status		}, 
}; 
 
static void 
mach64xxovlctl(VGAscr *scr, Chan *c, void *a, int) 
{ 
#define MAXARGS	10 
	char *field[MAXARGS]; 
	int nfields, i; 
 
	if (!mach64type->m64_vtgt) error(Enodev); 
 
	nfields = getfields(a, field, nelem(field), 1, "\t\n\r "); 
	if (nfields < 1) error(Ebadarg); 
 
	for (i = 0; i != nelem(ovl_cmds); i++) 
		if (!strcmp(field[0], ovl_cmds[i].ovl_command)) 
			break; 
 
	if (i == nelem(ovl_cmds)) 
		error(Ebadarg); 
 
	ovl_cmds[i].ovl_f(scr, c, nfields, field); 
} 
 
static int 
mach64xxovlwrite(VGAscr *scr, void *a, int len, vlong offs) 
{ 
	uchar *src; 
	int _len; 
 
	if (ovl_chan == nil) return len;	/* Acts as a /dev/null */ 
	 
	/* Calculate the destination address */ 
	_len = len; 
	src   = (uchar *)a; 
	while (len > 0) { 
		ulong _offs; 
		int nb; 
 
		_offs = (ulong)(offs % ovl_fib); 
		nb     = (_offs + len > ovl_fib)? ovl_fib - _offs: len; 
		memmove((uchar *)KADDR(scr->aperture + mach64overlay + _offs),  
				  src, nb); 
		offs += nb; 
		src  += nb; 
		len  -= nb; 
	} 
	return _len; 
} 
 
1998/0507    
VGAdev vgamach64xxdev = { 
	"mach64xx", 
 
	mach64xxenable,			/* enable */ 
2001/0505    
	mach64xxenable,	/* enable */ 
1998/0507    
	0,				/* disable */ 
	0,				/* page */ 
	mach64xxlinear,			/* linear */ 
2001/0505    
	mach64xxlinear,	/* linear */ 
1999/1005    
	mach64xxdrawinit,	/* drawinit */ 
2001/0505    
	0, 
	mach64xxovlctl,	/* overlay control */ 
	mach64xxovlwrite,	/* write the overlay */ 
1998/0507    
}; 
 
VGAcur vgamach64xxcur = { 
2001/0505/sys/src/9/pc/vgamach64xx.c:510,5172001/0518/sys/src/9/pc/vgamach64xx.c:510,518 (short | long)
1998/0507    
		for(i = 0; i < 16; i++){ 
			if(s & (1<<(15-i))) 
				m |= 0x01<<(2*i); 
			else if(c & (1<<(15-i))) 
				; 
2001/0518    
			else if(c & (1<<(15-i))){ 
				/* noting to do */ 
			} 
1998/0507    
			else 
				m |= 0x02<<(2*i); 
		} 
2001/0518/sys/src/9/pc/vgamach64xx.c:12,1422001/0527/sys/src/9/pc/vgamach64xx.c:12,41 (short | long)
1999/0119    
#include <cursor.h> 
1998/0507    
#include "screen.h" 
 
2001/0505    
char Eunsupportedformat[] = "unsupported video format"; 
char Enotconfigured[] = "device not configured"; 
                 
#define SCALE_ZERO_EXTEND           	0x0 
#define SCALE_DYNAMIC               		0x1 
#define SCALE_RED_TEMP_6500K        	0x0 
#define SCALE_RED_TEMP_9800K        	0x2 
#define SCALE_HORZ_BLEND            	0x0 
#define SCALE_HORZ_REP              		0x4 
#define SCALE_VERT_BLEND            		0x0 
#define SCALE_VERT_REP              		0x8 
#define SCALE_BANDWIDTH_NORMAL     0x0 
#define SCALE_BANDWIDTH_EXCEEDED  0x4000000 
#define SCALE_BANDWIDTH_RESET       	0x4000000 
#define SCALE_CLK_ACTIVITY          	0x0 
#define SCALE_CLK_CONTINUOUS        	0x20000000 
#define OVERLAY_DISABLE             		0x0 
#define OVERLAY_ENABLE              		0x40000000 
#define SCALE_DISABLE               		0x0 
#define SCALE_ENABLE                		0x80000000 
                 
#define SCALER_FRAME_READ_MODE_FULL 	0x0 
#define SCALER_BUF_MODE_SINGLE      		0x0 
#define SCALER_BUF_MODE_DOUBLE      		0x40000 
#define SCALER_BUF_NEXT_0           		0x0 
#define SCALER_BUF_NEXT_1           		0x80000 
#define SCALER_BUF_STATUS_0         		0x0 
#define SCALER_BUF_STATUS_1         		0x100000 
                 
#define OVERLAY_MIX_G_CMP           		0x0 
#define OVERLAY_MIX_ALWAYS_G        		0x100 
#define OVERLAY_MIX_ALWAYS_V        		0x200 
#define OVERLAY_MIX_NOT_G           		0x300 
#define OVERLAY_MIX_NOT_V           		0x400 
#define OVERLAY_MIX_G_XOR_V         		0x500 
#define OVERLAY_MIX_NOT_G_XOR_V     	0x600 
#define OVERLAY_MIX_V_CMP           		0x700 
#define OVERLAY_MIX_NOT_G_OR_NOT_V	0x800 
#define OVERLAY_MIX_G_OR_NOT_V      	0x900 
#define OVERLAY_MIX_NOT_G_OR_V      	0xA00 
#define OVERLAY_MIX_G_OR_V          		0xB00 
#define OVERLAY_MIX_G_AND_V         		0xC00 
#define OVERLAY_MIX_NOT_G_AND_V     	0xD00 
#define OVERLAY_MIX_G_AND_NOT_V     	0xE00 
#define OVERLAY_MIX_NOT_G_AND_NOT_V 	0xF00 
#define OVERLAY_EXCLUSIVE_NORMAL    	0x0 
#define OVERLAY_EXCLUSIVE_V_ONLY    	0x80000000 
                 
#define VIDEO_IN_8BPP               			0x2 
#define VIDEO_IN_16BPP              			0x4 
#define VIDEO_IN_32BPP              			0x6 
#define VIDEO_IN_VYUY422            			0xB         		/*16 bpp */ 
#define VIDEO_IN_YVYU422            			0xC         		/* 16 bpp */ 
#define SCALE_IN_15BPP              			0x30000     	/* aRGB 1555 */ 
#define SCALE_IN_16BPP              			0x40000     	/* RGB 565 */ 
#define SCALE_IN_32BPP              			0x60000     	/* aRGB 8888 */ 
#define SCALE_IN_YUV9               			0x90000     	/* planar */ 
#define SCALE_IN_YUV12              			0xA0000     	/* planar */ 
#define SCALE_IN_VYUY422            			0xB0000     	/* 16 bpp */ 
#define SCALE_IN_YVYU422            			0xC0000     	/* 16 bpp */ 
#define HOST_YUV_APERTURE_UPPER     		0x0 
#define HOST_YUV_APERTURE_LOWER     	0x20000000 
#define HOST_MEM_MODE_Y             		0x40000000 
#define HOST_MEM_MODE_U             		0x80000000 
#define HOST_MEM_MODE_V             		0xC0000000 
#define HOST_MEM_MODE_NORMAL     		HOST_YUV_APERTURE_UPPER  
                 
static Chan *ovl_chan;	/* Channel of controlling process */ 
static int ovl_width;		/* Width of input overlay buffer */ 
static int ovl_height;		/* Height of input overlay buffer */ 
static int ovl_format;	/* Overlay format */ 
static ulong ovl_fib;		/* Frame in bytes */ 
                 
enum { 
	 VTGTB1S1        = 0x01,            //  Asic description for VTB1S1 and GTB1S1. 
	 VT4GTIIC        	= 0x3A,            // asic descr for VT4 and RAGE IIC 
	 GTB1U1          	= 0x19,            //  Asic description for GTB1U1. 
	 GTB1S2          	= 0x41,            //  Asic description for GTB1S2. 
	 GTB2U1          	= 0x1A, 
	 GTB2U2          	= 0x5A, 
	 GTB2U3          	= 0x9A, 
	 GTIIIC1U1       	= 0x1B,            // 3D RAGE PRO asic descrp. 
	 GTIIIC1U2       	= 0x5B,            // 3D RAGE PRO asic descrp. 
	 GTIIIC2U1       	= 0x1C,            // 3D RAGE PRO asic descrp. 
	 GTIIIC2U2       	= 0x5C,           // 3D RAGE PRO asic descrp. 
	 GTIIIC2U3       	= 0x7C,            // 3D RAGE PRO asic descrp. 
	 GTBC            	= 0x3A,            // 3D RAGE IIC asic descrp. 
	 LTPRO           	= 0x9C,            // 3D RAGE LT PRO 
}; 
                 
1998/0507    
/* 
2000/0727    
 * ATI Mach64(CT|ET|G*|V*|L*). 
1998/0507    
 */ 
2001/0505    
typedef struct { 
	ushort 	m64_id;			/* Chip ID */ 
	int 		m64_vtgt;		/* Is this a VT or GT chipset? */ 
	double	m64_ovlclock;		/* Max. overlay clock frequency */ 
	int		m64_pro;			/* Is this a PRO? */ 
} mach64types; 
                 
static double mach64refclock; 
static mach64types *mach64type; 
static int mach64revb;			/* Revision B or greater? */ 
static ulong mach64overlay;		/* Overlay buffer */ 
                 
static mach64types mach64s[] = { 
	('C'<<8)|'T',	0,	0.,		0,	/* 4354: CT */ 
	('E'<<8)|'T',	0,	0.,		0,	/* 4554: ET */ 
	('G'<<8)|'B',	1,	125.,		1, 	/* 4742: 264GT PRO */ 
	('G'<<8)|'D',	1,	125.,		1, 	/* 4744: 264GT PRO */ 
	('G'<<8)|'I',	1,	125.,		1, 	/* 4749: 264GT PRO */ 
	('G'<<8)|'M',	0,	135.,		0,	/* 474D: Rage XL */ 
	('G'<<8)|'P',	1,	125.,		1, 	/* 4750: 264GT PRO */ 
	('G'<<8)|'Q',	1,	125.,		1,	/* 4751: 264GT PRO */ 
	('G'<<8)|'T',	1,	80.,		0,	/* 4754: 264GT[B] */ 
	('G'<<8)|'U',	1,	100.,		0,	/* 4755: 264GT DVD */ 
	('G'<<8)|'V',	1,	100.,		0,	/* 4756: Rage2C */ 
	('G'<<8)|'Z',	1,	100.,		0,	/* 475A: Rage2C */ 
	('V'<<8)|'T',	1,	80.,		0,	/* 5654: 264VT/GT/VTB */ 
	('V'<<8)|'U',	1,	80.,		0,	/* 5655: 264VT3 */ 
	('V'<<8)|'V',	1,	100.,		0,	/* 5656: 264VT4 */ 
	('L'<<8)|'B',	0,	135.,		1,	/* 4C42: Rage LTPro AGP */ 
	('L'<<8)|'I',		0,	135.,		0,	/* 4C49: Rage LTPro AGP */ 
	('L'<<8)|'M',	0,	135.,		0,	/* 4C4D: Rage Mobility */ 
	('L'<<8)|'P',	0,	135.,		1,	/* 4C50: 264LT PRO */ 
2001/0527    
static ushort mach64xxdid[] = { 
	('C'<<8)|'T', 
	('E'<<8)|'T', 
	('G'<<8)|'B', 
	('G'<<8)|'D', 
	('G'<<8)|'I', 
	('G'<<8)|'M', 
	('G'<<8)|'P', 
	('G'<<8)|'Q', 
	('G'<<8)|'T', 
	('G'<<8)|'U', 
	('G'<<8)|'V', 
	('G'<<8)|'Z', 
	('V'<<8)|'T', 
	('V'<<8)|'U', 
	('V'<<8)|'V', 
	('L'<<8)|'B', 
	('L'<<8)|'I', 
	('L'<<8)|'M', 
	('L'<<8)|'P', 
	0, 
1998/0507    
}; 
 
1999/1005    
static int hwfill(VGAscr*, Rectangle, ulong); 
2001/0518/sys/src/9/pc/vgamach64xx.c:147,1622001/0527/sys/src/9/pc/vgamach64xx.c:46,60
1998/0507    
mach64xxpci(void) 
{ 
	Pcidev *p; 
2001/0505    
	int i; 
2001/0527    
	ushort *did; 
1998/0507    
 
	if((p = pcimatch(nil, 0x1002, 0)) == nil) 
		return nil; 
                 
2001/0505    
	for (i = 0; i != nelem(mach64s); i++) 
		if (mach64s[i].m64_id == p->did) { 
			mach64type = &mach64s[i]; 
2001/0527    
	for(did = mach64xxdid; *did; did++){ 
		if(*did == p->did) 
2001/0505    
			return p; 
		} 
2001/0527    
	} 
 
1998/0508    
	return nil; 
1998/0507    
} 
 
2001/0518/sys/src/9/pc/vgamach64xx.c:172,1782001/0527/sys/src/9/pc/vgamach64xx.c:70,75
1998/0507    
		return; 
1998/0508    
	if(p = mach64xxpci()){ 
2000/0504    
		scr->id = p->did; 
2001/0505    
         	// iprint("mach64xxenable: found x%.4X\n", p->did); 
2000/0504    
 
1998/0508    
		/* 
		 * The CT doesn't always have the I/O base address 
2001/0518/sys/src/9/pc/vgamach64xx.c:233,2462001/0527/sys/src/9/pc/vgamach64xx.c:130,141
1999/1005    
		print("warning (BUG): redefinition of aperture does not change mach64mmio segment\n"); 
	memset(&seg, 0, sizeof(seg)); 
	seg.attr = SG_PHYSICAL; 
	seg.name = smalloc(NAMELEN); 
	snprint(seg.name, NAMELEN, "mach64mmio"); 
2001/0527    
	kstrdup(&seg.name, "mach64mmio"); 
1999/1005    
	seg.pa = aperture+osize - BY2PG; 
	seg.size = BY2PG; 
	addphysseg(&seg); 
 
	seg.name = smalloc(NAMELEN); 
	snprint(seg.name, NAMELEN, "mach64screen"); 
2001/0527    
	kstrdup(&seg.name, "mach64screen"); 
1999/1005    
	seg.pa = aperture; 
	seg.size = osize; 
	addphysseg(&seg); 
2001/0518/sys/src/9/pc/vgamach64xx.c:303,3312001/0527/sys/src/9/pc/vgamach64xx.c:198,203
1999/1005    
	SrcOffPitch,	 
2000/0504    
	LcdIndex, 
	LcdData, 
2001/0505    
	ClockCntl, 
	OverlayScaleCntl, 
	ConfigChipId, 
	Buf0Pitch, 
	ScalerBuf0Pitch, 
	CaptureConfig, 
	OverlayKeyCntl, 
	ScalerColourCntl, 
	ScalerHCoef0, 
	ScalerHCoef1, 
	ScalerHCoef2, 
	ScalerHCoef3, 
	ScalerHCoef4, 
	VideoFormat, 
	Buf0Offset, 
	ScalerBuf0Offset, 
	CrtcGenCntl, 
	OverlayScaleInc, 
	OverlayYX, 
	OverlayYXEnd, 
	ScalerHeightWidth, 
	HTotalDisp, 
	VTotalDisp, 
1998/0507    
}; 
 
2000/0504    
enum { 
2001/0518/sys/src/9/pc/vgamach64xx.c:342,4242001/0527/sys/src/9/pc/vgamach64xx.c:214,269
2000/0504    
	Nlcd, 
}; 
 
2001/0505    
#define Bank1			(-0x100)		/* 1KB */ 
                 
static int mmoffset[] = { 
	[HTotalDisp]		0x00, 
	[VTotalDisp]		0x02, 
	[CrtcOffPitch]		0x05, 
	[CrtcGenCntl]		0x07, 
	[CurClr0]			0x18, 
	[CurClr1]			0x19, 
	[CurOffset]		0x1A, 
	[CurHVposn]		0x1B, 
	[CurHVoff]		0x1C, 
	[ClockCntl]		0x24, 
	[BusCntl]			0x28, 
	[LcdIndex]		0x29, 
	[LcdData]			0x2A, 
	[GenTestCntl]		0x34, 
	[ConfigChipId]		0x38, 
	[DstOffPitch]		0x40, 
	[DstYX]			0x43, 
	[DstHeight]		0x45, 
2001/0527    
static uchar mmoffset[] = { 
	[CrtcOffPitch]	0x05, 
	[CurClr0]	0x18, 
	[CurClr1]	0x19, 
	[CurOffset]	0x1A, 
	[CurHVposn]	0x1B, 
	[CurHVoff]	0x1C, 
	[BusCntl]		0x28, 
	[LcdIndex]	0x29, 
	[LcdData]	0x2A, 
	[GenTestCntl]	0x34, 
	[DstOffPitch]	0x40, 
	[DstYX]		0x43, 
	[DstHeight]	0x45, 
1999/1005    
	[DstHeightWidth]	0x46, 
2001/0505    
	[DstBresErr]		0x49, 
	[DstBresInc]		0x4A, 
	[DstBresDec]		0x4B, 
	[DstCntl]			0x4C, 
	[SrcOffPitch]		0x60, 
	[SrcYX]			0x63, 
	[SrcWidth1]		0x64, 
	[SrcYXstart]		0x69, 
2001/0527    
	[DstBresErr]	0x49, 
	[DstBresInc]	0x4A, 
	[DstBresDec]	0x4B, 
	[DstCntl]		0x4C, 
	[SrcOffPitch]	0x60, 
	[SrcYX]	0x63, 
	[SrcWidth1]	0x64, 
	[SrcYXstart]	0x69, 
1999/1005    
	[SrcHeight1Width1]	0x66, 
	[SrcHeight2Width2]	0x6C, 
2001/0505    
	[SrcCntl]			0x6D, 
	[HostCntl]			0x90, 
	[PatReg0]			0xA0, 
	[PatReg1]			0xA1, 
	[PatCntl]			0xA2, 
	[ScLeft]			0xA8, 
	[ScRight]			0xA9, 
	[ScLeftRight]		0xAA, 
	[ScTop]			0xAB, 
	[ScBottom] 		0xAC, 
	[ScTopBottom]		0xAD, 
	[DpBkgdClr]		0xB0, 
	[DpFrgdClr]		0xB1, 
	[DpWriteMask]		0xB2, 
	[DpChainMask]		0xB3, 
	[DpPixWidth]		0xB4, 
	[DpMix]			0xB5, 
	[DpSrc]			0xB6, 
	[ClrCmpClr]		0xC0, 
	[ClrCmpMask]		0xC1, 
	[ClrCmpCntl]		0xC2, 
	[FifoStat]			0xC4, 
	[ContextMask]		0xC8, 
	[GuiTrajCntl]		0xCC, 
	[GuiStat]			0xCE, 
                 
	/* Bank1 */ 
	[OverlayYX]		Bank1 + 0x00, 
	[OverlayYXEnd]		Bank1 + 0x01, 
	[OverlayKeyCntl]	Bank1 + 0x06, 
	[OverlayScaleInc]	Bank1 + 0x08, 
	[OverlayScaleCntl]	Bank1 + 0x09, 
	[ScalerHeightWidth]	Bank1 + 0x0A, 
	[ScalerBuf0Offset]	Bank1 + 0x0D, 
	[ScalerBuf0Pitch]	Bank1 + 0x0F, 
	[VideoFormat]		Bank1 + 0x12, 
	[CaptureConfig]	Bank1 + 0x14, 
	[Buf0Offset]		Bank1 + 0x20, 
	[Buf0Pitch]		Bank1 + 0x23, 
	[ScalerColourCntl]	Bank1 + 0x54, 
	[ScalerHCoef0]		Bank1 + 0x55, 
	[ScalerHCoef1]		Bank1 + 0x56, 
	[ScalerHCoef2]		Bank1 + 0x57, 
	[ScalerHCoef3]		Bank1 + 0x58, 
	[ScalerHCoef4]		Bank1 + 0x59, 
2001/0527    
	[SrcCntl]		0x6D, 
	[HostCntl]	0x90, 
	[PatReg0]	0xA0, 
	[PatReg1]	0xA1, 
	[PatCntl]	0xA2, 
	[ScLeft]	0xA8, 
	[ScRight]	0xA9, 
	[ScLeftRight]	0xAA, 
	[ScTop]	0xAB, 
	[ScBottom] 0xAC, 
	[ScTopBottom]	0xAD, 
	[DpBkgdClr]	0xB0, 
	[DpFrgdClr]	0xB1, 
	[DpWriteMask]	0xB2, 
	[DpChainMask]	0xB3, 
	[DpPixWidth]	0xB4, 
	[DpMix]		0xB5, 
	[DpSrc]		0xB6, 
	[ClrCmpClr]	0xC0, 
	[ClrCmpMask]	0xC1, 
	[ClrCmpCntl]	0xC2, 
	[FifoStat]		0xC4, 
	[ContextMask]	0xC8, 
	[GuiTrajCntl]	0xCC, 
	[GuiStat]		0xCE, 
1998/0508    
}; 
 
1998/0507    
static ulong 
2001/0518/sys/src/9/pc/vgamach64xx.c:511,5172001/0527/sys/src/9/pc/vgamach64xx.c:356,362
1998/0507    
			if(s & (1<<(15-i))) 
				m |= 0x01<<(2*i); 
2001/0518    
			else if(c & (1<<(15-i))){ 
				/* noting to do */ 
2001/0527    
				/* nothing to do */ 
2001/0518    
			} 
1998/0507    
			else 
				m |= 0x02<<(2*i); 
2001/0518/sys/src/9/pc/vgamach64xx.c:699,7442001/0527/sys/src/9/pc/vgamach64xx.c:544,552
1999/1005    
} 
 
static void 
2001/0505    
init_overlayclock(VGAscr *scr) 
{ 
	uchar *cc, save, pll_ref_div, pll_vclk_cntl, vclk_post_div,  
			vclk_fb_div, ecp_div; 
	int i; 
	double dotclock; 
                 
	/* Taken from GLX */ 
	/* Get monitor dotclock, check for Overlay Scaler clock limit */ 
 	cc = (uchar *)&scr->mmio[mmoffset[ClockCntl]]; 
  	save = cc[1]; i = cc[0] & 3; 
  	cc[1] = 2<<2; pll_ref_div = cc[2]; 
  	cc[1] = 5<<2; pll_vclk_cntl = cc[2]; 
  	cc[1] = 6<<2; vclk_post_div = (cc[2]>>(i+i)) & 3; 
  	cc[1] = (7+i)<<2; vclk_fb_div = cc[2]; 
                 
  	dotclock = 2.0 * mach64refclock * vclk_fb_div /  
			(pll_ref_div * (1 << vclk_post_div)); 
	/* ecp_div: 0=dotclock, 1=dotclock/2, 2=dotclock/4 */ 
  	ecp_div = dotclock / mach64type->m64_ovlclock; 
  	if (ecp_div>2) ecp_div = 2; 
                 
  	/* Force a scaler clock factor of 1 if refclock * 
   	  * is unknown (VCLK_SRC not PLLVCLK)  */ 
  	if ((pll_vclk_cntl & 0x03) != 0x03) dotclock = ecp_div = 0; 
  	if ((pll_vclk_cntl & 0x30) != ecp_div<<4) { 
    		cc[1] = (5<<2)|2; 
    		cc[2] = (pll_vclk_cntl&0xCF) | (ecp_div<<4); 
	} 
                 
  	/* Restore PLL Register Index */ 
  	cc[1] = save; 
} 
                 
static void 
1999/1005    
initengine(VGAscr *scr) 
{ 
	ulong pitch; 
2001/0505    
	uchar *bios; 
	ushort table; 
1999/1005    
 
	pitch = Dx(scr->gscreen->r)/8; 
	if(scr->gscreen->depth == 24) 
2001/0518/sys/src/9/pc/vgamach64xx.c:798,8492001/0527/sys/src/9/pc/vgamach64xx.c:606,612
1999/1005    
		break; 
	} 
 
2001/0505    
	/* Get the base freq from the BIOS */ 
	bios  = KADDR(0xC000); 
	table = *(ushort *)(bios + 0x48); 
	table = *(ushort *)(bios + table + 0x10); 
	switch (*(ushort *)(bios + table + 0x08)) { 
      	case 2700:  
		mach64refclock = 27.0;  
		break; 
      	case 2863:  
      	case 2864:  
		mach64refclock = 28.63636;  
		break; 
      	case 2950:  
		mach64refclock = 29.498928713;  
		break; 
    	case 1432:  
	default: 
		mach64refclock = 14.31818;  
		break ;	 
	} 
	                 
	/* Figure out which revision this chip is */ 
	switch ((scr->mmio[mmoffset[ConfigChipId]] >> 24) & 0xFF) { 
	case VTGTB1S1: 
	case GTB1U1: 
	case GTB1S2: 
	case GTB2U1: 
	case GTB2U2: 
	case GTB2U3: 
	case GTBC: 
	case GTIIIC1U1: 
	case GTIIIC1U2: 
	case GTIIIC2U1: 
	case GTIIIC2U2:  
	case GTIIIC2U3:  
	case LTPRO: 
			mach64revb = 1; 
			break; 
	default:  
			mach64revb = 0; 
			break; 
	} 
                 
	init_overlayclock(scr); 
1999/1005    
	waitforidle(scr); 
2001/0505    
	                 
1999/1005    
} 
 
static int 
2001/0518/sys/src/9/pc/vgamach64xx.c:997,10032001/0527/sys/src/9/pc/vgamach64xx.c:760,766
2000/0504    
 
static void 
1999/1005    
mach64xxdrawinit(VGAscr *scr) 
2001/0505    
{  
2001/0527    
{ 
1999/1005    
	if(scr->io > 0x2FF){ 
		initengine(scr); 
		scr->fill = mach64hwfill; 
2001/0518/sys/src/9/pc/vgamach64xx.c:1016,12312001/0527/sys/src/9/pc/vgamach64xx.c:779,792
2000/0614    
	} 
1999/1005    
} 
 
2001/0505    
static void 
ovl_configure(VGAscr *scr, Chan *c, int nfields, char **field) 
{ 
	int w, h; 
	char *format; 
                 
	if (nfields != 4) error(Ebadarg); 
                 
	w = (int)strtol(field[1], nil, 0); 
	h = (int)strtol(field[2], nil, 0); 
	format = field[3]; 
                 
	if (c != ovl_chan) error(Einuse); 
	if (strcmp(format, "YUYV")) 
		error(Eunsupportedformat); 
	                 
	ovl_width  = w; 
	ovl_height = h; 
	ovl_fib       = w * h * sizeof(ushort); 
                 
	waitforidle(scr); 
	scr->mmio[mmoffset[BusCntl]] |= 0x08000000;	/* Enable regblock 1 */ 
	scr->mmio[mmoffset[OverlayScaleCntl]] =  
		SCALE_ZERO_EXTEND|SCALE_RED_TEMP_6500K| 
		SCALE_HORZ_BLEND|SCALE_VERT_BLEND; 
	scr->mmio[mmoffset[!mach64revb? Buf0Pitch: ScalerBuf0Pitch]] = w; 
	scr->mmio[mmoffset[CaptureConfig]] =  
		SCALER_FRAME_READ_MODE_FULL| 
		SCALER_BUF_MODE_SINGLE| 
		SCALER_BUF_NEXT_0; 
	scr->mmio[mmoffset[OverlayKeyCntl]] = !mach64revb? 
		OVERLAY_MIX_ALWAYS_V|(OVERLAY_EXCLUSIVE_NORMAL << 28):  
		0x011; 
                 
	if (mach64type->m64_pro) { 
		waitforfifo(scr, 6); 
                 
		/* set the scaler co-efficient registers */ 
		scr->mmio[mmoffset[ScalerColourCntl]] =  
			(0x00) | (0x10 << 8) | (0x10 << 16); 
		scr->mmio[mmoffset[ScalerHCoef0]] =  
			(0x00) | (0x20 << 8); 
		scr->mmio[mmoffset[ScalerHCoef1]] =  
			(0x0D) | (0x20 << 8) | (0x06 << 16) | (0x0D << 24); 
		scr->mmio[mmoffset[ScalerHCoef2]] =  
			(0x0D) | (0x1C << 8) | (0x0A << 16) | (0x0D << 24); 
		scr->mmio[mmoffset[ScalerHCoef3]] =  
			(0x0C) | (0x1A << 8) | (0x0E << 16) | (0x0C << 24); 
		scr->mmio[mmoffset[ScalerHCoef4]] =  
			(0x0C) | (0x14 << 8) | (0x14 << 16) | (0x0C << 24); 
	} 
	                 
	waitforfifo(scr, 3); 
	scr->mmio[mmoffset[VideoFormat]] = SCALE_IN_YVYU422 | 
		(!mach64revb? 0xC: 0); 
                 
	if (mach64overlay == 0) 
		mach64overlay = scr->storage + 64 * 64 * sizeof(uchar); 
	scr->mmio[mmoffset[!mach64revb? Buf0Offset: ScalerBuf0Offset]] =  
		mach64overlay; 
} 
                 
static void 
ovl_enable(VGAscr *scr, Chan *c, int nfields, char **field) 
{ 
	int x, y, w, h; 
	long h_inc, v_inc; 
                 
	if (nfields != 5) error(Ebadarg); 
                 
	x = (int)strtol(field[1], nil, 0); 
	y = (int)strtol(field[2], nil, 0); 
	w = (int)strtol(field[3], nil, 0); 
	h = (int)strtol(field[4], nil, 0); 
                 
	if (x < 0 || x + w > physgscreenr.max.x || 
	     y < 0 || y + h > physgscreenr.max.y) 
		error(Ebadarg); 
                 
	if (c != ovl_chan) error(Einuse); 
	if (scr->mmio[mmoffset[CrtcGenCntl]] & 1) {	/* double scan enable */ 
		y *= 2; 
		h *= 2; 
	} 
                 
	waitforfifo(scr, 2); 
	scr->mmio[mmoffset[OverlayYX]] =  
			((x & 0xFFFF) << 16) | (y & 0xFFFF); 
	scr->mmio[mmoffset[OverlayYXEnd]] =  
			(((x + w) & 0xFFFF) << 16) | ((y + h) & 0xFFFF); 
                 
	h_inc = (ovl_width << 12) / (w >> 1);  /* ??? */ 
	v_inc = (ovl_height << 12) / h; 
	waitforfifo(scr, 2); 
	scr->mmio[mmoffset[OverlayScaleInc]] =  
			((h_inc & 0xFFFF) << 16) | (v_inc & 0xFFFF); 
	scr->mmio[mmoffset[ScalerHeightWidth]] =  
			((ovl_width & 0xFFFF) << 16) | (ovl_height & 0xFFFF); 
	waitforidle(scr); 
	scr->mmio[mmoffset[OverlayScaleCntl]] |=  
			(SCALE_ENABLE|OVERLAY_ENABLE); 
} 
                 
static void 
ovl_status(VGAscr *scr, Chan *, int nfields, char **field) 
{ 
	if (nfields != 1) error(Ebadarg); 
                 
	pprint("%s: %s %.4uX, VT/GT %s, PRO %s, ovlclock %d, rev B %s, refclock %d\n", 
		   scr->dev->name, field[0], mach64type->m64_id, 
		   mach64type->m64_vtgt? "yes": "no", 
		   mach64type->m64_pro? "yes": "no", 
		   (int)(mach64type->m64_ovlclock  * 10000.), 
		   mach64revb? "yes": "no", 
		   (int)(mach64refclock * 10000.)); 
	pprint("%s: storage @%.8luX, aperture @%8.ulX, ovl buf @%.8ulX\n", 
		   scr->dev->name, scr->storage, scr->aperture, 
		   mach64overlay); 
} 
	                 
static void 
ovl_openctl(VGAscr *, Chan *c, int nfields, char **) 
{ 
	if (nfields != 1) error(Ebadarg); 
	if (ovl_chan) error(Einuse); 
	ovl_chan = c; 
} 
                 
static void 
ovl_closectl(VGAscr *scr, Chan *c, int nfields, char **) 
{ 
	if (c != ovl_chan || nfields != 1) return; 
                 
	waitforidle(scr); 
	scr->mmio[mmoffset[OverlayScaleCntl]] &= 
			~(SCALE_ENABLE|OVERLAY_ENABLE); 
	ovl_chan = nil; 
	ovl_width = ovl_height = ovl_fib = 0; 
} 
                 
static struct { 
	char *ovl_command; 
	void	 (*ovl_f)(VGAscr *, Chan *, int, char **); 
} ovl_cmds[] = { 
	{	"openctl",		ovl_openctl	}, 
	{	"configure", 	ovl_configure,	}, 
	{	"enable",		ovl_enable,	}, 
	{	"closectl",		ovl_closectl	}, 
	{	"status",		ovl_status		}, 
}; 
                 
static void 
mach64xxovlctl(VGAscr *scr, Chan *c, void *a, int) 
{ 
#define MAXARGS	10 
	char *field[MAXARGS]; 
	int nfields, i; 
                 
	if (!mach64type->m64_vtgt) error(Enodev); 
                 
	nfields = getfields(a, field, nelem(field), 1, "\t\n\r "); 
	if (nfields < 1) error(Ebadarg); 
                 
	for (i = 0; i != nelem(ovl_cmds); i++) 
		if (!strcmp(field[0], ovl_cmds[i].ovl_command)) 
			break; 
                 
	if (i == nelem(ovl_cmds)) 
		error(Ebadarg); 
                 
	ovl_cmds[i].ovl_f(scr, c, nfields, field); 
} 
                 
static int 
mach64xxovlwrite(VGAscr *scr, void *a, int len, vlong offs) 
{ 
	uchar *src; 
	int _len; 
                 
	if (ovl_chan == nil) return len;	/* Acts as a /dev/null */ 
	                 
	/* Calculate the destination address */ 
	_len = len; 
	src   = (uchar *)a; 
	while (len > 0) { 
		ulong _offs; 
		int nb; 
                 
		_offs = (ulong)(offs % ovl_fib); 
		nb     = (_offs + len > ovl_fib)? ovl_fib - _offs: len; 
		memmove((uchar *)KADDR(scr->aperture + mach64overlay + _offs),  
				  src, nb); 
		offs += nb; 
		src  += nb; 
		len  -= nb; 
	} 
	return _len; 
} 
                 
1998/0507    
VGAdev vgamach64xxdev = { 
	"mach64xx", 
 
2001/0505    
	mach64xxenable,	/* enable */ 
2001/0527    
	mach64xxenable,			/* enable */ 
1998/0507    
	0,				/* disable */ 
	0,				/* page */ 
2001/0505    
	mach64xxlinear,	/* linear */ 
2001/0527    
	mach64xxlinear,			/* linear */ 
1999/1005    
	mach64xxdrawinit,	/* drawinit */ 
2001/0505    
	0, 
	mach64xxovlctl,	/* overlay control */ 
	mach64xxovlwrite,	/* write the overlay */ 
1998/0507    
}; 
 
VGAcur vgamach64xxcur = { 
2001/0527/sys/src/9/pc/vgamach64xx.c:126,1322001/0704/sys/src/9/pc/vgamach64xx.c:126,132 (short | long)
1998/0507    
		scr->isupamem = 1; 
 
2000/0613    
	scr->mmio = KADDR(aperture+osize-0x400); 
1999/1005    
	if(oaperture) 
2001/0704    
	if(oaperture && oaperture != aperture) 
1999/1005    
		print("warning (BUG): redefinition of aperture does not change mach64mmio segment\n"); 
	memset(&seg, 0, sizeof(seg)); 
	seg.attr = SG_PHYSICAL; 
2001/0704/sys/src/9/pc/vgamach64xx.c:90,962001/0908/sys/src/9/pc/vgamach64xx.c:90,95 (short | long)
1999/1005    
	ulong aperture, osize, oaperture; 
2000/0611    
	int i, oapsize, wasupamem; 
1998/0507    
	Pcidev *p; 
1999/1005    
	Physseg seg; 
1998/0507    
 
1999/1005    
	osize = *size; 
1998/0507    
	oaperture = scr->aperture; 
2001/0704/sys/src/9/pc/vgamach64xx.c:128,1442001/0908/sys/src/9/pc/vgamach64xx.c:127,134
2000/0613    
	scr->mmio = KADDR(aperture+osize-0x400); 
2001/0704    
	if(oaperture && oaperture != aperture) 
1999/1005    
		print("warning (BUG): redefinition of aperture does not change mach64mmio segment\n"); 
	memset(&seg, 0, sizeof(seg)); 
	seg.attr = SG_PHYSICAL; 
2001/0527    
	kstrdup(&seg.name, "mach64mmio"); 
1999/1005    
	seg.pa = aperture+osize - BY2PG; 
	seg.size = BY2PG; 
	addphysseg(&seg); 
                 
2001/0527    
	kstrdup(&seg.name, "mach64screen"); 
1999/1005    
	seg.pa = aperture; 
	seg.size = osize; 
	addphysseg(&seg); 
2001/0908    
	addvgaseg("mach64mmio", aperture+osize-BY2PG, BY2PG); 
	addvgaseg("mach64screen", aperture, osize); 
1999/1005    
 
1998/0507    
	return aperture; 
} 
2001/0908/sys/src/9/pc/vgamach64xx.c:12,432001/1005/sys/src/9/pc/vgamach64xx.c:12,145 (short | long)
1999/0119    
#include <cursor.h> 
1998/0507    
#include "screen.h" 
 
2001/1005    
char Eunsupportedformat[] = "unsupported video format"; 
char Enotconfigured[] = "device not configured"; 
 
#define SCALE_ZERO_EXTEND           	0x0 
#define SCALE_DYNAMIC               		0x1 
#define SCALE_RED_TEMP_6500K        	0x0 
#define SCALE_RED_TEMP_9800K        	0x2 
#define SCALE_HORZ_BLEND            	0x0 
#define SCALE_HORZ_REP              		0x4 
#define SCALE_VERT_BLEND            		0x0 
#define SCALE_VERT_REP              		0x8 
#define SCALE_BANDWIDTH_NORMAL     0x0 
#define SCALE_BANDWIDTH_EXCEEDED  0x4000000 
#define SCALE_BANDWIDTH_RESET       	0x4000000 
#define SCALE_CLK_ACTIVITY          	0x0 
#define SCALE_CLK_CONTINUOUS        	0x20000000 
#define OVERLAY_DISABLE             		0x0 
#define OVERLAY_ENABLE              		0x40000000 
#define SCALE_DISABLE               		0x0 
#define SCALE_ENABLE                		0x80000000 
 
#define SCALER_FRAME_READ_MODE_FULL 	0x0 
#define SCALER_BUF_MODE_SINGLE      		0x0 
#define SCALER_BUF_MODE_DOUBLE      		0x40000 
#define SCALER_BUF_NEXT_0           		0x0 
#define SCALER_BUF_NEXT_1           		0x80000 
#define SCALER_BUF_STATUS_0         		0x0 
#define SCALER_BUF_STATUS_1         		0x100000 
 
#define OVERLAY_MIX_G_CMP           		0x0 
#define OVERLAY_MIX_ALWAYS_G        		0x100 
#define OVERLAY_MIX_ALWAYS_V        		0x200 
#define OVERLAY_MIX_NOT_G           		0x300 
#define OVERLAY_MIX_NOT_V           		0x400 
#define OVERLAY_MIX_G_XOR_V         		0x500 
#define OVERLAY_MIX_NOT_G_XOR_V     	0x600 
#define OVERLAY_MIX_V_CMP           		0x700 
#define OVERLAY_MIX_NOT_G_OR_NOT_V	0x800 
#define OVERLAY_MIX_G_OR_NOT_V      	0x900 
#define OVERLAY_MIX_NOT_G_OR_V      	0xA00 
#define OVERLAY_MIX_G_OR_V          		0xB00 
#define OVERLAY_MIX_G_AND_V         		0xC00 
#define OVERLAY_MIX_NOT_G_AND_V     	0xD00 
#define OVERLAY_MIX_G_AND_NOT_V     	0xE00 
#define OVERLAY_MIX_NOT_G_AND_NOT_V 	0xF00 
#define OVERLAY_EXCLUSIVE_NORMAL    	0x0 
#define OVERLAY_EXCLUSIVE_V_ONLY    	0x80000000 
 
#define VIDEO_IN_8BPP               			0x2 
#define VIDEO_IN_16BPP              			0x4 
#define VIDEO_IN_32BPP              			0x6 
#define VIDEO_IN_VYUY422            			0xB         		/*16 bpp */ 
#define VIDEO_IN_YVYU422            			0xC         		/* 16 bpp */ 
#define SCALE_IN_15BPP              			0x30000     	/* aRGB 1555 */ 
#define SCALE_IN_16BPP              			0x40000     	/* RGB 565 */ 
#define SCALE_IN_32BPP              			0x60000     	/* aRGB 8888 */ 
#define SCALE_IN_YUV9               			0x90000     	/* planar */ 
#define SCALE_IN_YUV12              			0xA0000     	/* planar */ 
#define SCALE_IN_VYUY422            			0xB0000     	/* 16 bpp */ 
#define SCALE_IN_YVYU422            			0xC0000     	/* 16 bpp */ 
#define HOST_YUV_APERTURE_UPPER     		0x0 
#define HOST_YUV_APERTURE_LOWER     	0x20000000 
#define HOST_MEM_MODE_Y             		0x40000000 
#define HOST_MEM_MODE_U             		0x80000000 
#define HOST_MEM_MODE_V             		0xC0000000 
#define HOST_MEM_MODE_NORMAL     		HOST_YUV_APERTURE_UPPER  
 
static Chan *ovl_chan;	/* Channel of controlling process */ 
static int ovl_width;		/* Width of input overlay buffer */ 
static int ovl_height;		/* Height of input overlay buffer */ 
static int ovl_format;	/* Overlay format */ 
static ulong ovl_fib;		/* Frame in bytes */ 
 
enum { 
	 VTGTB1S1        = 0x01,            //  Asic description for VTB1S1 and GTB1S1. 
	 VT4GTIIC        	= 0x3A,            // asic descr for VT4 and RAGE IIC 
	 GTB1U1          	= 0x19,            //  Asic description for GTB1U1. 
	 GTB1S2          	= 0x41,            //  Asic description for GTB1S2. 
	 GTB2U1          	= 0x1A, 
	 GTB2U2          	= 0x5A, 
	 GTB2U3          	= 0x9A, 
	 GTIIIC1U1       	= 0x1B,            // 3D RAGE PRO asic descrp. 
	 GTIIIC1U2       	= 0x5B,            // 3D RAGE PRO asic descrp. 
	 GTIIIC2U1       	= 0x1C,            // 3D RAGE PRO asic descrp. 
	 GTIIIC2U2       	= 0x5C,           // 3D RAGE PRO asic descrp. 
	 GTIIIC2U3       	= 0x7C,            // 3D RAGE PRO asic descrp. 
	 GTBC            	= 0x3A,            // 3D RAGE IIC asic descrp. 
	 LTPRO           	= 0x9C,            // 3D RAGE LT PRO 
}; 
 
1998/0507    
/* 
2000/0727    
 * ATI Mach64(CT|ET|G*|V*|L*). 
1998/0507    
 */ 
2001/0527    
static ushort mach64xxdid[] = { 
	('C'<<8)|'T', 
	('E'<<8)|'T', 
	('G'<<8)|'B', 
	('G'<<8)|'D', 
	('G'<<8)|'I', 
	('G'<<8)|'M', 
	('G'<<8)|'P', 
	('G'<<8)|'Q', 
	('G'<<8)|'T', 
	('G'<<8)|'U', 
	('G'<<8)|'V', 
	('G'<<8)|'Z', 
	('V'<<8)|'T', 
	('V'<<8)|'U', 
	('V'<<8)|'V', 
	('L'<<8)|'B', 
	('L'<<8)|'I', 
	('L'<<8)|'M', 
	('L'<<8)|'P', 
	0, 
2001/1005    
typedef struct { 
	ushort 	m64_id;			/* Chip ID */ 
	int 		m64_vtgt;		/* Is this a VT or GT chipset? */ 
	double	m64_ovlclock;		/* Max. overlay clock frequency */ 
	int		m64_pro;			/* Is this a PRO? */ 
} mach64types; 
 
static double mach64refclock; 
static mach64types *mach64type; 
static int mach64revb;			/* Revision B or greater? */ 
static ulong mach64overlay;		/* Overlay buffer */ 
 
static mach64types mach64s[] = { 
	('C'<<8)|'T',	0,	0.,		0,	/* 4354: CT */ 
	('E'<<8)|'T',	0,	0.,		0,	/* 4554: ET */ 
	('G'<<8)|'B',	1,	125.,		1, 	/* 4742: 264GT PRO */ 
	('G'<<8)|'D',	1,	125.,		1, 	/* 4744: 264GT PRO */ 
	('G'<<8)|'I',	1,	125.,		1, 	/* 4749: 264GT PRO */ 
	('G'<<8)|'M',	0,	135.,		0,	/* 474D: Rage XL */ 
	('G'<<8)|'P',	1,	125.,		1, 	/* 4750: 264GT PRO */ 
	('G'<<8)|'Q',	1,	125.,		1,	/* 4751: 264GT PRO */ 
	('G'<<8)|'T',	1,	80.,		0,	/* 4754: 264GT[B] */ 
	('G'<<8)|'U',	1,	100.,		0,	/* 4755: 264GT DVD */ 
	('G'<<8)|'V',	1,	100.,		0,	/* 4756: Rage2C */ 
	('G'<<8)|'Z',	1,	100.,		0,	/* 475A: Rage2C */ 
	('V'<<8)|'T',	1,	80.,		0,	/* 5654: 264VT/GT/VTB */ 
	('V'<<8)|'U',	1,	80.,		0,	/* 5655: 264VT3 */ 
	('V'<<8)|'V',	1,	100.,		0,	/* 5656: 264VT4 */ 
	('L'<<8)|'B',	0,	135.,		1,	/* 4C42: Rage LTPro AGP */ 
	('L'<<8)|'I',		0,	135.,		0,	/* 4C49: Rage LTPro AGP */ 
	('L'<<8)|'M',	0,	135.,		0,	/* 4C4D: Rage Mobility */ 
	('L'<<8)|'P',	0,	135.,		1,	/* 4C50: 264LT PRO */ 
1998/0507    
}; 
 
2001/1005    
 
1999/1005    
static int hwfill(VGAscr*, Rectangle, ulong); 
static int hwscroll(VGAscr*, Rectangle, Rectangle); 
static void initengine(VGAscr*); 
2001/0908/sys/src/9/pc/vgamach64xx.c:46,602001/1005/sys/src/9/pc/vgamach64xx.c:148,163
1998/0507    
mach64xxpci(void) 
{ 
	Pcidev *p; 
2001/0527    
	ushort *did; 
2001/1005    
	int i; 
1998/0507    
 
	if((p = pcimatch(nil, 0x1002, 0)) == nil) 
		return nil; 
2001/0527    
	for(did = mach64xxdid; *did; did++){ 
		if(*did == p->did) 
2001/0505    
			return p; 
2001/0527    
	} 
 
2001/1005    
	for (i = 0; i != nelem(mach64s); i++) 
		if (mach64s[i].m64_id == p->did) { 
			mach64type = &mach64s[i]; 
			return p; 
		} 
1998/0508    
	return nil; 
1998/0507    
} 
 
2001/0908/sys/src/9/pc/vgamach64xx.c:188,1932001/1005/sys/src/9/pc/vgamach64xx.c:291,319
1999/1005    
	SrcOffPitch,	 
2000/0504    
	LcdIndex, 
	LcdData, 
2001/1005    
	ClockCntl, 
	OverlayScaleCntl, 
	ConfigChipId, 
	Buf0Pitch, 
	ScalerBuf0Pitch, 
	CaptureConfig, 
	OverlayKeyCntl, 
	ScalerColourCntl, 
	ScalerHCoef0, 
	ScalerHCoef1, 
	ScalerHCoef2, 
	ScalerHCoef3, 
	ScalerHCoef4, 
	VideoFormat, 
	Buf0Offset, 
	ScalerBuf0Offset, 
	CrtcGenCntl, 
	OverlayScaleInc, 
	OverlayYX, 
	OverlayYXEnd, 
	ScalerHeightWidth, 
	HTotalDisp, 
	VTotalDisp, 
1998/0507    
}; 
 
2000/0504    
enum { 
2001/0908/sys/src/9/pc/vgamach64xx.c:204,2592001/1005/sys/src/9/pc/vgamach64xx.c:330,412
2000/0504    
	Nlcd, 
}; 
 
2001/0527    
static uchar mmoffset[] = { 
	[CrtcOffPitch]	0x05, 
	[CurClr0]	0x18, 
	[CurClr1]	0x19, 
	[CurOffset]	0x1A, 
	[CurHVposn]	0x1B, 
	[CurHVoff]	0x1C, 
	[BusCntl]		0x28, 
	[LcdIndex]	0x29, 
	[LcdData]	0x2A, 
	[GenTestCntl]	0x34, 
	[DstOffPitch]	0x40, 
	[DstYX]		0x43, 
	[DstHeight]	0x45, 
2001/1005    
#define Bank1			(-0x100)		/* 1KB */ 
 
static int mmoffset[] = { 
	[HTotalDisp]		0x00, 
	[VTotalDisp]		0x02, 
	[CrtcOffPitch]		0x05, 
	[CrtcGenCntl]		0x07, 
	[CurClr0]			0x18, 
	[CurClr1]			0x19, 
	[CurOffset]		0x1A, 
	[CurHVposn]		0x1B, 
	[CurHVoff]		0x1C, 
	[ClockCntl]		0x24, 
	[BusCntl]			0x28, 
	[LcdIndex]		0x29, 
	[LcdData]			0x2A, 
	[GenTestCntl]		0x34, 
	[ConfigChipId]		0x38, 
	[DstOffPitch]		0x40, 
	[DstYX]			0x43, 
	[DstHeight]		0x45, 
1999/1005    
	[DstHeightWidth]	0x46, 
2001/0527    
	[DstBresErr]	0x49, 
	[DstBresInc]	0x4A, 
	[DstBresDec]	0x4B, 
	[DstCntl]		0x4C, 
	[SrcOffPitch]	0x60, 
	[SrcYX]	0x63, 
	[SrcWidth1]	0x64, 
	[SrcYXstart]	0x69, 
2001/1005    
	[DstBresErr]		0x49, 
	[DstBresInc]		0x4A, 
	[DstBresDec]		0x4B, 
	[DstCntl]			0x4C, 
	[SrcOffPitch]		0x60, 
	[SrcYX]			0x63, 
	[SrcWidth1]		0x64, 
	[SrcYXstart]		0x69, 
1999/1005    
	[SrcHeight1Width1]	0x66, 
	[SrcHeight2Width2]	0x6C, 
2001/0527    
	[SrcCntl]		0x6D, 
	[HostCntl]	0x90, 
	[PatReg0]	0xA0, 
	[PatReg1]	0xA1, 
	[PatCntl]	0xA2, 
	[ScLeft]	0xA8, 
	[ScRight]	0xA9, 
	[ScLeftRight]	0xAA, 
	[ScTop]	0xAB, 
	[ScBottom] 0xAC, 
	[ScTopBottom]	0xAD, 
	[DpBkgdClr]	0xB0, 
	[DpFrgdClr]	0xB1, 
	[DpWriteMask]	0xB2, 
	[DpChainMask]	0xB3, 
	[DpPixWidth]	0xB4, 
	[DpMix]		0xB5, 
	[DpSrc]		0xB6, 
	[ClrCmpClr]	0xC0, 
	[ClrCmpMask]	0xC1, 
	[ClrCmpCntl]	0xC2, 
	[FifoStat]		0xC4, 
	[ContextMask]	0xC8, 
	[GuiTrajCntl]	0xCC, 
	[GuiStat]		0xCE, 
2001/1005    
	[SrcCntl]			0x6D, 
	[HostCntl]			0x90, 
	[PatReg0]			0xA0, 
	[PatReg1]			0xA1, 
	[PatCntl]			0xA2, 
	[ScLeft]			0xA8, 
	[ScRight]			0xA9, 
	[ScLeftRight]		0xAA, 
	[ScTop]			0xAB, 
	[ScBottom] 		0xAC, 
	[ScTopBottom]		0xAD, 
	[DpBkgdClr]		0xB0, 
	[DpFrgdClr]		0xB1, 
	[DpWriteMask]		0xB2, 
	[DpChainMask]		0xB3, 
	[DpPixWidth]		0xB4, 
	[DpMix]			0xB5, 
	[DpSrc]			0xB6, 
	[ClrCmpClr]		0xC0, 
	[ClrCmpMask]		0xC1, 
	[ClrCmpCntl]		0xC2, 
	[FifoStat]			0xC4, 
	[ContextMask]		0xC8, 
	[GuiTrajCntl]		0xCC, 
	[GuiStat]			0xCE, 
 
	/* Bank1 */ 
	[OverlayYX]		Bank1 + 0x00, 
	[OverlayYXEnd]		Bank1 + 0x01, 
	[OverlayKeyCntl]	Bank1 + 0x06, 
	[OverlayScaleInc]	Bank1 + 0x08, 
	[OverlayScaleCntl]	Bank1 + 0x09, 
	[ScalerHeightWidth]	Bank1 + 0x0A, 
	[ScalerBuf0Offset]	Bank1 + 0x0D, 
	[ScalerBuf0Pitch]	Bank1 + 0x0F, 
	[VideoFormat]		Bank1 + 0x12, 
	[CaptureConfig]	Bank1 + 0x14, 
	[Buf0Offset]		Bank1 + 0x20, 
	[Buf0Pitch]		Bank1 + 0x23, 
	[ScalerColourCntl]	Bank1 + 0x54, 
	[ScalerHCoef0]		Bank1 + 0x55, 
	[ScalerHCoef1]		Bank1 + 0x56, 
	[ScalerHCoef2]		Bank1 + 0x57, 
	[ScalerHCoef3]		Bank1 + 0x58, 
	[ScalerHCoef4]		Bank1 + 0x59, 
1998/0508    
}; 
 
1998/0507    
static ulong 
2001/0908/sys/src/9/pc/vgamach64xx.c:534,5422001/1005/sys/src/9/pc/vgamach64xx.c:687,732
1999/1005    
} 
 
static void 
2001/1005    
init_overlayclock(VGAscr *scr) 
{ 
	uchar *cc, save, pll_ref_div, pll_vclk_cntl, vclk_post_div,  
			vclk_fb_div, ecp_div; 
	int i; 
	double dotclock; 
 
	/* Taken from GLX */ 
	/* Get monitor dotclock, check for Overlay Scaler clock limit */ 
 	cc = (uchar *)&scr->mmio[mmoffset[ClockCntl]]; 
  	save = cc[1]; i = cc[0] & 3; 
  	cc[1] = 2<<2; pll_ref_div = cc[2]; 
  	cc[1] = 5<<2; pll_vclk_cntl = cc[2]; 
  	cc[1] = 6<<2; vclk_post_div = (cc[2]>>(i+i)) & 3; 
  	cc[1] = (7+i)<<2; vclk_fb_div = cc[2]; 
 
  	dotclock = 2.0 * mach64refclock * vclk_fb_div /  
			(pll_ref_div * (1 << vclk_post_div)); 
	/* ecp_div: 0=dotclock, 1=dotclock/2, 2=dotclock/4 */ 
  	ecp_div = dotclock / mach64type->m64_ovlclock; 
  	if (ecp_div>2) ecp_div = 2; 
 
  	/* Force a scaler clock factor of 1 if refclock * 
   	  * is unknown (VCLK_SRC not PLLVCLK)  */ 
  	if ((pll_vclk_cntl & 0x03) != 0x03) dotclock = ecp_div = 0; 
  	if ((pll_vclk_cntl & 0x30) != ecp_div<<4) { 
    		cc[1] = (5<<2)|2; 
    		cc[2] = (pll_vclk_cntl&0xCF) | (ecp_div<<4); 
	} 
 
  	/* Restore PLL Register Index */ 
  	cc[1] = save; 
} 
 
static void 
1999/1005    
initengine(VGAscr *scr) 
{ 
	ulong pitch; 
2001/1005    
	uchar *bios; 
	ushort table; 
1999/1005    
 
	pitch = Dx(scr->gscreen->r)/8; 
	if(scr->gscreen->depth == 24) 
2001/0908/sys/src/9/pc/vgamach64xx.c:596,6012001/1005/sys/src/9/pc/vgamach64xx.c:786,835
1999/1005    
		break; 
	} 
 
2001/1005    
	/* Get the base freq from the BIOS */ 
	bios  = KADDR(0xC000); 
	table = *(ushort *)(bios + 0x48); 
	table = *(ushort *)(bios + table + 0x10); 
	switch (*(ushort *)(bios + table + 0x08)) { 
      	case 2700:  
		mach64refclock = 27.0;  
		break; 
      	case 2863:  
      	case 2864:  
		mach64refclock = 28.63636;  
		break; 
      	case 2950:  
		mach64refclock = 29.498928713;  
		break; 
    	case 1432:  
	default: 
		mach64refclock = 14.31818;  
		break ;	 
	} 
	 
	/* Figure out which revision this chip is */ 
	switch ((scr->mmio[mmoffset[ConfigChipId]] >> 24) & 0xFF) { 
	case VTGTB1S1: 
	case GTB1U1: 
	case GTB1S2: 
	case GTB2U1: 
	case GTB2U2: 
	case GTB2U3: 
	case GTBC: 
	case GTIIIC1U1: 
	case GTIIIC1U2: 
	case GTIIIC2U1: 
	case GTIIIC2U2:  
	case GTIIIC2U3:  
	case LTPRO: 
			mach64revb = 1; 
			break; 
	default:  
			mach64revb = 0; 
			break; 
	} 
 
	init_overlayclock(scr); 
1999/1005    
	waitforidle(scr); 
} 
 
2001/0908/sys/src/9/pc/vgamach64xx.c:769,7742001/1005/sys/src/9/pc/vgamach64xx.c:1003,1207
2000/0614    
	} 
1999/1005    
} 
 
2001/1005    
static void 
ovl_configure(VGAscr *scr, Chan *c, int nfields, char **field) 
{ 
	int w, h; 
	char *format; 
 
	if (nfields != 4) error(Ebadarg); 
 
	w = (int)strtol(field[1], nil, 0); 
	h = (int)strtol(field[2], nil, 0); 
	format = field[3]; 
 
	if (c != ovl_chan) error(Einuse); 
	if (strcmp(format, "YUYV")) 
		error(Eunsupportedformat); 
	 
	ovl_width  = w; 
	ovl_height = h; 
	ovl_fib       = w * h * sizeof(ushort); 
 
	waitforidle(scr); 
	scr->mmio[mmoffset[BusCntl]] |= 0x08000000;	/* Enable regblock 1 */ 
	scr->mmio[mmoffset[OverlayScaleCntl]] =  
		SCALE_ZERO_EXTEND|SCALE_RED_TEMP_6500K| 
		SCALE_HORZ_BLEND|SCALE_VERT_BLEND; 
	scr->mmio[mmoffset[!mach64revb? Buf0Pitch: ScalerBuf0Pitch]] = w; 
	scr->mmio[mmoffset[CaptureConfig]] =  
		SCALER_FRAME_READ_MODE_FULL| 
		SCALER_BUF_MODE_SINGLE| 
		SCALER_BUF_NEXT_0; 
	scr->mmio[mmoffset[OverlayKeyCntl]] = !mach64revb? 
		OVERLAY_MIX_ALWAYS_V|(OVERLAY_EXCLUSIVE_NORMAL << 28):  
		0x011; 
 
	if (mach64type->m64_pro) { 
		waitforfifo(scr, 6); 
 
		/* set the scaler co-efficient registers */ 
		scr->mmio[mmoffset[ScalerColourCntl]] =  
			(0x00) | (0x10 << 8) | (0x10 << 16); 
		scr->mmio[mmoffset[ScalerHCoef0]] =  
			(0x00) | (0x20 << 8); 
		scr->mmio[mmoffset[ScalerHCoef1]] =  
			(0x0D) | (0x20 << 8) | (0x06 << 16) | (0x0D << 24); 
		scr->mmio[mmoffset[ScalerHCoef2]] =  
			(0x0D) | (0x1C << 8) | (0x0A << 16) | (0x0D << 24); 
		scr->mmio[mmoffset[ScalerHCoef3]] =  
			(0x0C) | (0x1A << 8) | (0x0E << 16) | (0x0C << 24); 
		scr->mmio[mmoffset[ScalerHCoef4]] =  
			(0x0C) | (0x14 << 8) | (0x14 << 16) | (0x0C << 24); 
	} 
	 
	waitforfifo(scr, 3); 
	scr->mmio[mmoffset[VideoFormat]] = SCALE_IN_YVYU422 | 
		(!mach64revb? 0xC: 0); 
 
	if (mach64overlay == 0) 
		mach64overlay = scr->storage + 64 * 64 * sizeof(uchar); 
	scr->mmio[mmoffset[!mach64revb? Buf0Offset: ScalerBuf0Offset]] =  
		mach64overlay; 
} 
 
static void 
ovl_enable(VGAscr *scr, Chan *c, int nfields, char **field) 
{ 
	int x, y, w, h; 
	long h_inc, v_inc; 
 
	if (nfields != 5) error(Ebadarg); 
 
	x = (int)strtol(field[1], nil, 0); 
	y = (int)strtol(field[2], nil, 0); 
	w = (int)strtol(field[3], nil, 0); 
	h = (int)strtol(field[4], nil, 0); 
 
	if (x < 0 || x + w > physgscreenr.max.x || 
	     y < 0 || y + h > physgscreenr.max.y) 
		error(Ebadarg); 
 
	if (c != ovl_chan) error(Einuse); 
	if (scr->mmio[mmoffset[CrtcGenCntl]] & 1) {	/* double scan enable */ 
		y *= 2; 
		h *= 2; 
	} 
 
	waitforfifo(scr, 2); 
	scr->mmio[mmoffset[OverlayYX]] =  
			((x & 0xFFFF) << 16) | (y & 0xFFFF); 
	scr->mmio[mmoffset[OverlayYXEnd]] =  
			(((x + w) & 0xFFFF) << 16) | ((y + h) & 0xFFFF); 
 
	h_inc = (ovl_width << 12) / (w >> 1);  /* ??? */ 
	v_inc = (ovl_height << 12) / h; 
	waitforfifo(scr, 2); 
	scr->mmio[mmoffset[OverlayScaleInc]] =  
			((h_inc & 0xFFFF) << 16) | (v_inc & 0xFFFF); 
	scr->mmio[mmoffset[ScalerHeightWidth]] =  
			((ovl_width & 0xFFFF) << 16) | (ovl_height & 0xFFFF); 
	waitforidle(scr); 
	scr->mmio[mmoffset[OverlayScaleCntl]] |=  
			(SCALE_ENABLE|OVERLAY_ENABLE); 
} 
 
static void 
ovl_status(VGAscr *scr, Chan *, int nfields, char **field) 
{ 
	if (nfields != 1) error(Ebadarg); 
 
	pprint("%s: %s %.4uX, VT/GT %s, PRO %s, ovlclock %d, rev B %s, refclock %d\n", 
		   scr->dev->name, field[0], mach64type->m64_id, 
		   mach64type->m64_vtgt? "yes": "no", 
		   mach64type->m64_pro? "yes": "no", 
		   (int)(mach64type->m64_ovlclock  * 10000.), 
		   mach64revb? "yes": "no", 
		   (int)(mach64refclock * 10000.)); 
	pprint("%s: storage @%.8luX, aperture @%8.ulX, ovl buf @%.8ulX\n", 
		   scr->dev->name, scr->storage, scr->aperture, 
		   mach64overlay); 
} 
	 
static void 
ovl_openctl(VGAscr *, Chan *c, int nfields, char **) 
{ 
	if (nfields != 1) error(Ebadarg); 
	if (ovl_chan) error(Einuse); 
	ovl_chan = c; 
} 
 
static void 
ovl_closectl(VGAscr *scr, Chan *c, int nfields, char **) 
{ 
	if (c != ovl_chan || nfields != 1) return; 
 
	waitforidle(scr); 
	scr->mmio[mmoffset[OverlayScaleCntl]] &= 
			~(SCALE_ENABLE|OVERLAY_ENABLE); 
	ovl_chan = nil; 
	ovl_width = ovl_height = ovl_fib = 0; 
} 
 
static struct { 
	char *ovl_command; 
	void	 (*ovl_f)(VGAscr *, Chan *, int, char **); 
} ovl_cmds[] = { 
	{	"openctl",		ovl_openctl	}, 
	{	"configure", 	ovl_configure,	}, 
	{	"enable",		ovl_enable,	}, 
	{	"closectl",		ovl_closectl	}, 
	{	"status",		ovl_status		}, 
}; 
 
static void 
mach64xxovlctl(VGAscr *scr, Chan *c, void *a, int) 
{ 
#define MAXARGS	10 
	char *field[MAXARGS]; 
	int nfields, i; 
 
	if (!mach64type->m64_vtgt) error(Enodev); 
 
	nfields = getfields(a, field, nelem(field), 1, "\t\n\r "); 
	if (nfields < 1) error(Ebadarg); 
 
	for (i = 0; i != nelem(ovl_cmds); i++) 
		if (!strcmp(field[0], ovl_cmds[i].ovl_command)) 
			break; 
 
	if (i == nelem(ovl_cmds)) 
		error(Ebadarg); 
 
	ovl_cmds[i].ovl_f(scr, c, nfields, field); 
} 
 
static int 
mach64xxovlwrite(VGAscr *scr, void *a, int len, vlong offs) 
{ 
	uchar *src; 
	int _len; 
 
	if (ovl_chan == nil) return len;	/* Acts as a /dev/null */ 
	 
	/* Calculate the destination address */ 
	_len = len; 
	src   = (uchar *)a; 
	while (len > 0) { 
		ulong _offs; 
		int nb; 
 
		_offs = (ulong)(offs % ovl_fib); 
		nb     = (_offs + len > ovl_fib)? ovl_fib - _offs: len; 
		memmove((uchar *)KADDR(scr->aperture + mach64overlay + _offs),  
				  src, nb); 
		offs += nb; 
		src  += nb; 
		len  -= nb; 
	} 
	return _len; 
} 
 
1998/0507    
VGAdev vgamach64xxdev = { 
	"mach64xx", 
 
2001/0908/sys/src/9/pc/vgamach64xx.c:777,7822001/1005/sys/src/9/pc/vgamach64xx.c:1210,1218
1998/0507    
	0,				/* page */ 
2001/0527    
	mach64xxlinear,			/* linear */ 
1999/1005    
	mach64xxdrawinit,	/* drawinit */ 
2001/1005    
	0, 
	mach64xxovlctl,	/* overlay control */ 
	mach64xxovlwrite,	/* write the overlay */ 
1998/0507    
}; 
 
VGAcur vgamach64xxcur = { 
2001/1005/sys/src/9/pc/vgamach64xx.c:580,5862001/1015/sys/src/9/pc/vgamach64xx.c:580,586 (short | long)
1999/1005    
	else 
		dx = 64 / scr->gscreen->depth; 
 
	if(screenpan(p, &physgscreenr, dx, 1)){ 
2001/1015    
	if(panning && screenpan(p, &physgscreenr, dx, 1)){ 
1999/1005    
		off = (physgscreenr.min.y*Dx(scr->gscreen->r)+physgscreenr.min.x)/dx; 
		pitch = Dx(scr->gscreen->r)/8; 
		iow32(scr, CrtcOffPitch, (pitch<<22)|off); 
2001/1005/sys/src/9/pc/vgamach64xx.c:999,10042001/1015/sys/src/9/pc/vgamach64xx.c:999,1005
2000/0614    
	case ('L'<<8)|'M':		/* 4C4D: Rage Mobility */ 
	case ('L'<<8)|'P':		/* 4C50: Rage 3D LTPro */ 
2000/0504    
		scr->blank = mach64lcdblank; 
2001/1015    
		hwblank = 1; 
2000/0614    
		break; 
	} 
1999/1005    
} 
Too many diffs (26 > 25). Stopping.


source code copyright © 1990-2005 Lucent Technologies; see license
Plan 9 distribution
comments to russ cox (rsc@swtch.com)