2011-03-30 12:46:40 +00:00
|
|
|
/*
|
|
|
|
* vga driver using just vesa bios to set up.
|
|
|
|
*/
|
|
|
|
#include "u.h"
|
|
|
|
#include "../port/lib.h"
|
|
|
|
#include "mem.h"
|
|
|
|
#include "dat.h"
|
|
|
|
#include "fns.h"
|
|
|
|
#include "io.h"
|
|
|
|
#include "../port/error.h"
|
2014-02-01 09:14:41 +00:00
|
|
|
|
|
|
|
#define Ureg Ureg386
|
|
|
|
#include "/386/include/ureg.h"
|
|
|
|
typedef struct Ureg386 Ureg386;
|
2011-03-30 12:46:40 +00:00
|
|
|
|
|
|
|
#define Image IMAGE
|
|
|
|
#include <draw.h>
|
|
|
|
#include <memdraw.h>
|
|
|
|
#include <cursor.h>
|
|
|
|
#include "screen.h"
|
|
|
|
|
|
|
|
enum {
|
2011-08-23 03:33:51 +00:00
|
|
|
Cdisable = 0,
|
|
|
|
Cenable,
|
|
|
|
Cblank,
|
2011-11-05 05:54:48 +00:00
|
|
|
|
|
|
|
RealModeBuf = 0x9000,
|
2011-03-30 12:46:40 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static uchar modebuf[0x1000];
|
2011-08-23 03:33:51 +00:00
|
|
|
static Chan *creg, *cmem;
|
|
|
|
static QLock vesaq;
|
|
|
|
static Rendez vesar;
|
|
|
|
static int vesactl;
|
2011-03-30 12:46:40 +00:00
|
|
|
|
|
|
|
#define WORD(p) ((p)[0] | ((p)[1]<<8))
|
|
|
|
#define LONG(p) ((p)[0] | ((p)[1]<<8) | ((p)[2]<<16) | ((p)[3]<<24))
|
|
|
|
#define PWORD(p, v) (p)[0] = (v); (p)[1] = (v)>>8
|
|
|
|
#define PLONG(p, v) (p)[0] = (v); (p)[1] = (v)>>8; (p)[2] = (v)>>16; (p)[3] = (v)>>24
|
|
|
|
|
|
|
|
static uchar*
|
2014-02-01 09:14:41 +00:00
|
|
|
vbesetup(Ureg386 *u, int ax)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
|
|
|
memset(modebuf, 0, sizeof modebuf);
|
|
|
|
memset(u, 0, sizeof *u);
|
|
|
|
u->ax = ax;
|
2011-11-05 05:54:48 +00:00
|
|
|
u->es = (RealModeBuf>>4)&0xF000;
|
|
|
|
u->di = RealModeBuf&0xFFFF;
|
2011-03-30 12:46:40 +00:00
|
|
|
return modebuf;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2014-02-01 09:14:41 +00:00
|
|
|
vbecall(Ureg386 *u)
|
2011-03-30 12:46:40 +00:00
|
|
|
{
|
2011-11-05 05:54:48 +00:00
|
|
|
if(devtab[cmem->type]->write(cmem, modebuf, sizeof(modebuf), RealModeBuf) != sizeof(modebuf))
|
2011-04-11 20:56:59 +00:00
|
|
|
error("write modebuf");
|
|
|
|
u->trap = 0x10;
|
|
|
|
if(devtab[creg->type]->write(creg, u, sizeof(*u), 0) != sizeof(*u))
|
|
|
|
error("write ureg");
|
|
|
|
if(devtab[creg->type]->read(creg, u, sizeof(*u), 0) != sizeof(*u))
|
|
|
|
error("read ureg");
|
2011-03-30 12:46:40 +00:00
|
|
|
if((u->ax&0xFFFF) != 0x004F)
|
|
|
|
error("vesa bios error");
|
2011-11-05 05:54:48 +00:00
|
|
|
if(devtab[cmem->type]->read(cmem, modebuf, sizeof(modebuf), RealModeBuf) != sizeof(modebuf))
|
2011-04-11 20:56:59 +00:00
|
|
|
error("read modebuf");
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
vbecheck(void)
|
|
|
|
{
|
2014-02-01 09:14:41 +00:00
|
|
|
Ureg386 u;
|
2011-03-30 12:46:40 +00:00
|
|
|
uchar *p;
|
|
|
|
|
|
|
|
p = vbesetup(&u, 0x4F00);
|
|
|
|
strcpy((char*)p, "VBE2");
|
|
|
|
vbecall(&u);
|
|
|
|
if(memcmp((char*)p, "VESA", 4) != 0)
|
|
|
|
error("bad vesa signature");
|
|
|
|
if(p[5] < 2)
|
|
|
|
error("bad vesa version");
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
vbegetmode(void)
|
|
|
|
{
|
2014-02-01 09:14:41 +00:00
|
|
|
Ureg386 u;
|
2011-03-30 12:46:40 +00:00
|
|
|
|
|
|
|
vbesetup(&u, 0x4F03);
|
|
|
|
vbecall(&u);
|
|
|
|
return u.bx;
|
|
|
|
}
|
|
|
|
|
|
|
|
static uchar*
|
|
|
|
vbemodeinfo(int mode)
|
|
|
|
{
|
|
|
|
uchar *p;
|
2014-02-01 09:14:41 +00:00
|
|
|
Ureg386 u;
|
2011-03-30 12:46:40 +00:00
|
|
|
|
|
|
|
p = vbesetup(&u, 0x4F01);
|
|
|
|
u.cx = mode;
|
|
|
|
vbecall(&u);
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
vesalinear(VGAscr *scr, int, int)
|
|
|
|
{
|
|
|
|
int i, mode, size, havesize;
|
|
|
|
ulong paddr;
|
|
|
|
Pcidev *pci;
|
2011-11-05 04:16:50 +00:00
|
|
|
uchar *p;
|
2011-03-30 12:46:40 +00:00
|
|
|
|
|
|
|
vbecheck();
|
|
|
|
mode = vbegetmode();
|
|
|
|
/*
|
|
|
|
* bochs loses the top bits - cannot use this
|
|
|
|
if((mode&(1<<14)) == 0)
|
|
|
|
error("not in linear graphics mode");
|
|
|
|
*/
|
|
|
|
mode &= 0x3FFF;
|
|
|
|
p = vbemodeinfo(mode);
|
|
|
|
if(!(WORD(p+0) & (1<<4)))
|
|
|
|
error("not in VESA graphics mode");
|
|
|
|
if(!(WORD(p+0) & (1<<7)))
|
|
|
|
error("not in linear graphics mode");
|
|
|
|
|
|
|
|
paddr = LONG(p+40);
|
|
|
|
size = WORD(p+20)*WORD(p+16);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* figure out max size of memory so that we have
|
|
|
|
* enough if the screen is resized.
|
|
|
|
*/
|
|
|
|
pci = nil;
|
|
|
|
havesize = 0;
|
|
|
|
while(!havesize && (pci = pcimatch(pci, 0, 0)) != nil){
|
|
|
|
if(pci->ccrb != Pcibcdisp)
|
|
|
|
continue;
|
2011-11-26 20:24:01 +00:00
|
|
|
for(i=0; i<nelem(pci->mem); i++){
|
|
|
|
ulong a, e;
|
|
|
|
|
2013-01-06 22:39:02 +00:00
|
|
|
if(pci->mem[i].bar&1) /* not memory */
|
|
|
|
continue;
|
2011-11-26 20:24:01 +00:00
|
|
|
a = pci->mem[i].bar & ~0xF;
|
|
|
|
e = a + pci->mem[i].size;
|
|
|
|
if(paddr >= a && (paddr+size) <= e){
|
|
|
|
size = e - paddr;
|
2011-03-30 12:46:40 +00:00
|
|
|
havesize = 1;
|
|
|
|
break;
|
|
|
|
}
|
2011-11-26 20:24:01 +00:00
|
|
|
}
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* no pci - heuristic guess */
|
2011-11-26 20:24:01 +00:00
|
|
|
if(!havesize)
|
2011-03-30 12:46:40 +00:00
|
|
|
if(size < 4*1024*1024)
|
|
|
|
size = 4*1024*1024;
|
|
|
|
else
|
|
|
|
size = ROUND(size, 1024*1024);
|
|
|
|
|
|
|
|
vgalinearaddr(scr, paddr, size);
|
|
|
|
if(scr->apsize)
|
|
|
|
addvgaseg("vesascreen", scr->paddr, scr->apsize);
|
|
|
|
|
2012-07-18 08:16:00 +00:00
|
|
|
scr->softscreen = 1;
|
2011-03-30 12:46:40 +00:00
|
|
|
}
|
|
|
|
|
2011-08-23 03:33:51 +00:00
|
|
|
static int
|
2013-07-07 19:02:46 +00:00
|
|
|
gotctl(void *arg)
|
2011-08-23 03:33:51 +00:00
|
|
|
{
|
2013-07-07 19:02:46 +00:00
|
|
|
return vesactl != *((int*)arg);
|
2011-08-23 03:33:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
vesaproc(void*)
|
|
|
|
{
|
2014-02-01 09:14:41 +00:00
|
|
|
Ureg386 u;
|
2013-07-07 19:02:46 +00:00
|
|
|
int ctl;
|
2011-08-23 03:33:51 +00:00
|
|
|
|
2013-07-07 19:02:46 +00:00
|
|
|
ctl = Cenable;
|
|
|
|
while(ctl != Cdisable){
|
2011-08-23 03:33:51 +00:00
|
|
|
if(!waserror()){
|
2013-07-07 19:02:46 +00:00
|
|
|
sleep(&vesar, gotctl, &ctl);
|
|
|
|
ctl = vesactl;
|
2011-08-23 04:03:54 +00:00
|
|
|
|
2014-12-26 15:10:45 +00:00
|
|
|
vbesetup(&u, 0x4f10);
|
|
|
|
if(ctl == Cblank)
|
|
|
|
u.bx = 0x0101;
|
|
|
|
else
|
|
|
|
u.bx = 0x0001;
|
2012-08-01 20:56:58 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* dont wait forever here. some BIOS get stuck
|
|
|
|
* in i/o poll loop after blank/unblank for some
|
|
|
|
* reason. (Thinkpad A22p)
|
|
|
|
*/
|
|
|
|
procalarm(10000);
|
2011-08-23 03:33:51 +00:00
|
|
|
vbecall(&u);
|
2011-08-23 04:03:54 +00:00
|
|
|
|
2011-08-23 03:33:51 +00:00
|
|
|
poperror();
|
|
|
|
}
|
2012-08-01 20:56:58 +00:00
|
|
|
procalarm(0);
|
|
|
|
up->notepending = 0;
|
2011-08-23 03:33:51 +00:00
|
|
|
}
|
|
|
|
cclose(cmem);
|
|
|
|
cclose(creg);
|
|
|
|
cmem = creg = nil;
|
|
|
|
qunlock(&vesaq);
|
|
|
|
|
|
|
|
pexit("", 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
vesaenable(VGAscr *)
|
|
|
|
{
|
|
|
|
eqlock(&vesaq);
|
|
|
|
if(waserror()){
|
|
|
|
qunlock(&vesaq);
|
|
|
|
nexterror();
|
|
|
|
}
|
|
|
|
cmem = namec("/dev/realmodemem", Aopen, ORDWR, 0);
|
|
|
|
if(waserror()){
|
|
|
|
cclose(cmem);
|
|
|
|
cmem = nil;
|
|
|
|
nexterror();
|
|
|
|
}
|
|
|
|
creg = namec("/dev/realmode", Aopen, ORDWR, 0);
|
|
|
|
poperror();
|
|
|
|
poperror();
|
|
|
|
|
|
|
|
vesactl = Cenable;
|
|
|
|
kproc("vesa", vesaproc, nil);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
vesadisable(VGAscr *)
|
|
|
|
{
|
|
|
|
vesactl = Cdisable;
|
|
|
|
wakeup(&vesar);
|
2011-08-23 04:11:16 +00:00
|
|
|
|
|
|
|
/* wait for vesaproc to finish */
|
|
|
|
qlock(&vesaq);
|
|
|
|
qunlock(&vesaq);
|
2011-08-23 03:33:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
vesablank(VGAscr *, int blank)
|
|
|
|
{
|
|
|
|
if(vesactl != Cdisable){
|
|
|
|
vesactl = blank ? Cblank : Cenable;
|
|
|
|
wakeup(&vesar);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
vesadrawinit(VGAscr *scr)
|
|
|
|
{
|
|
|
|
scr->blank = vesablank;
|
|
|
|
}
|
|
|
|
|
2011-03-30 12:46:40 +00:00
|
|
|
VGAdev vgavesadev = {
|
|
|
|
"vesa",
|
2011-08-23 03:33:51 +00:00
|
|
|
vesaenable,
|
|
|
|
vesadisable,
|
2014-12-26 15:10:45 +00:00
|
|
|
0,
|
2011-03-30 12:46:40 +00:00
|
|
|
vesalinear,
|
2011-08-23 03:33:51 +00:00
|
|
|
vesadrawinit,
|
2011-03-30 12:46:40 +00:00
|
|
|
};
|