summaryrefslogtreecommitdiff
path: root/os/pc/vgai81x.c
diff options
context:
space:
mode:
authorCharles.Forsyth <devnull@localhost>2006-12-22 21:39:35 +0000
committerCharles.Forsyth <devnull@localhost>2006-12-22 21:39:35 +0000
commit74a4d8c26dd3c1e9febcb717cfd6cb6512991a7a (patch)
treec6e220ba61db3a6ea4052e6841296d829654e664 /os/pc/vgai81x.c
parent46439007cf417cbd9ac8049bb4122c890097a0fa (diff)
20060303
Diffstat (limited to 'os/pc/vgai81x.c')
-rw-r--r--os/pc/vgai81x.c282
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,
+};