Subversion Repositories planix.SVN

Rev

Blame | Last modification | View Log | RSS feed

#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,
        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 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 void
i81xenable(VGAscr* scr)
{
        Pcidev *p;
        int size;
        Mach *mach0;
        ulong *pgtbl, *rp, cursor, *pte, fbuf, fbend;
        
        if(scr->mmio)
                return;
        p = i81xpcimatch();
        if(p == nil)
                return;
        scr->mmio = vmap(p->mem[1].bar & ~0x0F, p->mem[1].size);
        if(scr->mmio == 0)
                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;
        }

        /*
         * 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 mmuwalk");
        *pte |= PTEUNCACHED;
        scr->storage = cursor;

        scr->blank = i81xblank;
        hwblank = 1;
}

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)
                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;
        CursorI81x *hwcurs;

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

        /*
         * Initialise the 32x32 cursor to be transparent in 2bpp mode.
         */
        hwcurs->base = PADDR(scr->storage);
        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, &arrow);
        i81xcurmove(scr, ZP);
}

VGAdev vgai81xdev = {
        "i81x",

        i81xenable,
        nil,
        nil,
        nil,
};

VGAcur vgai81xcur = {
        "i81xhwgc",

        i81xcurenable,
        i81xcurdisable,
        i81xcurload,
        i81xcurmove,
};