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-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;
|
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
|
|
|
|
|
2017-06-25 20:22:58 +00:00
|
|
|
typedef struct Vmode Vmode;
|
|
|
|
struct Vmode
|
|
|
|
{
|
|
|
|
char chan[32];
|
|
|
|
int attr; /* flags */
|
|
|
|
int bpl;
|
|
|
|
int dx, dy;
|
|
|
|
int depth;
|
|
|
|
ulong paddr;
|
|
|
|
};
|
|
|
|
|
2011-03-30 12:46:40 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2017-06-25 20:22:58 +00:00
|
|
|
static char*
|
|
|
|
vmode(Vmode *m, uchar *p)
|
|
|
|
{
|
|
|
|
m->attr = WORD(p);
|
|
|
|
if(!(m->attr & (1<<4)))
|
|
|
|
return "not in VESA graphics mode";
|
|
|
|
if(!(m->attr & (1<<7)))
|
|
|
|
return "not in linear graphics mode";
|
|
|
|
m->bpl = WORD(p+16);
|
|
|
|
m->dx = WORD(p+18);
|
|
|
|
m->dy = WORD(p+20);
|
|
|
|
m->depth = p[25];
|
|
|
|
m->paddr = LONG(p+40);
|
|
|
|
if(m->depth <= 8)
|
|
|
|
snprint(m->chan, sizeof m->chan, "%c%d",
|
|
|
|
(m->attr & (1<<3)) ? 'm' : 'k', m->depth);
|
|
|
|
else
|
|
|
|
rgbmask2chan(m->chan, m->depth,
|
|
|
|
(1UL<<p[31])-1 << p[32],
|
|
|
|
(1UL<<p[33])-1 << p[34],
|
|
|
|
(1UL<<p[35])-1 << p[36]);
|
|
|
|
return nil;
|
|
|
|
}
|
|
|
|
|
2011-03-30 12:46:40 +00:00
|
|
|
static void
|
|
|
|
vesalinear(VGAscr *scr, int, int)
|
|
|
|
{
|
|
|
|
int i, mode, size, havesize;
|
|
|
|
Pcidev *pci;
|
2017-06-25 20:22:58 +00:00
|
|
|
char *err;
|
|
|
|
Vmode m;
|
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;
|
2017-06-25 20:22:58 +00:00
|
|
|
if((err = vmode(&m, vbemodeinfo(mode))) != nil)
|
|
|
|
error(err);
|
2011-03-30 12:46:40 +00:00
|
|
|
|
2017-06-25 20:22:58 +00:00
|
|
|
size = m.dy * m.bpl;
|
2011-03-30 12:46:40 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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;
|
2017-06-25 20:22:58 +00:00
|
|
|
if(m.paddr >= a && (m.paddr+size) <= e){
|
|
|
|
size = e - m.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);
|
|
|
|
|
2017-06-25 20:22:58 +00:00
|
|
|
vgalinearaddr(scr, m.paddr, size);
|
2011-03-30 12:46:40 +00:00
|
|
|
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 void
|
|
|
|
vesaenable(VGAscr *)
|
|
|
|
{
|
|
|
|
cmem = namec("/dev/realmodemem", Aopen, ORDWR, 0);
|
|
|
|
if(waserror()){
|
|
|
|
cclose(cmem);
|
|
|
|
cmem = nil;
|
|
|
|
nexterror();
|
|
|
|
}
|
|
|
|
creg = namec("/dev/realmode", Aopen, ORDWR, 0);
|
|
|
|
poperror();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
vesadisable(VGAscr *)
|
|
|
|
{
|
2015-01-02 14:29:15 +00:00
|
|
|
if(cmem != nil)
|
|
|
|
cclose(cmem);
|
|
|
|
if(creg != nil)
|
|
|
|
cclose(creg);
|
|
|
|
cmem = creg = nil;
|
2011-08-23 03:33:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
vesablank(VGAscr *, int blank)
|
|
|
|
{
|
2015-01-02 14:29:15 +00:00
|
|
|
Ureg386 u;
|
|
|
|
|
|
|
|
vbesetup(&u, 0x4f10);
|
|
|
|
u.bx = blank ? 0x0101 : 0x0001;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* dont wait forever when called from mouse kproc.
|
|
|
|
* some BIOS get stuck in i/o poll loop after
|
|
|
|
* blank/unblank for some reason. (Thinkpad A22p)
|
|
|
|
*/
|
|
|
|
if(up->kp)
|
|
|
|
procalarm(10000);
|
|
|
|
|
|
|
|
if(!waserror()){
|
|
|
|
vbecall(&u);
|
|
|
|
poperror();
|
|
|
|
}
|
|
|
|
|
|
|
|
if(up->kp){
|
|
|
|
procalarm(0);
|
|
|
|
up->notepending = 0;
|
2011-08-23 03:33:51 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
};
|
2017-06-25 20:22:58 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* called from multibootargs() to convert
|
|
|
|
* vbe mode info (passed from bootloader)
|
|
|
|
* to *bootscreen= parameter
|
|
|
|
*/
|
|
|
|
char*
|
|
|
|
vesabootscreenconf(char *s, char *e, uchar *p)
|
|
|
|
{
|
|
|
|
Vmode m;
|
|
|
|
|
|
|
|
if(vmode(&m, p) != nil)
|
|
|
|
return s;
|
|
|
|
return seprint(s, e, "*bootscreen=%dx%dx%d %s %#lux\n",
|
|
|
|
m.bpl * 8 / m.depth, m.dy, m.depth, m.chan, m.paddr);
|
|
|
|
}
|