Subversion Repositories planix.SVN

Rev

Rev 2 | Blame | Compare with Previous | 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"

enum {
        PCIVMWARE       = 0x15AD,       /* PCI VID */

        VMWARE1         = 0x0710,       /* PCI DID */
        VMWARE2         = 0x0405,
};

enum {
        Rid = 0,
        Renable,
        Rwidth,
        Rheight,
        Rmaxwidth,

        Rmaxheight,
        Rdepth,
        Rbpp,
        Rpseudocolor,
        Rrmask,

        Rgmask,
        Rbmask,
        Rbpl,
        Rfbstart,
        Rfboffset,

        Rfbmaxsize,
        Rfbsize,
        Rcap,
        Rmemstart,
        Rmemsize,

        Rconfigdone,
        Rsync,
        Rbusy,
        Rguestid,
        Rcursorid,

        Rcursorx,
        Rcursory,
        Rcursoron,
        Nreg,

        Crectfill = 1<<0,
        Crectcopy = 1<<1,
        Crectpatfill = 1<<2,
        Coffscreen = 1<<3,
        Crasterop = 1<<4,
        Ccursor = 1<<5,
        Ccursorbypass = 1<<6,
        Ccursorbypass2 = 1<<7,
        C8bitemulation = 1<<8,
        Calphacursor = 1<<9,

        FifoMin = 0,
        FifoMax = 1,
        FifoNextCmd = 2,
        FifoStop = 3,
        FifoUser = 4,

        Xupdate = 1,
        Xrectfill = 2,
        Xrectcopy = 3,
        Xdefinebitmap = 4,
        Xdefinebitmapscanline = 5,
        Xdefinepixmap = 6,
        Xdefinepixmapscanline = 7,
        Xrectbitmapfill = 8,
        Xrectpixmapfill = 9,
        Xrectbitmapcopy = 10,
        Xrectpixmapcopy = 11,
        Xfreeobject = 12,
        Xrectropfill = 13,
        Xrectropcopy = 14,
        Xrectropbitmapfill = 15,
        Xrectroppixmapfill = 16,
        Xrectropbitmapcopy = 17,
        Xrectroppixmapcopy = 18,
        Xdefinecursor = 19,
        Xdisplaycursor = 20,
        Xmovecursor = 21,
        Xdefinealphacursor = 22,
        Xcmdmax = 23,

        CursorOnHide = 0,
        CursorOnShow = 1,
        CursorOnRemoveFromFb = 2,
        CursorOnRestoreToFb = 3,

        Rpalette = 1024,
};

typedef struct Vmware   Vmware;
struct Vmware {
        ulong   fb;

        ulong   ra;
        ulong   rd;

        ulong   r[Nreg];
        ulong   *mmio;
        ulong   mmiosize;

        char    chan[32];
        int     depth;
};

Vmware xvm;
Vmware *vm=&xvm;

static ulong
vmrd(Vmware *vm, int i)
{
        outl(vm->ra, i);
        return inl(vm->rd);
}

static void
vmwr(Vmware *vm, int i, ulong v)
{
        outl(vm->ra, i);
        outl(vm->rd, v);
}

static void
vmwait(Vmware *vm)
{
        vmwr(vm, Rsync, 1);
        while(vmrd(vm, Rbusy))
                ;
}

static void
vmwarelinear(VGAscr* scr, int, int)
{
        char err[64];
        Pcidev *p;

        err[0] = 0;
        p = nil;
        while((p = pcimatch(p, PCIVMWARE, 0)) != nil){
                if(p->ccrb != Pcibcdisp)
                        continue;
                switch(p->did){
                default:
                        snprint(err, sizeof err, "unknown vmware pci did %.4ux",
                                p->did);
                        continue;
                        
                case VMWARE1:
                        vm->ra = 0x4560;
                        vm->rd = 0x4560 + 4;
                        break;
        
                case VMWARE2:
                        vm->ra = p->mem[0].bar & ~3;
                        vm->rd = vm->ra + 1;
                        break;
                }
                break;                  /* found a card, p is set */
        }
        if(p == nil)
                error(err[0]? err: "no vmware vga card found");

        /*
         * empirically, 2*fbsize enables 1280x1024x32, not just 1024x768x32.
         * is fbsize in bytes or pixels?
         */
        vgalinearaddr(scr, vmrd(vm, Rfbstart), 2*vmrd(vm, Rfbsize));
        if(scr->apsize)
                addvgaseg("vmwarescreen", scr->paddr, scr->apsize);
}

static void
vmfifowr(Vmware *vm, ulong v)
{
        ulong *mm;

        mm = vm->mmio;
        if(mm == nil){
                iprint("!");
                return;
        }

        if(mm[FifoNextCmd]+sizeof(ulong) == mm[FifoStop]
        || (mm[FifoNextCmd]+sizeof(ulong) == mm[FifoMax]
            && mm[FifoStop] == mm[FifoMin]))
                vmwait(vm);

        mm[mm[FifoNextCmd]/sizeof(ulong)] = v;

        /* must do this way so mm[FifoNextCmd] is never mm[FifoMax] */
        v = mm[FifoNextCmd] + sizeof(ulong);
        if(v == mm[FifoMax])
                v = mm[FifoMin];
        mm[FifoNextCmd] = v;
}

