2a1b43ad98
previously, we had to maintain 3 sets of pci vid/did's: 1) in /lib/vgadb for detection 2) in the userspace driver in aux/vga 3) in the kernel mode driver this change makes the kernel mode driver more dumb in the cases where possible. we let userspace do the pci enumeration and if needed, it can set the pci address of the vga card. kernel mode drivers can assume to get the right pci device passed in scr->pci for enable() and linear() functions and just do very basic sanity checking before mapping framebuffer and mmio regions. vgalinearpciid() was removed as userspace is responsible to pick pci device. theres a new vgactl message "pcidev" where userspace can set the bus address. we initialize scr->pci in vgareset() to the first pci graphics card found. this should cover cases when an old aux/vga binary is used that doesnt use the new pcidev message. userspace drivers will now use the pci device that got a match from /lib/vgadb and skip ther own enumeration. this way, vga cards can be made to work by simply adding an entry in vgadb with no need to modify userspace or kernelspace drivers. this is not always possible if the driver derives information from the specific card model.
347 lines
5.6 KiB
C
347 lines
5.6 KiB
C
#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, /* deprecated */
|
|
Rfboffset,
|
|
|
|
Rfbmaxsize,
|
|
Rfbsize,
|
|
Rcap,
|
|
Rmemstart, /* deprecated */
|
|
Rmemsize,
|
|
|
|
Rconfigdone,
|
|
Rsync,
|
|
Rbusy,
|
|
Rguestid,
|
|
Rcursorid,
|
|
|
|
Rcursorx,
|
|
Rcursory,
|
|
Rcursoron,
|
|
Nreg,
|
|
|
|
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;
|
|
int ver;
|
|
};
|
|
|
|
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)
|
|
{
|
|
Pcidev *p;
|
|
|
|
p = scr->pci;
|
|
if(p == nil || p->vid != PCIVMWARE)
|
|
return;
|
|
switch(p->did){
|
|
default:
|
|
return;
|
|
case VMWARE1:
|
|
vm->ver = 1;
|
|
vm->ra = 0x4560;
|
|
vm->rd = 0x4560 + 4;
|
|
break;
|
|
case VMWARE2:
|
|
vm->ver = 2;
|
|
vm->ra = p->mem[0].bar & ~3;
|
|
vm->rd = vm->ra + 1;
|
|
break;
|
|
}
|
|
// vm->fb = vmrd(vm, Rfbstart);
|
|
vm->fb = p->mem[1].bar & ~0xF;
|
|
vm->fb += vmrd(vm, Rfboffset);
|
|
vgalinearaddr(scr, vm->fb, vmrd(vm, Rfbmaxsize));
|
|
if(scr->apsize)
|
|
addvgaseg("vmwarescreen", scr->paddr, scr->apsize);
|
|
|
|
if(scr->mmio==nil){
|
|
ulong mmiobase, mmiosize;
|
|
|
|
// mmiobase = vmrd(vm, Rmemstart);
|
|
mmiobase = p->mem[2].bar & ~0xF;
|
|
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);
|
|
}
|
|
|
|
static void
|
|
vmfifowr(Vmware *vm, ulong v)
|
|
{
|
|
ulong *mm;
|
|
|
|
mm = vm->mmio;
|
|
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)
|
|
{
|
|
if(vm->mmio == nil)
|
|
return 1;
|
|
vmwr(vm, Rcursorid, 1);
|
|
vmwr(vm, Rcursorx, p.x);
|
|
vmwr(vm, Rcursory, p.y);
|
|
vmwr(vm, Rcursoron, CursorOnShow);
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
vmwaredisable(VGAscr*)
|
|
{
|
|
if(vm->mmio == nil)
|
|
return;
|
|
vmwr(vm, Rcursorid, 1);
|
|
vmwr(vm, Rcursoron, CursorOnHide);
|
|
}
|
|
|
|
static void
|
|
vmwareenable(VGAscr*)
|
|
{
|
|
if(vm->mmio == nil)
|
|
return;
|
|
vmwr(vm, Rcursorid, 1);
|
|
vmwr(vm, Rcursoron, CursorOnShow);
|
|
}
|
|
|
|
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)
|
|
{
|
|
scr->scroll = vmwarescroll;
|
|
if(vm->ver == 1)
|
|
scr->fill = vmwarefill;
|
|
}
|
|
|
|
VGAdev vgavmwaredev = {
|
|
"vmware",
|
|
0,
|
|
0,
|
|
0,
|
|
vmwarelinear,
|
|
vmwaredrawinit,
|
|
0,
|
|
0,
|
|
0,
|
|
vmwareflush,
|
|
};
|
|
|
|
VGAcur vgavmwarecur = {
|
|
"vmwarehwgc",
|
|
|
|
vmwareenable,
|
|
vmwaredisable,
|
|
vmwareload,
|
|
vmwaremove,
|
|
};
|