diff options
| author | Charles.Forsyth <devnull@localhost> | 2006-12-22 21:39:35 +0000 |
|---|---|---|
| committer | Charles.Forsyth <devnull@localhost> | 2006-12-22 21:39:35 +0000 |
| commit | 74a4d8c26dd3c1e9febcb717cfd6cb6512991a7a (patch) | |
| tree | c6e220ba61db3a6ea4052e6841296d829654e664 /os/pc/vgai81x.c | |
| parent | 46439007cf417cbd9ac8049bb4122c890097a0fa (diff) | |
20060303
Diffstat (limited to 'os/pc/vgai81x.c')
| -rw-r--r-- | os/pc/vgai81x.c | 282 |
1 files changed, 282 insertions, 0 deletions
diff --git a/os/pc/vgai81x.c b/os/pc/vgai81x.c new file mode 100644 index 00000000..ac840fe6 --- /dev/null +++ b/os/pc/vgai81x.c @@ -0,0 +1,282 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.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, +}; + +static Pcidev * +i81xpcimatch(void) +{ + Pcidev *p; + + p = nil; + while((p = pcimatch(p, 0x8086, 0)) != nil){ + switch(p->did){ + default: + continue; + case 0x7121: + case 0x7123: + case 0x7125: + case 0x1102: + case 0x1112: + case 0x1132: + case 0x3577: /* IBM R31 uses intel 830M chipset */ + return p; + } + } + return nil; +} + +static ulong +i81xlinear(VGAscr* scr, int* size, int* align) +{ + Pcidev *p; + int oapsize, wasupamem; + ulong aperture, oaperture, fbuf, fbend, *rp; + + oaperture = scr->aperture; + oapsize = scr->apsize; + wasupamem = scr->isupamem; + + aperture = 0; + p = i81xpcimatch(); + if(p != nil) { + aperture = p->mem[0].bar & ~0x0F; + *size = p->mem[0].size; + if(*size > Fbsize) + *size = Fbsize; + } + + if(wasupamem){ + if(oaperture == aperture) + return oaperture; + upafree(oaperture, oapsize); + } + scr->isupamem = 0; + + aperture = upamalloc(aperture, *size, *align); + if(aperture == 0){ + if(wasupamem && upamalloc(oaperture, oapsize, 0)){ + aperture = oaperture; + scr->isupamem = 1; + } + else + scr->isupamem = 0; + } + else + scr->isupamem = 1; + + /* allocate space for frame buffer, populate page table */ + if(oapsize == 0) { + fbuf = PADDR(xspanalloc(*size, BY2PG, 0)); + fbend = PGROUND(fbuf+*size); + rp = KADDR(scr->io+0x10000); + while(fbuf < fbend) { + *rp++ = fbuf | (1<<0); + fbuf += BY2PG; + } + } + return aperture; +} + +static void +i81xenable(VGAscr* scr) +{ + Pcidev *p; + int align, size; + Mach *mach0; + ulong aperture, pgtbl, *rp, cursor, *pte; + + /* + * Only once, can't be disabled for now. + * scr->io holds the physical address of + * the MMIO registers. + */ + if(scr->io) + return; + p = i81xpcimatch(); + if(p == nil) + return; + scr->io = upamalloc(p->mem[1].bar & ~0x0F, p->mem[1].size, 0); + if(scr->io == 0) + return; + + /* allocate page table */ + pgtbl = PADDR(xspanalloc(64*1024, BY2PG, 0)); + rp = KADDR(scr->io+0x2020); + *rp = pgtbl | 1; + + addvgaseg("i81xmmio", (ulong)scr->io, p->mem[0].size); + + size = p->mem[0].size; + align = 0; + aperture = i81xlinear(scr, &size, &align); + if(aperture){ + scr->aperture = aperture; + scr->apsize = size; + addvgaseg("i81xscreen", aperture, size); + } + + /* + * allocate space for the cursor data in system memory. + * must be uncached. + */ + cursor = (ulong)xspanalloc(BY2PG, BY2PG, 0); + mach0 = MACHP(0); + pte = mmuwalk(mach0->pdb, cursor, 2, 0); + if(pte == nil) + panic("i81x cursor"); + *pte |= PTEUNCACHED; + scr->storage = PADDR(cursor); +} + +static void +i81xcurdisable(VGAscr* scr) +{ + CursorI81x *hwcurs; + + if(scr->io == 0) + return; + hwcurs = KADDR(scr->io+hwCur); + hwcurs->ctl = (1<<4); +} + +static void +i81xcurload(VGAscr* scr, Cursor* curs) +{ + int y; + uchar *p; + CursorI81x *hwcurs; + + if(scr->io == 0) + return; + hwcurs = KADDR(scr->io+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 = KADDR(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->io == 0) + return 1; + hwcurs = KADDR(scr->io+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; + CursorI81x *hwcurs; + + i81xenable(scr); + if(scr->io == 0) + return; + hwcurs = KADDR(scr->io+hwCur); + + /* + * Initialise the 32x32 cursor to be transparent in 2bpp mode. + */ + hwcurs->base = scr->storage; + p = KADDR(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, &arrow); + i81xcurmove(scr, ZP); +} + +VGAdev vgai81xdev = { + "i81x", + + i81xenable, + nil, + nil, + i81xlinear, +}; + +VGAcur vgai81xcur = { + "i81xhwgc", + + i81xcurenable, + i81xcurdisable, + i81xcurload, + i81xcurmove, +}; |
