ref: 2d56837b2fabf6a7cc11f02b51f20a1e35128c57
dir: /sys/src/9/pc/vgai81x.c/
#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,
};