static void
vmwareflush(VGAscr*, Rectangle r)
{
        if(vm->mmio == nil)
                return;

        vmfifowr(vm, Xupdate);
        vmfifowr(vm, r.min.x);
        vmfifowr(vm, r.min.y);
        vmfifowr(vm, r.max.x-r.min.x);
        vmfifowr(vm, r.max.y-r.min.y);
        vmwait(vm);
}

static void
vmwareload(VGAscr*, Cursor *c)
{
        int i;
        ulong clr, set;
        ulong and[16];
        ulong xor[16];

        if(vm->mmio == nil)
                return;
        vmfifowr(vm, Xdefinecursor);
        vmfifowr(vm, 1);        /* cursor id */
        vmfifowr(vm, -c->offset.x);
        vmfifowr(vm, -c->offset.y);

        vmfifowr(vm, 16);       /* width */
        vmfifowr(vm, 16);       /* height */
        vmfifowr(vm, 1);        /* depth for and mask */
        vmfifowr(vm, 1);        /* depth for xor mask */

        for(i=0; i<16; i++){
                clr = (c->clr[i*2+1]<<8) | c->clr[i*2];
                set = (c->set[i*2+1]<<8) | c->set[i*2];
                and[i] = ~(clr|set);    /* clr and set pixels => black */
                xor[i] = clr&~set;              /* clr pixels => white */
        }
        for(i=0; i<16; i++)
                vmfifowr(vm, and[i]);
        for(i=0; i<16; i++)
                vmfifowr(vm, xor[i]);

        vmwait(vm);
}

static int
vmwaremove(VGAscr*, Point p)
{
        vmwr(vm, Rcursorid, 1);
        vmwr(vm, Rcursorx, p.x);
        vmwr(vm, Rcursory, p.y);
        vmwr(vm, Rcursoron, CursorOnShow);
        return 0;
}

static void
vmwaredisable(VGAscr*)
{
        vmwr(vm, Rcursorid, 1);
        vmwr(vm, Rcursoron, CursorOnHide);
}

static void
vmwareenable(VGAscr*)
{
        vmwr(vm, Rcursorid, 1);
        vmwr(vm, Rcursoron, CursorOnShow);
}

static void
vmwareblank(int)
{
}

static int
vmwarescroll(VGAscr*, Rectangle r, Rectangle sr)
{
        if(vm->mmio == nil)
                return 0;
        vmfifowr(vm, Xrectcopy);
        vmfifowr(vm, sr.min.x);
        vmfifowr(vm, sr.min.y);
        vmfifowr(vm, r.min.x);
        vmfifowr(vm, r.min.y);
        vmfifowr(vm, Dx(r));
        vmfifowr(vm, Dy(r));
        vmwait(vm);
        return 1;
}

static int
vmwarefill(VGAscr*, Rectangle r, ulong sval)
{
        if(vm->mmio == nil)
                return 0;
        vmfifowr(vm, Xrectfill);
        vmfifowr(vm, sval);
        vmfifowr(vm, r.min.x);
        vmfifowr(vm, r.min.y);
        vmfifowr(vm, r.max.x-r.min.x);
        vmfifowr(vm, r.max.y-r.min.y);
        vmwait(vm);
        return 1;
}

static void
vmwaredrawinit(VGAscr *scr)
{
        ulong offset;
        ulong mmiobase, mmiosize;

        if(scr->mmio==nil){
                mmiobase = vmrd(vm, Rmemstart);
                if(mmiobase == 0)
                        return;
                mmiosize = vmrd(vm, Rmemsize);
                scr->mmio = vmap(mmiobase, mmiosize);
                if(scr->mmio == nil)
                        return;
                vm->mmio = scr->mmio;
                vm->mmiosize = mmiosize;
                addvgaseg("vmwaremmio", mmiobase, mmiosize);
        }

        scr->mmio[FifoMin] = 4*sizeof(ulong);
        scr->mmio[FifoMax] = vm->mmiosize;
        scr->mmio[FifoNextCmd] = 4*sizeof(ulong);
        scr->mmio[FifoStop] = 4*sizeof(ulong);
        vmwr(vm, Rconfigdone, 1);

        scr->scroll = vmwarescroll;
        scr->fill = vmwarefill;

        offset = vmrd(vm, Rfboffset);
        scr->gscreendata->bdata += offset;
}

VGAdev vgavmwaredev = {
        "vmware",

        0,
        0,
        0,
        vmwarelinear,
        vmwaredrawinit,
        0,
        0,
        0,
        vmwareflush,
};

VGAcur vgavmwarecur = {
        "vmwarehwgc",

        vmwareenable,
        vmwaredisable,
        vmwareload,
        vmwaremove,
};