code: plan9front

ref: df04ea8d6c2e1e75307a77f2b086a836f480ab72
dir: /sys/src/9/pc/vgai81x.c/

View raw version
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "io.h"
#include "../port/pci.h"
#include "../port/error.h"

#define	Image	IMAGE
#include <draw.h>
#include <memdraw.h>
#include <cursor.h>
#include "screen.h"

typedef struct
{
	ushort	ctl;
	ushort	pad;
	ulong	base;
	ulong	pos;
} CursorI81x;

enum {
	Fbsize		= 8*MB,

	hwCur		= 0x70080,
	SRX		= 0x3c4,
	DPMSsync	= 0x5002,
};

static void
i81xblank(VGAscr *scr, int blank)
{
	char *srx, *srxd, *dpms;
	char sr01, mode;

	srx = (char *)scr->mmio+SRX;
	srxd = srx+1;
	dpms = (char *)scr->mmio+DPMSsync;

	*srx = 0x01;
	sr01 = *srxd & ~0x20;
	mode = *dpms & 0xf0;

	if(blank) {
		sr01 |= 0x20;
		mode |= 0x0a;
	}
	*srxd = sr01;
	*dpms = mode;
}

static void
i81xenable(VGAscr* scr)
{
	Pcidev *p;
	int size;
	ulong *pgtbl, *rp;
	uintptr fbuf, fbend;
	
	if(scr->mmio)
		return;
	p = scr->pci;
	if(p == nil)
		return;
	if((p->mem[0].bar & 1) != 0
	|| (p->mem[1].bar & 1) != 0)
		return;
	scr->mmio = vmap(p->mem[1].bar & ~0x0F, p->mem[1].size);
	if(scr->mmio == nil)
		return;
	addvgaseg("i81xmmio", p->mem[1].bar&~0x0F, p->mem[1].size);

	/* allocate page table */
	pgtbl = xspanalloc(64*1024, BY2PG, 0);
	scr->mmio[0x2020/4] = PADDR(pgtbl) | 1;

	size = p->mem[0].size;
	if(size > 0)
		size = Fbsize;
	vgalinearaddr(scr, p->mem[0].bar&~0xF, size);
	addvgaseg("i81xscreen", p->mem[0].bar&~0xF, size);

	/*
	 * allocate backing store for frame buffer
	 * and populate device page tables.
	 */
	fbuf = PADDR(xspanalloc(size, BY2PG, 0));
	fbend = PGROUND(fbuf+size);
	rp = scr->mmio+0x10000/4;
	while(fbuf < fbend) {
		*rp++ = fbuf | 1;
		fbuf += BY2PG;
	}

	scr->storage = 0;
	scr->blank = i81xblank;
}

static void
i81xcurdisable(VGAscr* scr)
{
	CursorI81x *hwcurs;

	if(scr->mmio == 0)
		return;
	hwcurs = (void*)((uchar*)scr->mmio+hwCur);
	hwcurs->ctl = (1<<4);
}

static void
i81xcurload(VGAscr* scr, Cursor* curs)
{
	int y;
	uchar *p;
	CursorI81x *hwcurs;

	if(scr->mmio == 0 || scr->storage == 0)
		return;
	hwcurs = (void*)((uchar*)scr->mmio+hwCur);

	/*
	 * Disable the cursor then load the new image in
	 * the top-left of the 32x32 array.
	 * Unused portions of the image have been initialised to be
	 * transparent.
	 */
	hwcurs->ctl = (1<<4);
	p = (uchar*)scr->storage;
	for(y = 0; y < 16; y += 2) {
		*p++ = ~(curs->clr[2*y]|curs->set[2*y]);
		*p++ = ~(curs->clr[2*y+1]|curs->set[2*y+1]);
		p += 2;
		*p++ = ~(curs->clr[2*y+2]|curs->set[2*y+2]);
		*p++ = ~(curs->clr[2*y+3]|curs->set[2*y+3]);
		p += 2;
		*p++ = curs->set[2*y];
		*p++ = curs->set[2*y+1];
		p += 2;
		*p++ = curs->set[2*y+2];
		*p++ = curs->set[2*y+3];
		p += 2;
	}

	/*
	 * Save the cursor hotpoint and enable the cursor.
	 * The 0,0 cursor point is top-left.
	 */
	scr->offset.x = curs->offset.x;
	scr->offset.y = curs->offset.y;
	hwcurs->ctl = (1<<4)|1;
}

static int
i81xcurmove(VGAscr* scr, Point p)
{
	int x, y;
	ulong pos;
	CursorI81x *hwcurs;

	if(scr->mmio == 0)
		return 1;
	hwcurs = (void*)((uchar*)scr->mmio+hwCur);

	x = p.x+scr->offset.x;
	y = p.y+scr->offset.y;
	pos = 0;
	if(x < 0) {
		pos |= (1<<15);
		x = -x;
	}
	if(y < 0) {
		pos |= (1<<31);
		y = -y;
	}
	pos |= ((y&0x7ff)<<16)|(x&0x7ff);
	hwcurs->pos = pos;

	return 0;
}

static void
i81xcurenable(VGAscr* scr)
{
	int i;
	uchar *p;

	i81xenable(scr);
	if(scr->mmio == 0)
		return;

	if(scr->storage == 0){
		CursorI81x *hwcurs;
		Page *pg = newpage(0, nil, 0);
		scr->storage = (uintptr)vmap(pg->pa, BY2PG);
		if(scr->storage == 0){
			putpage(pg);
			return;
		}
		hwcurs = (void*)((uchar*)scr->mmio+hwCur);
		hwcurs->base = pg->pa;
	}

	/*
	 * Initialise the 32x32 cursor to be transparent in 2bpp mode.
	 */
	p = (uchar*)scr->storage;
	for(i = 0; i < 32/2; i++) {
		memset(p, 0xff, 8);
		memset(p+8, 0, 8);
		p += 16;
	}

	/*
	 * Load, locate and enable the 32x32 cursor in 2bpp mode.
	 */
	i81xcurload(scr, &cursor);
	i81xcurmove(scr, ZP);
}

VGAdev vgai81xdev = {
	"i81x",

	i81xenable,
	nil,
	nil,
	nil,
};

VGAcur vgai81xcur = {
	"i81xhwgc",

	i81xcurenable,
	i81xcurdisable,
	i81xcurload,
	i81xcurmove,
};