vmx: VESA support and other misc I/O improvements
This commit is contained in:
parent
31d14c316a
commit
cbcd9b1d71
11 changed files with 1160 additions and 133 deletions
|
@ -44,6 +44,14 @@ struct PCIBar {
|
|||
void *aux;
|
||||
};
|
||||
|
||||
enum {
|
||||
/* type */
|
||||
BARIO = 1,
|
||||
BARMEM32 = 0,
|
||||
BARMEM64 = 4,
|
||||
BARPREF = 8,
|
||||
};
|
||||
|
||||
struct PCIDev {
|
||||
u32int bdf, viddid, clrev, subid;
|
||||
u16int ctrl;
|
||||
|
@ -67,3 +75,11 @@ enum {
|
|||
IRQLTOGGLE = -1,
|
||||
IRQLLOHI = -2,
|
||||
};
|
||||
|
||||
typedef struct VgaMode VgaMode;
|
||||
struct VgaMode {
|
||||
u16int no;
|
||||
int w, h, hbytes, sz;
|
||||
u32int chan;
|
||||
VgaMode *next;
|
||||
};
|
||||
|
|
|
@ -61,6 +61,8 @@ stepmmio(uvlong pa, uvlong *val, int size, ExitInfo *ei)
|
|||
|
||||
extern u32int io(int, u16int, u32int, int);
|
||||
|
||||
u32int iodebug[32];
|
||||
|
||||
static void
|
||||
iohandler(ExitInfo *ei)
|
||||
{
|
||||
|
@ -88,7 +90,11 @@ iohandler(ExitInfo *ei)
|
|||
if(len == 1) ax = (u8int) ax;
|
||||
else if(len == 2) ax = (u16int) ax;
|
||||
io(0, port, ax, len);
|
||||
SET(val);
|
||||
}
|
||||
if(port < 0x400 && (iodebug[port >> 5] >> (port & 31) & 1) != 0)
|
||||
if(isin) vmdebug("in %#.4ux <- %#ux", port, val);
|
||||
else vmdebug("out %#.4ux <- %#ux", port, (int)ax);
|
||||
skipinstr(ei);
|
||||
}
|
||||
|
||||
|
@ -232,7 +238,7 @@ cpuid(ExitInfo *ei)
|
|||
ax = cp->ax;
|
||||
bx = cp->bx & 0xffff;
|
||||
cx = cp->cx & 0x60de2203;
|
||||
dx = cp->dx & 0x0682a179;
|
||||
dx = cp->dx & 0x0782a179;
|
||||
break;
|
||||
case 2: goto literal; /* cache stuff */
|
||||
case 3: goto zero; /* processor serial number */
|
||||
|
|
|
@ -5,6 +5,8 @@ void rpoke(char *, uvlong, int);
|
|||
#define rset(a,b) rpoke(a,b,0)
|
||||
void processexit(char *);
|
||||
void pitadvance(void);
|
||||
void rtcadvance(void);
|
||||
void settimer(vlong targ);
|
||||
void vmerror(char *, ...);
|
||||
#define vmdebug vmerror
|
||||
int ctl(char *, ...);
|
||||
|
@ -16,7 +18,7 @@ void vgaresize(void);
|
|||
void uartinit(int, char *);
|
||||
void sendnotif(void (*)(void *), void *);
|
||||
PCIDev *mkpcidev(u32int, u32int, u32int, int);
|
||||
PCIBar *mkpcibar(PCIDev *, u8int, u32int, void *, void *);
|
||||
PCIBar *mkpcibar(PCIDev *, u8int, u32int, u32int, void *, void *);
|
||||
PCICap *mkpcicap(PCIDev *, u8int, u32int (*)(PCICap *, u8int), void(*)(PCICap *, u8int, u32int, u32int));
|
||||
u32int allocbdf(void);
|
||||
void *gptr(u64int, u64int);
|
||||
|
@ -38,3 +40,6 @@ void i8042kick(void *);
|
|||
#define PUT16(p,n,v) (*(u16int*)((u8int*)(p)+(n)) = (v))
|
||||
#define PUT32(p,n,v) (*(u32int*)((u8int*)(p)+(n)) = (v))
|
||||
#define PUT64(p,n,v) (*(u64int*)((u8int*)(p)+(n)) = (v))
|
||||
u32int roundpow2(u32int);
|
||||
u32int vgagetpal(u8int);
|
||||
void vgasetpal(u8int, u32int);
|
||||
|
|
|
@ -7,10 +7,60 @@
|
|||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
|
||||
static uchar cmos[0x30] = {
|
||||
[1] 0xff, [3] 0xff, [5] 0xff,
|
||||
[0xa] 0x26,
|
||||
[0xb] 1<<1,
|
||||
[0xd] 1<<7, /* cmos valid */
|
||||
[0xf] 0x56, /* cmos tests pass */
|
||||
[0x11] 0x80, /* mouse enabled */
|
||||
[0x14] 0x2e, /* cga 80-column */
|
||||
[0x2d] 0x1c, /* caches + fpu enabled */
|
||||
};
|
||||
static vlong rtcnext = -1;
|
||||
|
||||
static uchar
|
||||
bcd(uchar c)
|
||||
bcd(uchar m, uchar c)
|
||||
{
|
||||
return c / 10 << 4 | c % 10;
|
||||
return (m & 1) != 0 ? c : c / 10 << 4 | c % 10;
|
||||
}
|
||||
|
||||
void
|
||||
rtcadvance(void)
|
||||
{
|
||||
vlong t;
|
||||
|
||||
if(rtcnext != -1){
|
||||
t = nsec();
|
||||
if(t >= rtcnext){
|
||||
cmos[0xc] |= 0x40;
|
||||
rtcnext = -1;
|
||||
}else
|
||||
settimer(rtcnext);
|
||||
}
|
||||
irqline(8, (cmos[0xc] & cmos[0xb] & 0x70) != 0);
|
||||
}
|
||||
|
||||
static void
|
||||
rtcset(void)
|
||||
{
|
||||
vlong t, b;
|
||||
int d;
|
||||
|
||||
rtcadvance();
|
||||
if((cmos[0xa] >> 4) > 2 || (cmos[0xa] & 15) == 0 || (cmos[0xc] & 0x40) != 0){
|
||||
rtcnext = -1;
|
||||
return;
|
||||
}
|
||||
switch(cmos[0xa]){
|
||||
case 0x21: d = 12; break;
|
||||
case 0x22: d = 13; break;
|
||||
default: d = 4 + (cmos[0xa] & 0xf);
|
||||
}
|
||||
b = (1000000000ULL << d) / 1048576;
|
||||
t = nsec();
|
||||
rtcnext = t + b - t % b;
|
||||
settimer(rtcnext);
|
||||
}
|
||||
|
||||
static u32int
|
||||
|
@ -18,16 +68,7 @@ rtcio(int isin, u16int port, u32int val, int sz, void *)
|
|||
{
|
||||
static u8int addr;
|
||||
uintptr basemem, extmem;
|
||||
static uchar cmos[0x30] = {
|
||||
[1] 0xff, [3] 0xff, [5] 0xff,
|
||||
[0xa] 0x26,
|
||||
[0xb] 0,
|
||||
[0xd] 1<<7, /* cmos valid */
|
||||
[0xf] 0x56, /* cmos tests pass */
|
||||
[0x11] 0x80, /* mouse enabled */
|
||||
[0x14] 0x2e, /* cga 80-column */
|
||||
[0x2d] 0x1c, /* caches + fpu enabled */
|
||||
};
|
||||
|
||||
static int cmosinit;
|
||||
int i, s;
|
||||
Tm *tm;
|
||||
|
@ -48,24 +89,43 @@ rtcio(int isin, u16int port, u32int val, int sz, void *)
|
|||
cmos[0x2f] = s;
|
||||
cmosinit = 1;
|
||||
}
|
||||
if(sz != 1) vmerror("rtc: access size %d != 1", sz);
|
||||
val = (u8int) val;
|
||||
switch(isin << 16 | port){
|
||||
case 0x10070: return addr;
|
||||
case 0x70: addr = val; return 0;
|
||||
case 0x71:
|
||||
switch(addr){
|
||||
case 0xa: cmos[addr] = val & 0x7f; rtcset(); break;
|
||||
case 0xb: cmos[addr] = val | 2; rtcadvance(); break;
|
||||
case 0xc: case 0xd: goto no;
|
||||
default:
|
||||
if(addr < nelem(cmos))
|
||||
cmos[addr] = val;
|
||||
else no:
|
||||
vmerror("rtc: write to unknown address %#x (val=%#x)", addr, val);
|
||||
return 0;
|
||||
}
|
||||
case 0x10070: return addr;
|
||||
case 0x10071:
|
||||
tm = gmtime(time(nil));
|
||||
switch(addr){
|
||||
case 0x00: return bcd(tm->sec);
|
||||
case 0x02: return bcd(tm->min);
|
||||
case 0x04: return bcd(tm->hour);
|
||||
case 0x06: return bcd(tm->wday + 1);
|
||||
case 0x07: return bcd(tm->mday);
|
||||
case 0x08: return bcd(tm->mon + 1);
|
||||
case 0x09: return bcd(tm->year % 100);
|
||||
case 0x32: return bcd(tm->year / 100 + 19);
|
||||
case 0x00: return bcd(cmos[0xb], tm->sec);
|
||||
case 0x02: return bcd(cmos[0xb], tm->min);
|
||||
case 0x04: return bcd(cmos[0xb], tm->hour);
|
||||
case 0x06: return bcd(cmos[0xb], tm->wday + 1);
|
||||
case 0x07: return bcd(cmos[0xb], tm->mday);
|
||||
case 0x08: return bcd(cmos[0xb], tm->mon + 1);
|
||||
case 0x09: return bcd(cmos[0xb], tm->year % 100);
|
||||
case 0x0c:
|
||||
i = cmos[0xc] | ((cmos[0xc] & cmos[0xb] & 0x70) != 0) << 7;
|
||||
cmos[0xc] = 0;
|
||||
rtcset();
|
||||
return i;
|
||||
case 0x32: return bcd(cmos[0xb], tm->year / 100 + 19);
|
||||
default:
|
||||
if(addr < nelem(cmos))
|
||||
return cmos[addr];
|
||||
vmerror("rtc read from unknown address %#x", addr);
|
||||
vmerror("rtc: read from unknown address %#x", addr);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -191,7 +251,10 @@ irqack(int n)
|
|||
p = &pic[1];
|
||||
else
|
||||
return;
|
||||
if(p == &pic[1]) irqack(pic[0].base + 2);
|
||||
if(p == &pic[1]){
|
||||
irqack(pic[0].base + 2);
|
||||
irqline(2, 0);
|
||||
}
|
||||
n &= 7;
|
||||
p->irr &= ~(1<<n);
|
||||
p->isr |= 1<<n;
|
||||
|
@ -307,6 +370,7 @@ picio(int isin, u16int port, u32int val, int sz, void *)
|
|||
}
|
||||
break;
|
||||
case 0x10020:
|
||||
case 0x100a0:
|
||||
if((p->flags & READSR) != 0)
|
||||
return p->isr;
|
||||
if((p->flags & POLL) != 0){
|
||||
|
@ -322,7 +386,6 @@ picio(int isin, u16int port, u32int val, int sz, void *)
|
|||
return 0;
|
||||
}
|
||||
return p->irr;
|
||||
case 0x100a0:
|
||||
case 0x10021:
|
||||
case 0x100a1:
|
||||
return p->imr;
|
||||
|
@ -571,6 +634,7 @@ struct I8042 {
|
|||
.cmd -1,
|
||||
};
|
||||
Channel *kbdch, *mousech;
|
||||
u8int mouseactive;
|
||||
typedef struct PCKeyb PCKeyb;
|
||||
struct PCKeyb {
|
||||
u8int buf[64];
|
||||
|
@ -632,7 +696,7 @@ kbdcmd(u8int val)
|
|||
if(val == 0) keyputc(1);
|
||||
kbd.actcmd = 0;
|
||||
break;
|
||||
case 0x3d: /* set leds */
|
||||
case 0xed: /* set leds */
|
||||
keyputc(0xfa);
|
||||
kbd.actcmd = 0;
|
||||
break;
|
||||
|
@ -684,8 +748,8 @@ mousepacket(int force)
|
|||
dx = mouse.xy.x;
|
||||
dy = -mouse.xy.y;
|
||||
b0 = 8;
|
||||
if((ulong)(dx + 256) > 511) dx = dx >> 31 & 0x1ff ^ 0xff;
|
||||
if((ulong)(dy + 256) > 511) dy = dy >> 31 & 0x1ff ^ 0xff;
|
||||
if((ulong)(dx + 256) > 511) dx = dx >> 31 ^ 0xff;
|
||||
if((ulong)(dy + 256) > 511) dy = dy >> 31 ^ 0xff;
|
||||
b0 |= dx >> 5 & 0x10 | dy >> 4 & 0x20;
|
||||
b0 |= (mouse.buttons * 0x111 & 0x421) % 7;
|
||||
mouseputc(b0);
|
||||
|
@ -693,7 +757,7 @@ mousepacket(int force)
|
|||
mouseputc((u8int)dy);
|
||||
mouse.xy.x -= dx;
|
||||
mouse.xy.y += dy;
|
||||
mouse.gotmouse = 0;
|
||||
mouse.gotmouse = mouse.xy.x != 0 || mouse.xy.y != 0;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -796,7 +860,7 @@ i8042io(int isin, u16int port, u32int val, int sz, void *)
|
|||
case 0x60:
|
||||
i8042.stat &= ~8;
|
||||
switch(i8042.cmd){
|
||||
case 0x60: i8042.cfg = val; break;
|
||||
case 0x60: i8042.cfg = val; mouseactive = (val & 0x20) == 0; break;
|
||||
case 0xd1:
|
||||
i8042.oport = val;
|
||||
irqline(1, i8042.oport >> 4 & 1);
|
||||
|
@ -819,8 +883,8 @@ i8042io(int isin, u16int port, u32int val, int sz, void *)
|
|||
switch(val){
|
||||
case 0x20: i8042putbuf(0x400 | i8042.cfg); return 0;
|
||||
case 0xa1: i8042putbuf(0x4f1); return 0; /* no keyboard password */
|
||||
case 0xa7: i8042.cfg |= 1<<5; return 0;
|
||||
case 0xa8: i8042.cfg &= ~(1<<5); return 0;
|
||||
case 0xa7: i8042.cfg |= 1<<5; mouseactive = 0; return 0;
|
||||
case 0xa8: i8042.cfg &= ~(1<<5); mouseactive = 1; return 0;
|
||||
case 0xa9: i8042putbuf(0x400); return 0; /* test second port */
|
||||
case 0xaa: i8042putbuf(0x455); return 0; /* test controller */
|
||||
case 0xab: i8042putbuf(0x400); return 0; /* test first port */
|
||||
|
@ -1111,9 +1175,9 @@ u32int
|
|||
iowhine(int isin, u16int port, u32int val, int sz, void *mod)
|
||||
{
|
||||
if(isin)
|
||||
vmerror("%s%sread from unknown i/o port %#ux ignored (sz=%d)", mod != nil ? mod : "", mod != nil ? ": " : "", port, sz);
|
||||
vmerror("%s%sread from unknown i/o port %#ux ignored (sz=%d, pc=%#ullx)", mod != nil ? mod : "", mod != nil ? ": " : "", port, sz, rget(RPC));
|
||||
else
|
||||
vmerror("%s%swrite to unknown i/o port %#ux ignored (val=%#ux, sz=%d)", mod != nil ? mod : "", mod != nil ? ": " : "", port, val, sz);
|
||||
vmerror("%s%swrite to unknown i/o port %#ux ignored (val=%#ux, sz=%d, pc=%#ullx)", mod != nil ? mod : "", mod != nil ? ": " : "", port, val, sz, rget(RPC));
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -1126,6 +1190,7 @@ struct IOHandler {
|
|||
|
||||
u32int vgaio(int, u16int, u32int, int, void *);
|
||||
u32int pciio(int, u16int, u32int, int, void *);
|
||||
u32int vesaio(int, u16int, u32int, int, void *);
|
||||
IOHandler handlers[] = {
|
||||
0x20, 0x21, picio, nil,
|
||||
0x40, 0x43, pitio, nil,
|
||||
|
@ -1139,20 +1204,30 @@ IOHandler handlers[] = {
|
|||
0x3f8, 0x3ff, uartio, nil,
|
||||
0x4d0, 0x4d1, picio, nil,
|
||||
0xcf8, 0xcff, pciio, nil,
|
||||
0xfee0, 0xfeef, vesaio, nil,
|
||||
|
||||
0x170, 0x177, ideio, nil, /* ide secondary */
|
||||
0x376, 0x376, ideio, nil, /* ide secondary (aux) */
|
||||
0x1f0, 0x1f7, ideio, nil, /* ide primary */
|
||||
0x3f6, 0x3f6, ideio, nil, /* ide primary (aux) */
|
||||
0x3f0, 0x3f7, fdcio, nil, /* floppy */
|
||||
|
||||
0x061, 0x061, nopio, nil, /* pc speaker */
|
||||
0x084, 0x084, nopio, nil, /* dma -- used by openbsd for delay by dummy read */
|
||||
0x100, 0x110, nopio, nil, /* elnk3 */
|
||||
0x240, 0x25f, nopio, nil, /* ne2000 */
|
||||
0x279, 0x279, nopio, nil, /* isa pnp */
|
||||
0x280, 0x28f, nopio, nil, /* 8003 */
|
||||
0x280, 0x29f, nopio, nil, /* ne2000 */
|
||||
0x2e8, 0x2ef, nopio, nil, /* COM4 */
|
||||
0x300, 0x31f, nopio, nil, /* ne2000 */
|
||||
0x320, 0x32f, nopio, nil, /* etherexpress */
|
||||
0x330, 0x33f, nopio, nil, /* uha scsi */
|
||||
0x340, 0x35f, nopio, nil, /* adaptec scsi */
|
||||
0x360, 0x373, nopio, nil, /* isolan */
|
||||
0x378, 0x37a, nopio, nil, /* LPT1 */
|
||||
0x3e0, 0x3e3, nopio, nil, /* cardbus */
|
||||
0x3e0, 0x3e5, nopio, nil, /* cardbus or isa pci bridges */
|
||||
0x3e8, 0x3ef, nopio, nil, /* COM3 */
|
||||
0x650, 0x65f, nopio, nil, /* 3c503 ethernet */
|
||||
0x778, 0x77a, nopio, nil, /* LPT1 (ECP) */
|
||||
0xa79, 0xa79, nopio, nil, /* isa pnp */
|
||||
};
|
||||
|
|
|
@ -221,7 +221,7 @@ elff(uchar **p, uchar *e, int sz)
|
|||
if(sz == -1)
|
||||
sz = elf64 ? 8 : 4;
|
||||
if(*p + sz > e){
|
||||
print("out of bounds: %p > %p", *p + sz, e);
|
||||
fprint(2, "out of bounds: %p > %p", *p + sz, e);
|
||||
return 0;
|
||||
}
|
||||
switch(sz){
|
||||
|
@ -558,11 +558,12 @@ obsdargs(void)
|
|||
uvlong s, e;
|
||||
|
||||
obsdstart(BOOTARG_MEMMAP);
|
||||
obsdpack("vvi", (uvlong)0, (uvlong)0xa0000, BIOS_MAP_FREE);
|
||||
for(r = mmap; r != nil; r = r->next){
|
||||
s = r->start;
|
||||
e = r->end;
|
||||
if(s < (1<<20)) s = 1<<20;
|
||||
if(e <= s) continue;
|
||||
if(e <= s || r->type == REGFB) continue;
|
||||
obsdpack("vvi", s, e - s, isusermem(r) ? BIOS_MAP_FREE : BIOS_MAP_RES);
|
||||
}
|
||||
obsdpack("vvi", 0ULL, 0ULL, BIOS_MAP_END);
|
||||
|
|
|
@ -11,5 +11,6 @@ OFILES=\
|
|||
vga.$O \
|
||||
pci.$O \
|
||||
virtio.$O \
|
||||
vesa.$O \
|
||||
|
||||
</sys/src/cmd/mkone
|
||||
|
|
|
@ -37,8 +37,20 @@ allocbdf(void)
|
|||
return BDF(0, dev++, 0);
|
||||
}
|
||||
|
||||
u32int
|
||||
roundpow2(u32int l)
|
||||
{
|
||||
l = -l;
|
||||
l &= (int)l >> 16;
|
||||
l &= (int)l >> 8;
|
||||
l &= (int)l >> 4;
|
||||
l &= (int)l >> 2;
|
||||
l &= (int)l >> 1;
|
||||
return -l;
|
||||
}
|
||||
|
||||
PCIBar *
|
||||
mkpcibar(PCIDev *d, u8int t, u32int l, void *fn, void *aux)
|
||||
mkpcibar(PCIDev *d, u8int t, u32int a, u32int l, void *fn, void *aux)
|
||||
{
|
||||
PCIBar *b;
|
||||
|
||||
|
@ -46,16 +58,14 @@ mkpcibar(PCIDev *d, u8int t, u32int l, void *fn, void *aux)
|
|||
assert((t & 1) != 0 || (t & 6) == 0);
|
||||
if((t & 1) != 0 && l < 4) l = 4;
|
||||
if((t & 1) == 0 && l < 4096) l = 4096;
|
||||
if((l & l-1) != 0){
|
||||
do
|
||||
l &= l-1;
|
||||
while((l & l-1) == 0);
|
||||
l <<= 1;
|
||||
assert(l != 0);
|
||||
}
|
||||
if((l & l-1) != 0)
|
||||
l = roundpow2(l);
|
||||
for(b = d->bar; b < d->bar + nelem(d->bar); b++)
|
||||
if(b->length == 0)
|
||||
break;
|
||||
if(b == d->bar + nelem(d->bar))
|
||||
sysfatal("pci bdf %6ux: too many bars", d->bdf);
|
||||
b->addr = a;
|
||||
b->type = t;
|
||||
b->length = l;
|
||||
b->busnext = b;
|
||||
|
@ -207,6 +217,7 @@ pciwrite(PCIDev *d, int addr, u32int val, u32int mask)
|
|||
d->bar[n].addr = (d->bar[n].addr & ~mask | val & mask) & ~(d->bar[n].length - 1);
|
||||
updatebar(&d->bar[n]);
|
||||
return;
|
||||
case 0x30: return;
|
||||
case 0x3c: d->irqno = (d->irqno & ~mask | val & mask) & 0xff; pciirqupdate(); return;
|
||||
}
|
||||
c = findpcicap(d, addr);
|
||||
|
@ -275,7 +286,7 @@ pcibusmap(void)
|
|||
for(d = pcidevs; d != nil; d = d->next){
|
||||
d->ctrl |= 3;
|
||||
for(b = d->bar; b < d->bar + nelem(d->bar); b++){
|
||||
if(b->length == 0)
|
||||
if(b->length == 0 || b->addr != 0)
|
||||
continue;
|
||||
if((b->type & 1) == 0){
|
||||
vmerror("pci device %.6ux: memory bars unsupported", d->bdf);
|
||||
|
|
718
sys/src/cmd/vmx/vesa.c
Normal file
718
sys/src/cmd/vmx/vesa.c
Normal file
|
@ -0,0 +1,718 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
#include <thread.h>
|
||||
#include <draw.h>
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
|
||||
static uchar vesabios[512] = {
|
||||
0x55, 0xaa, 0x01, 0xcb, 0x60, 0x1e, 0x06, 0x8c, 0xd0, 0xba, 0xe0, 0xfe, 0xef, 0x89, 0xe0, 0xba, 0xe1, 0xfe, 0xef, 0xba, 0xe2, 0xfe, 0xed, 0x85, 0xc0, 0x7c, 0x28, 0x50, 0x25, 0x00,
|
||||
0xf0, 0x8e, 0xc0, 0xba, 0xe3, 0xfe, 0xed, 0x89, 0xc6, 0xc3, 0x26, 0x8b, 0x04, 0xba, 0xe4, 0xfe, 0xef, 0xeb, 0xe2, 0xba, 0xe4, 0xfe, 0xed, 0x26, 0x89, 0x04, 0xeb, 0xd9, 0xba, 0xe4,
|
||||
0xfe, 0xed, 0x26, 0x88, 0x04, 0xeb, 0xd0, 0x58, 0x58, 0x61, 0xcf,
|
||||
};
|
||||
enum {
|
||||
READCMD = 0x28,
|
||||
WRITEWCMD = 0x31,
|
||||
WRITEBCMD = 0x3a,
|
||||
};
|
||||
typedef struct VESAIO VESAIO;
|
||||
struct VESAIO {
|
||||
u8int port;
|
||||
u16int val;
|
||||
};
|
||||
Channel *vesawchan, *vesarchan;
|
||||
typedef struct Ureg16 Ureg16;
|
||||
struct Ureg16 {
|
||||
u16int ax, bx, cx, dx;
|
||||
u16int si, di, bp;
|
||||
u16int ds, es;
|
||||
};
|
||||
#define ESDI(u) ((u).di + ((u).es<<4))
|
||||
typedef struct Vesa Vesa;
|
||||
struct Vesa {
|
||||
u32int romptr;
|
||||
u32int oemstring, oemvendor, oemproduct, oemproductrev;
|
||||
u32int modetab;
|
||||
u8int pal8;
|
||||
} vesa;
|
||||
#define FARPTR(x) (((x)&0xf0000)<<12|(u16int)(x))
|
||||
extern VgaMode *modes, **modeslast, *curmode, *nextmode, textmode;
|
||||
extern int curhbytes, nexthbytes;
|
||||
extern uintptr fbaddr, fbsz;
|
||||
extern int maxw, maxh;
|
||||
enum { CMAP4 = CHAN1(CMap, 4) };
|
||||
|
||||
|
||||
static VgaMode *
|
||||
findmode(u16int m)
|
||||
{
|
||||
VgaMode *p;
|
||||
|
||||
for(p = modes; p != nil; p = p->next)
|
||||
if(p->no == m)
|
||||
return p;
|
||||
return nil;
|
||||
}
|
||||
|
||||
static int
|
||||
vesagetsp(void)
|
||||
{
|
||||
VESAIO io;
|
||||
u32int rc;
|
||||
|
||||
loop:
|
||||
while(recv(vesarchan, &io), io.port != 0)
|
||||
sendul(vesawchan, -1);
|
||||
rc = io.val << 4;
|
||||
sendul(vesawchan, -1);
|
||||
recv(vesarchan, &io);
|
||||
sendul(vesawchan, -1);
|
||||
if(io.port != 1) goto loop;
|
||||
return rc + io.val;
|
||||
}
|
||||
|
||||
static int
|
||||
vesawrite(int addr, u32int val, int sz)
|
||||
{
|
||||
VESAIO io;
|
||||
|
||||
assert(sz == 1 || sz == 2 || sz == 4);
|
||||
recv(vesarchan, &io);
|
||||
if(io.port != 0x12){
|
||||
no: sendul(vesawchan, -1);
|
||||
return -1;
|
||||
}
|
||||
sendul(vesawchan, (sz > 1 ? WRITEWCMD : WRITEBCMD) | addr >> 4 & 0xf000);
|
||||
recv(vesarchan, &io);
|
||||
if(io.port != 0x13) goto no;
|
||||
sendul(vesawchan, addr);
|
||||
recv(vesarchan, &io);
|
||||
if(io.port != 0x14) goto no;
|
||||
sendul(vesawchan, val);
|
||||
if(sz == 4)
|
||||
return vesawrite(addr + 2, val >> 16, 2);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
vesaread(int addr)
|
||||
{
|
||||
VESAIO io;
|
||||
|
||||
recv(vesarchan, &io);
|
||||
if(io.port != 0x12){
|
||||
no: sendul(vesawchan, -1);
|
||||
return -1;
|
||||
}
|
||||
sendul(vesawchan, READCMD);
|
||||
recv(vesarchan, &io);
|
||||
if(io.port != 0x13) goto no;
|
||||
sendul(vesawchan, addr);
|
||||
recv(vesarchan, &io);
|
||||
if(io.port != 0x4) goto no;
|
||||
sendul(vesawchan, -1);
|
||||
return io.val;
|
||||
}
|
||||
|
||||
static int
|
||||
vesaregs(u32int sp, Ureg16 *ur)
|
||||
{
|
||||
int rc;
|
||||
#define R(n, a) rc = vesaread(sp + n); if(rc < 0) return -1; ur->a = rc
|
||||
|
||||
memset(ur, 0, sizeof(*ur));
|
||||
R(0, es);
|
||||
R(2, ds);
|
||||
R(4, di);
|
||||
R(6, si);
|
||||
R(8, bp);
|
||||
R(12, bx);
|
||||
R(14, dx);
|
||||
R(16, cx);
|
||||
R(18, ax);
|
||||
return 0;
|
||||
#undef R
|
||||
}
|
||||
|
||||
static int
|
||||
vesasetregs(u32int sp, Ureg16 *ur)
|
||||
{
|
||||
#define R(n, a) if(vesawrite(sp + n, ur->a, 2) < 0) return -1;
|
||||
|
||||
R(0, es);
|
||||
R(2, ds);
|
||||
R(4, di);
|
||||
R(6, si);
|
||||
R(8, bp);
|
||||
R(12, bx);
|
||||
R(14, dx);
|
||||
R(16, cx);
|
||||
R(18, ax);
|
||||
return 0;
|
||||
#undef R
|
||||
}
|
||||
|
||||
#define vesasetax(sp, val) vesawrite(sp+18, val, 2)
|
||||
#define vesasetbx(sp, val) vesawrite(sp+12, val, 2)
|
||||
|
||||
static int
|
||||
vesapack(int addr, char *fmt, ...)
|
||||
{
|
||||
va_list va;
|
||||
static u8int checksum;
|
||||
int v;
|
||||
char *p;
|
||||
int numb;
|
||||
|
||||
if(addr < 0) return -1;
|
||||
numb = 0;
|
||||
va_start(va, fmt);
|
||||
for(; *fmt != 0; fmt++)
|
||||
switch(*fmt){
|
||||
case ' ': break;
|
||||
case 'b': v = va_arg(va, int); if(vesawrite(addr, v, 1) < 0) return -1; addr += 1; checksum += v; break;
|
||||
case 'w': v = va_arg(va, int); if(vesawrite(addr, v, 2) < 0) return -1; addr += 2; checksum += v + (v >> 8); break;
|
||||
case 'd': v = va_arg(va, int); if(vesawrite(addr, v, 4) < 0) return -1; addr += 4; checksum += v + (v >> 8) + (v >> 16) + (v >> 24); break;
|
||||
case 's':
|
||||
p = va_arg(va, char *);
|
||||
for(; *p != 0; p++, addr++){
|
||||
if(vesawrite(addr, *p, 1) < 0)
|
||||
return -1;
|
||||
checksum += *p;
|
||||
}
|
||||
break;
|
||||
case 'S':
|
||||
p = va_arg(va, char *);
|
||||
v = va_arg(va, int);
|
||||
while(v-- > 0){
|
||||
if(vesawrite(addr++, *p, 1) < 0)
|
||||
return -1;
|
||||
checksum += *p++;
|
||||
}
|
||||
break;
|
||||
case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
|
||||
numb = strtol(fmt, &fmt, 10);
|
||||
fmt--;
|
||||
break;
|
||||
case 'f':
|
||||
for(; numb >= 2; numb -= 2, addr += 2)
|
||||
if(vesawrite(addr, 0, 2) < 0) return -1;
|
||||
if(numb == 1){
|
||||
if(vesawrite(addr++, 0, 1) < 0) return -1;
|
||||
numb = 0;
|
||||
}
|
||||
break;
|
||||
case 'c': if(vesawrite(addr, -checksum, 1) < 0) return -1; addr += 1; break;
|
||||
case 'C': checksum = 0; break;
|
||||
default: vmerror("vesapack: unknown char %c", *fmt); return -1;
|
||||
}
|
||||
va_end(va);
|
||||
return addr;
|
||||
}
|
||||
|
||||
static int
|
||||
vesarompack(char *fmt, ...)
|
||||
{
|
||||
va_list va;
|
||||
uchar *v, *v0;
|
||||
int rc, x;
|
||||
void *s;
|
||||
|
||||
v0 = gptr(vesa.romptr, 0x8000);
|
||||
v = v0;
|
||||
assert(v != nil);
|
||||
va_start(va, fmt);
|
||||
for(; *fmt != 0; fmt++)
|
||||
switch(*fmt){
|
||||
case 'b': *(u8int*)v = va_arg(va, int); v++; break;
|
||||
case 'w': *(u16int*)v = va_arg(va, int); v += 2; break;
|
||||
case 'd': *(u32int*)v = va_arg(va, int); v += 4; break;
|
||||
case 'a': v = (uchar*)strecpy((char*)v, (char*)v + 0x8000, va_arg(va, char*)); *v++ = 0; break;
|
||||
case 'S': s = va_arg(va, void *); x = va_arg(va, int); memcpy(v, s, x); v += x; break;
|
||||
default: sysfatal("vesarompack: unknown char %c", *fmt);
|
||||
}
|
||||
va_end(va);
|
||||
rc = vesa.romptr;
|
||||
vesa.romptr += v - v0;
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int
|
||||
vesamodeget(int addr, u16int mode, u16int *retv)
|
||||
{
|
||||
VgaMode *p;
|
||||
u8int model;
|
||||
u8int nred, pred, ngreen, pgreen, nblue, pblue, nx, px;
|
||||
int i, pos, s;
|
||||
|
||||
p = findmode(mode);
|
||||
if(p == nil){
|
||||
vmerror("vesa: Return VBE Mode Information: unknown mode %#x", mode);
|
||||
*retv = 0x014F;
|
||||
return 0;
|
||||
}
|
||||
*retv = 0x004F;
|
||||
model = 6;
|
||||
nred = pred = ngreen = pgreen = 0;
|
||||
nblue = pblue = nx = px = 0;
|
||||
pos = 0;
|
||||
for(i = 0; i < 4; i++){
|
||||
s = p->chan >> 8 * i & 15;
|
||||
switch(p->chan >> 8 * i + 4 & 15){
|
||||
case CRed: nred = s; pred = pos; break;
|
||||
case CGreen: ngreen = s; pgreen = pos; break;
|
||||
case CBlue: nblue = s; pblue = pos; break;
|
||||
case CAlpha: case CIgnore: nx = s; px = pos; break;
|
||||
case CMap: model = 4; break;
|
||||
}
|
||||
pos += s;
|
||||
}
|
||||
return vesapack(addr, "wbbwwwwdw wwbbbbbbbbb bbbbbbbbb ddw wbbbbb bbbbbd 189f",
|
||||
1<<0|1<<1|1<<3|1<<4|1<<5|1<<6|1<<7, /* attributes: color graphics, vga incompatible, linear framebuffer */
|
||||
0, 0, 0, 0, 0, 0, 0, p->hbytes, /* windowing crap */
|
||||
p->w, p->h,
|
||||
0, 0, /* character size */
|
||||
1, chantodepth(p->chan), 1, /* 1 bank, 1 plane, N bpp */
|
||||
model, /* memory model */
|
||||
0, 0, 1, /* no banking/paging */
|
||||
nred, pred, ngreen, pgreen, nblue, pblue, nx, px, /* masks */
|
||||
0, /* no ramp, reserved bits are reserved */
|
||||
fbaddr,
|
||||
0, 0, /* reserved */
|
||||
p->hbytes, 0, 0,
|
||||
nred, pred, ngreen, pgreen, nblue, pblue, nx, px, /* masks */
|
||||
p->w * p->h * 60 * 2 /* max pixelclock */);
|
||||
}
|
||||
|
||||
static int
|
||||
vesamodeset(u16int mode, u16int *retv)
|
||||
{
|
||||
VgaMode *p;
|
||||
|
||||
mode &= 0x1ff;
|
||||
if(mode == 3){
|
||||
*retv = 0x04F;
|
||||
nextmode = &textmode;
|
||||
return 0;
|
||||
}
|
||||
p = findmode(mode);
|
||||
if(p == nil){
|
||||
vmerror("vesa: Set VBE Mode: unknown mode %#x", mode);
|
||||
*retv = 0x14F;
|
||||
return 0;
|
||||
}
|
||||
*retv = 0x04F;
|
||||
nextmode = p;
|
||||
nexthbytes = p->hbytes;
|
||||
vesa.pal8 = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
vesalinelen(Ureg16 *ur)
|
||||
{
|
||||
int d;
|
||||
int nhb, x;
|
||||
|
||||
d = chantodepth(nextmode->chan);
|
||||
if(nextmode == &textmode || d == 0) goto fail;
|
||||
switch(ur->bx & 0xff){
|
||||
case 0:
|
||||
nhb = d * ur->cx / 8;
|
||||
set:
|
||||
if((d & 7) != 0){
|
||||
vmerror("vesa: set logical length unsupported on bitdepth < 8");
|
||||
fail: ur->ax = 0x014F;
|
||||
return 0;
|
||||
}
|
||||
if(nhb * nextmode->h > fbsz){
|
||||
ur->ax = 0x024F;
|
||||
return 0;
|
||||
}
|
||||
nexthbytes = nhb;
|
||||
ur->ax = 0x4F;
|
||||
ur->bx = nhb;
|
||||
ur->cx = nhb * 8 / d;
|
||||
ur->dx = fbsz / nhb;
|
||||
break;
|
||||
case 1:
|
||||
ur->ax = 0x4F;
|
||||
ur->bx = nexthbytes;
|
||||
ur->cx = nexthbytes * 8 / d;
|
||||
ur->dx = fbsz / nexthbytes;
|
||||
break;
|
||||
case 2:
|
||||
nhb = ur->cx;
|
||||
goto set;
|
||||
case 3:
|
||||
x = fbsz / nextmode->h;
|
||||
ur->ax = 0x4F;
|
||||
ur->bx = x;
|
||||
ur->cx = x * 8 / d;
|
||||
ur->dx = nextmode->h;
|
||||
break;
|
||||
default:
|
||||
vmerror("vesa: unsupported subfunction %#x of SetGetLogicalLineLength", ur->bx & 0xff);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
vesapalformat(Ureg16 *ur)
|
||||
{
|
||||
switch(ur->bx & 0xff){
|
||||
case 0:
|
||||
vesa.pal8 = (ur->bx >> 8) >= 8;
|
||||
case 1:
|
||||
ur->ax = 0x4F;
|
||||
ur->bx = vesa.pal8 ? 8 : 6;
|
||||
break;
|
||||
default:
|
||||
vmerror("vesa: unsupported subfunction %#x of SetGetDACPaletteFormat", ur->bx & 0xff);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
vesapal(Ureg16 *ur)
|
||||
{
|
||||
int i;
|
||||
int addr;
|
||||
u32int c;
|
||||
int r, g, b;
|
||||
|
||||
switch(ur->bx & 0xff){
|
||||
case 0:
|
||||
case 0x80:
|
||||
if(ur->dx >= 256 || ur->cx > 256){
|
||||
ur->ax = 0x014F;
|
||||
return 0;
|
||||
}
|
||||
ur->ax = 0x4F;
|
||||
addr = ESDI(*ur);
|
||||
for(i = ur->dx; i < ur->dx + ur->cx; i++){
|
||||
b = vesaread(addr);
|
||||
if(b < 0) return -1;
|
||||
g = b >> 8;
|
||||
b = b & 0xff;
|
||||
r = vesaread(addr + 2);
|
||||
if(r < 0) return -1;
|
||||
r &= 0xff;
|
||||
if(!vesa.pal8){
|
||||
r <<= 2;
|
||||
g <<= 2;
|
||||
b <<= 2;
|
||||
}
|
||||
vgasetpal(i, r << 24 | g << 16 | b << 8 | 0xff);
|
||||
addr += 4;
|
||||
}
|
||||
break;
|
||||
case 0x1:
|
||||
if(ur->dx >= 256 || ur->cx > 256){
|
||||
ur->ax = 0x014F;
|
||||
return 0;
|
||||
}
|
||||
ur->ax = 0x4F;
|
||||
addr = ESDI(*ur);
|
||||
for(i = ur->dx; i < ur->dx + ur->cx; i++){
|
||||
c = vgagetpal(i);
|
||||
r = c >> 24; g = c >> 16; b = c >> 8;
|
||||
if(!vesa.pal8){
|
||||
r >>= 2;
|
||||
g >>= 2;
|
||||
b >>= 2;
|
||||
}
|
||||
addr = vesapack(addr, "bbbb", b, g, r, 0);
|
||||
}
|
||||
return addr >= 0 ? 0 : -1;
|
||||
default:
|
||||
vmerror("vesa: unsupported subfunction %#x of SetGetPaletteData", ur->bx & 0xff);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
stdtiming(u8int *arr)
|
||||
{
|
||||
VgaMode *m;
|
||||
u8int s1, s2;
|
||||
int i;
|
||||
|
||||
memset(arr, 1, 16);
|
||||
for(m = modes; m != nil; m = m->next){
|
||||
if(m->w < 256 || m->w > 2288 || m->w > maxw || m->h > maxh) continue;
|
||||
if((m->w & 7) != 0) continue;
|
||||
if(m->w == 640 && m->h == 480) continue;
|
||||
if(m->w == 800 && m->h == 600) continue;
|
||||
if(m->w == 1024 && m->h == 768) continue;
|
||||
if(m->w == 1280 && m->h == 1024) continue;
|
||||
if(m->w * 10 == m->w * 16)
|
||||
s2 = 0x00;
|
||||
else if(m->w * 3 == m->h * 4)
|
||||
s2 = 0x40;
|
||||
else if(m->w * 4 == m->h * 5)
|
||||
s2 = 0x80;
|
||||
else if(m->w * 9 == m->w * 16)
|
||||
s2 = 0xc0;
|
||||
else
|
||||
continue;
|
||||
s1 = m->w / 8 - 31;
|
||||
for(i = 0; i < 16; i += 2){
|
||||
if(arr[i] == s1 && arr[i+1] == s2)
|
||||
goto skip;
|
||||
if(arr[i] == 1 && arr[i+1] == 1)
|
||||
break;
|
||||
}
|
||||
if(i == 16) skip: continue;
|
||||
arr[i] = s1;
|
||||
arr[i+1] = s2;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
detailtiming(int addr, VgaMode **m)
|
||||
{
|
||||
u32int hv, hfp, hsp, hbp, hmm;
|
||||
u32int vv, vfp, vsp, vbp, vmm;
|
||||
u32int freq;
|
||||
|
||||
again:
|
||||
if(*m == nil)
|
||||
return vesapack(addr, "d14f", 0x10000000);
|
||||
/* when in doubt, make shit up */
|
||||
hv = (*m)->w;
|
||||
hfp = hv / 40;
|
||||
hsp = hv * 3 / 20;
|
||||
hbp = hfp * 4 + hsp;
|
||||
vv = (*m)->h;
|
||||
vfp = (vv + 24) / 48;
|
||||
vsp = (vv + 120) / 240;
|
||||
vbp = vfp * 3 + vsp;
|
||||
freq = (hv + hfp + hsp + hbp) * (vv + vfp + vsp + vbp) * 60;
|
||||
hmm = hv * 254 / 960; /* assume 96 dpi */
|
||||
vmm = vv * 254 / 960;
|
||||
|
||||
*m = (*m)->next;
|
||||
if(hv > maxw || vv > maxh || hv > 0xfff || hfp > 0x3ff || hsp > 0x3ff || vfp > 63 || vsp > 63)
|
||||
goto again;
|
||||
return vesapack(addr, "w bbbbbbbbbb bbbbb b",
|
||||
freq / 10000,
|
||||
hv, hbp, hv >> 4 & 0xf0 | hbp >> 8 & 0xf,
|
||||
vv, vbp, vv >> 4 & 0xf0 | vbp >> 8 & 0xf,
|
||||
hfp, hsp,
|
||||
vfp << 4 & 0xf0 | vsp & 0xf,
|
||||
hfp >> 2 & 0xc0 | hsp >> 4 & 0x30 | vfp >> 2 & 0x0c | vsp >> 4 & 0x03,
|
||||
hmm, vmm,
|
||||
hmm >> 4 & 0xf0 | vmm >> 8 & 0xf,
|
||||
0, 0, 0x1f);
|
||||
|
||||
}
|
||||
|
||||
static int
|
||||
vesaddc(Ureg16 *ur)
|
||||
{
|
||||
int addr;
|
||||
u32int tim;
|
||||
u8int std[16];
|
||||
VgaMode *m;
|
||||
|
||||
switch(ur->bx & 0xff){
|
||||
case 0:
|
||||
ur->ax = 0x004F;
|
||||
ur->bx = 3;
|
||||
break;
|
||||
case 1:
|
||||
addr = ESDI(*ur);
|
||||
stdtiming(std);
|
||||
switch(ur->dx){
|
||||
case 0:
|
||||
ur->ax = 0x004F;
|
||||
tim = 0;
|
||||
if(maxw >= 640 && maxh >= 480) tim |= 0x3c;
|
||||
if(maxw >= 800 && maxh >= 600) tim |= 0xc003;
|
||||
if(maxw >= 1024 && maxh >= 768) tim |= 0xe00;
|
||||
if(maxw >= 1280 && maxh >= 1024) tim |= 0x100;
|
||||
addr = vesapack(addr, "Cdd bbbbdbb bb bbbbb bbbbb bbbbb wb S",
|
||||
0xFFFFFF00,
|
||||
0x00FFFFFF,
|
||||
0x0c, 0x34, 0xa7, 0xac, /* manufacturer & product id */
|
||||
1701, /* serial no */
|
||||
0xff, 27, /* model year 2017 */
|
||||
1, 4, /* edid version */
|
||||
0xa1, /* DVI input */
|
||||
maxw >= maxh ? maxw * 100 / maxh - 99 : 0, /* landscape aspect ratio */
|
||||
maxw < maxh ? maxh * 100 / maxw - 99 : 0, /* portrait aspect ratio */
|
||||
0x78, /* gamma=2.2 */
|
||||
7, /* srgb & have preferred timing mode */
|
||||
0, 0, 0, 0, 0, /* chromaticity coordinates */
|
||||
0, 0, 0, 0, 0,
|
||||
tim, tim >> 16,
|
||||
std, 16);
|
||||
m = modes;
|
||||
addr = detailtiming(addr, &m);
|
||||
addr = detailtiming(addr, &m);
|
||||
addr = detailtiming(addr, &m);
|
||||
addr = vesapack(addr, "3fbb bbbb bbbb bbbbb",
|
||||
0xfd, 0xa, 1, 0xff, 1, 0xff, 0xff, 0x04, 0x11,
|
||||
maxw >> 11 & 3, maxw >> 3, 0xf8, 0x18, 0, 60);
|
||||
addr = vesapack(addr, "bc", 0);
|
||||
if(addr < 0) return -1;
|
||||
break;
|
||||
default:
|
||||
ur->ax = 0x014F;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
vmerror("vesa: unsupported subfunction %#x of VBE/DDC", ur->bx & 0xff);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
vesathread(void *)
|
||||
{
|
||||
u32int sp;
|
||||
Ureg16 ur;
|
||||
|
||||
for(;;){
|
||||
sp = vesagetsp();
|
||||
// vmdebug("SP = %.8ux", sp);
|
||||
if(vesaregs(sp, &ur) < 0) continue;
|
||||
// vmdebug("AX = %.4x BX=%.4x CX=%.4x DX=%.4x", ur.ax, ur.bx, ur.cx, ur.dx);
|
||||
// vmdebug("SI = %.4x DI=%.4x BP=%.4x", ur.si, ur.di, ur.bp);
|
||||
// vmdebug("DS = %.4x ES=%.4x", ur.ds, ur.es);
|
||||
switch(ur.ax){
|
||||
case 0x4f00:
|
||||
if(vesapack(ESDI(ur), "swdddwwddd",
|
||||
"VESA", /* VbeSignature */
|
||||
0x0300, /* VbeVersion */
|
||||
FARPTR(vesa.oemstring), /* OemStringPtr */
|
||||
1, /* Capabilities (support 8 bit colors) */
|
||||
FARPTR(vesa.modetab), /* VideoModePtr */
|
||||
fbsz >> 16, /* TotalMemory */
|
||||
0x100 /* OemSoftwareRev */,
|
||||
FARPTR(vesa.oemvendor), /* OemVendorNamePtr */
|
||||
FARPTR(vesa.oemproduct), /* OemProductNamePtr */
|
||||
FARPTR(vesa.oemproductrev) /* OemProductRevPtr */) < 0)
|
||||
continue;
|
||||
if(vesasetax(sp, 0x004F) < 0) continue;
|
||||
break;
|
||||
case 0x4f01:
|
||||
if(vesamodeget(ESDI(ur), ur.cx, &ur.ax) < 0) continue;
|
||||
if(vesasetax(sp, ur.ax) < 0) continue;
|
||||
break;
|
||||
case 0x4f02:
|
||||
if(vesamodeset(ur.bx, &ur.ax) < 0 || vesasetax(sp, ur.ax) < 0) continue;
|
||||
break;
|
||||
case 0x4f03:
|
||||
if(vesasetax(sp, 0x004F) < 0) continue;
|
||||
if(vesasetbx(sp, nextmode->no | 0x4000) < 0) continue;
|
||||
break;
|
||||
case 0x4f06:
|
||||
if(vesalinelen(&ur) < 0 || vesasetregs(sp, &ur) < 0) continue;
|
||||
break;
|
||||
case 0x4f08:
|
||||
if(vesapalformat(&ur) < 0 || vesasetregs(sp, &ur) < 0) continue;
|
||||
break;
|
||||
case 0x4f09:
|
||||
if(vesapal(&ur) < 0 || vesasetregs(sp, &ur) < 0) continue;
|
||||
break;
|
||||
case 0x4f15:
|
||||
if(vesaddc(&ur) < 0 || vesasetregs(sp, &ur) < 0) continue;
|
||||
break;
|
||||
default:
|
||||
vmerror("vesa: unsupported function %#x", ur.ax);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
addmode(int no, int x, int y, u32int chan)
|
||||
{
|
||||
VgaMode *vm;
|
||||
|
||||
vm = emalloc(sizeof(VgaMode));
|
||||
vm->no = no;
|
||||
vm->w = x;
|
||||
vm->h = y;
|
||||
vm->chan = chan;
|
||||
vm->hbytes = chantodepth(chan) * vm->w + 7 >> 3;
|
||||
vm->sz = vm->hbytes * y;
|
||||
*modeslast = vm;
|
||||
modeslast = &vm->next;
|
||||
}
|
||||
|
||||
void
|
||||
vesainit(void)
|
||||
{
|
||||
void *v;
|
||||
int i, c;
|
||||
int mno;
|
||||
VgaMode *p;
|
||||
|
||||
v = gptr(0xc0000, sizeof(vesabios));
|
||||
if(v == nil) sysfatal("vesainit: gptr failed");
|
||||
for(i = 0, c = 0; i < sizeof(vesabios) - 1; i++)
|
||||
c += vesabios[i];
|
||||
vesabios[sizeof(vesabios) - 1] = -c;
|
||||
vesa.romptr = 0xc0000;
|
||||
vesarompack("S", vesabios, sizeof(vesabios));
|
||||
|
||||
v = gptr(0, 1024);
|
||||
if(v == nil) sysfatal("vesainit: gptr failed");
|
||||
PUT32(v, 0x40, 0xc0000004);
|
||||
|
||||
vesa.oemstring = vesarompack("a", "9front vmx(1)");
|
||||
vesa.oemvendor = vesarompack("a", "9front");
|
||||
vesa.oemproduct = vesarompack("a", "cat graphics adapter");
|
||||
vesa.oemproductrev = vesarompack("a", "∞");
|
||||
|
||||
vesa.modetab = vesa.romptr;
|
||||
mno = 0x120;
|
||||
for(p = modes; p != nil; p = p->next){
|
||||
p->no = mno++;
|
||||
vesarompack("w", p->no);
|
||||
}
|
||||
vesarompack("w", 0xffff);
|
||||
|
||||
addmode(0x100, 640, 400, CMAP8);
|
||||
addmode(0x101, 640, 480, CMAP8);
|
||||
addmode(0x102, 800, 600, CMAP4);
|
||||
addmode(0x6A, 800, 600, CMAP4);
|
||||
addmode(0x103, 800, 600, CMAP8);
|
||||
addmode(0x104, 1024, 768, CMAP4);
|
||||
addmode(0x105, 1024, 768, CMAP8);
|
||||
addmode(0x106, 1280, 1024, CMAP4);
|
||||
addmode(0x107, 1280, 1024, CMAP8);
|
||||
addmode(0x10D, 320, 200, RGB15);
|
||||
addmode(0x10E, 320, 200, RGB16);
|
||||
addmode(0x10F, 320, 200, RGB24);
|
||||
addmode(0x110, 640, 480, RGB15);
|
||||
addmode(0x111, 640, 480, RGB16);
|
||||
addmode(0x112, 640, 480, RGB24);
|
||||
addmode(0x113, 800, 600, RGB15);
|
||||
addmode(0x114, 800, 600, RGB16);
|
||||
addmode(0x115, 800, 600, RGB24);
|
||||
addmode(0x116, 1024, 768, RGB15);
|
||||
addmode(0x117, 1024, 768, RGB16);
|
||||
addmode(0x118, 1024, 768, RGB24);
|
||||
addmode(0x119, 1280, 1024, RGB15);
|
||||
addmode(0x11A, 1280, 1024, RGB16);
|
||||
addmode(0x11B, 1280, 1024, RGB24);
|
||||
|
||||
vesarchan = chancreate(sizeof(VESAIO), 0);
|
||||
vesawchan = chancreate(sizeof(ulong), 0);
|
||||
threadcreate(vesathread, nil, 8192);
|
||||
}
|
||||
|
||||
u32int
|
||||
vesaio(int isin, u16int port, u32int val, int sz, void *)
|
||||
{
|
||||
VESAIO io;
|
||||
|
||||
if(sz != 2) return iowhine(isin, port, val, sz, nil);
|
||||
io.port = isin << 4 | port & 0xf;
|
||||
io.val = val;
|
||||
send(vesarchan, &io);
|
||||
return recvul(vesawchan);
|
||||
}
|
|
@ -6,38 +6,48 @@
|
|||
#include <cursor.h>
|
||||
#include <mouse.h>
|
||||
#include <keyboard.h>
|
||||
#include <ctype.h>
|
||||
#include "dat.h"
|
||||
#include "fns.h"
|
||||
|
||||
static uchar *fb;
|
||||
static uchar *fb, *tfb;
|
||||
uintptr fbsz;
|
||||
uintptr fbaddr;
|
||||
int textmode;
|
||||
static ulong screenchan;
|
||||
|
||||
static int picw, pich, hbytes;
|
||||
VgaMode *curmode, *nextmode, *modes, **modeslast = &modes;
|
||||
int curhbytes, nexthbytes;
|
||||
int vesamode, maxw, maxh;
|
||||
|
||||
VgaMode textmode = {
|
||||
.w 640, .h 400, .no 3
|
||||
};
|
||||
|
||||
static Image *img, *bg;
|
||||
static Mousectl *mc;
|
||||
static Rectangle picr;
|
||||
Channel *kbdch, *mousech;
|
||||
u8int mousegrab;
|
||||
extern u8int mouseactive;
|
||||
static uchar *sfb;
|
||||
|
||||
typedef struct VGA VGA;
|
||||
struct VGA {
|
||||
u8int miscout;
|
||||
u8int cidx;
|
||||
u8int aidx; /* bit 7: access flipflop */
|
||||
u8int cidx; /* crtc */
|
||||
u8int aidx; /* attribute (bit 7: access flipflop) */
|
||||
u8int gidx; /* graphics */
|
||||
u8int sidx; /* sequencer */
|
||||
u16int rdidx, wdidx; /* bit 0-1: color */
|
||||
u8int attr[32];
|
||||
u32int pal[256];
|
||||
Image *col[256];
|
||||
Image *acol[16];
|
||||
u8int crtc[0x18];
|
||||
QLock;
|
||||
} vga = {
|
||||
.miscout 1,
|
||||
.attr { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
|
||||
.crtc { [11] 15 },
|
||||
.crtc { [10] 13, [11] 14 },
|
||||
.pal {
|
||||
0x000000ff, 0x0000a8ff, 0x00a800ff, 0x00a8a8ff, 0xa80000ff, 0xa800a8ff, 0xa85400ff, 0xa8a8a8ff,
|
||||
0x545454ff, 0x5454fcff, 0x54fc54ff, 0x54fcfcff, 0xfc5454ff, 0xfc54fcff, 0xfcfc54ff, 0xfcfcfcff,
|
||||
|
@ -79,10 +89,12 @@ newpal(int l, int n, int dofree)
|
|||
{
|
||||
int x;
|
||||
|
||||
assert(l >= 0 && n + l <= 256);
|
||||
for(; n-- > 0; l++){
|
||||
if(dofree)
|
||||
freeimage(vga.col[l]);
|
||||
vga.col[l] = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, vga.pal[l]);
|
||||
if(vga.col[l] == nil) sysfatal("allocimage: %r");
|
||||
}
|
||||
for(l = 0; l < 16; l++){
|
||||
x = vga.attr[0x14] << 4 & 0xc0 | vga.attr[l] & 0x3f;
|
||||
|
@ -92,17 +104,47 @@ newpal(int l, int n, int dofree)
|
|||
}
|
||||
}
|
||||
|
||||
u32int
|
||||
vgagetpal(u8int n)
|
||||
{
|
||||
return vga.pal[n];
|
||||
}
|
||||
|
||||
void
|
||||
vgasetpal(u8int n, u32int v)
|
||||
{
|
||||
qlock(&vga);
|
||||
vga.pal[n] = v;
|
||||
newpal(n, 1, 1);
|
||||
qunlock(&vga);
|
||||
}
|
||||
|
||||
static void
|
||||
screeninit(void)
|
||||
screeninit(int resize)
|
||||
{
|
||||
Point p;
|
||||
int ch;
|
||||
|
||||
if(!resize)
|
||||
freeimage(img);
|
||||
else{
|
||||
bg = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0xCCCCCCFF);
|
||||
newpal(0, 256, 0);
|
||||
}
|
||||
p = divpt(addpt(screen->r.min, screen->r.max), 2);
|
||||
picr = (Rectangle){subpt(p, Pt(picw/2, pich/2)), addpt(p, Pt((picw+1)/2, (pich+1)/2))};
|
||||
bg = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0xCCCCCCFF);
|
||||
img = allocimage(display, Rect(0, 0, picw, pich), screenchan == 0 ? screen->chan : screenchan, 0, 0);
|
||||
picr = (Rectangle){subpt(p, Pt(curmode->w/2, curmode->h/2)), addpt(p, Pt((curmode->w+1)/2, (curmode->h+1)/2))};
|
||||
switch(curmode->chan){
|
||||
case 0: ch = screen->chan; break;
|
||||
case CHAN1(CMap, 4): case CMAP8:
|
||||
if(vesamode){
|
||||
ch = RGBA32;
|
||||
break;
|
||||
}
|
||||
/* wet floor */
|
||||
default: ch = curmode->chan; break;
|
||||
}
|
||||
img = allocimage(display, Rect(0, 0, curmode->w, curmode->h), ch, 0, 0);
|
||||
draw(screen, screen->r, bg, nil, ZP);
|
||||
newpal(0, 256, 0);
|
||||
}
|
||||
|
||||
u32int
|
||||
|
@ -117,19 +159,24 @@ vgaio(int isin, u16int port, u32int val, int sz, void *)
|
|||
if((vga.aidx & 0x80) != 0){
|
||||
vmdebug("vga: attribute write %#.2x = %#.2x", vga.aidx & 0x1f, val);
|
||||
vga.attr[vga.aidx & 0x1f] = val;
|
||||
newpal(0, 0, 0);
|
||||
qlock(&vga); newpal(0, 0, 0); qunlock(&vga);
|
||||
}else
|
||||
vga.aidx = val & 0x3f;
|
||||
vga.aidx ^= 0x80;
|
||||
return 0;
|
||||
case 0x3c2: vga.miscout = val; return 0;
|
||||
case 0x3c4: vga.sidx = val; return 0;
|
||||
case 0x3c5: vmerror("vga: write to unknown sequencer register %#ux (val=%#ux)", vga.sidx, val); return 0;
|
||||
case 0x3c6: return 0;
|
||||
case 0x3c7: vga.rdidx = val << 2; return 0;
|
||||
case 0x3c8: vga.wdidx = val << 2; return 0;
|
||||
case 0x3c9:
|
||||
vga.pal[vga.wdidx >> 2] = vga.pal[vga.wdidx >> 2] & ~(0xff << (~vga.wdidx << 3 & 24)) | val << 2 + (~vga.wdidx << 3 & 24);
|
||||
newpal(vga.wdidx >> 2, 1, 1);
|
||||
qlock(&vga); newpal(vga.wdidx >> 2, 1, 1); qunlock(&vga);
|
||||
vga.wdidx = vga.wdidx + 1 + (vga.wdidx >> 1 & 1) & 0x3ff;
|
||||
return 0;
|
||||
case 0x3ce: vga.gidx = val; return 0;
|
||||
case 0x3cf: vmerror("vga: write to unknown graphics register %#ux (val=%#ux)", vga.gidx, val); return 0;
|
||||
case 0x3d4: vga.cidx = val; return 0;
|
||||
case 0x3d5:
|
||||
switch(vga.cidx){
|
||||
|
@ -137,11 +184,14 @@ vgaio(int isin, u16int port, u32int val, int sz, void *)
|
|||
vga.crtc[vga.cidx] = val;
|
||||
return 0;
|
||||
default:
|
||||
vmerror("write to unknown VGA register, 3d5/%#ux (val=%#ux)", vga.cidx, val);
|
||||
vmerror("vga: write to unknown CRTC register %#ux (val=%#ux)", vga.cidx, val);
|
||||
}
|
||||
return 0;
|
||||
case 0x103c0: return vga.aidx & 0x3f;
|
||||
case 0x103c1: return vga.attr[vga.aidx & 0x1f];
|
||||
case 0x103c4: return vga.sidx;
|
||||
case 0x103c5: vmerror("vga: read from unknown sequencer register %#ux (val=%#ux)", vga.sidx, val); return 0;
|
||||
case 0x103c6: return 0xff;
|
||||
case 0x103c7: return vga.rdidx >> 2;
|
||||
case 0x103c8: return vga.wdidx >> 2;
|
||||
case 0x103c9:
|
||||
|
@ -149,18 +199,21 @@ vgaio(int isin, u16int port, u32int val, int sz, void *)
|
|||
vga.rdidx = vga.rdidx + 1 + (vga.rdidx >> 1 & 1) & 0x3ff;
|
||||
return m;
|
||||
case 0x103cc: return vga.miscout;
|
||||
case 0x103ce: return vga.gidx;
|
||||
case 0x103cf: vmerror("vga: read from unknown graphics register %#ux", vga.gidx); return 0;
|
||||
case 0x103d4: return vga.cidx;
|
||||
case 0x103d5:
|
||||
switch(vga.cidx){
|
||||
case 10: case 11: case 12: case 13: case 14: case 15:
|
||||
return vga.crtc[vga.cidx];
|
||||
default:
|
||||
vmerror("read from unknown VGA register, 3d5/%#ux", vga.cidx);
|
||||
vmerror("vga: read from unknown CRTC register %#ux", vga.cidx);
|
||||
return 0;
|
||||
}
|
||||
case 0x103ca:
|
||||
case 0x103da:
|
||||
vga.aidx &= ~0x7f;
|
||||
return 0;
|
||||
vga.aidx &= 0x7f;
|
||||
return 0;
|
||||
}
|
||||
return iowhine(isin, port, val, sz, "vga");
|
||||
}
|
||||
|
@ -242,6 +295,8 @@ kbdlayout(char *fn)
|
|||
Bterm(bp);
|
||||
}
|
||||
|
||||
static vlong kbwatchdog; /* used to release mouse grabbing if keyproc is stuck */
|
||||
|
||||
void
|
||||
keyproc(void *)
|
||||
{
|
||||
|
@ -264,9 +319,11 @@ keyproc(void *)
|
|||
memmove(buf, buf+n, sizeof(buf)-n);
|
||||
}
|
||||
if(buf[0] == 0){
|
||||
kbwatchdog = 0;
|
||||
n = read(fd, buf, sizeof(buf)-1);
|
||||
if(n <= 0)
|
||||
sysfatal("read /dev/kbd: %r");
|
||||
kbwatchdog = nsec();
|
||||
buf[n-1] = 0;
|
||||
buf[n] = 0;
|
||||
}
|
||||
|
@ -332,13 +389,15 @@ mousethread(void *)
|
|||
break;
|
||||
}
|
||||
if(!mousegrab){
|
||||
if(clicked && (m.buttons & 1) == 0 && !textmode){
|
||||
if(clicked && (m.buttons & 1) == 0 && mouseactive){
|
||||
mousegrab = 1;
|
||||
setcursor(mc, &blank);
|
||||
}
|
||||
clicked = m.buttons & 1;
|
||||
break;
|
||||
}
|
||||
if(kbwatchdog != 0 && nsec() - kbwatchdog > 1000ULL*1000*1000)
|
||||
mousegrab = 0;
|
||||
gotm = 1;
|
||||
if(!ptinrect(m.xy, grabout)){
|
||||
moveto(mc, mid);
|
||||
|
@ -391,10 +450,10 @@ drawtext(void)
|
|||
sa = vga.crtc[12] << 8 | vga.crtc[13];
|
||||
if(sa + 80*25 >= 0x10000){
|
||||
memset(rbuf, 0, sizeof(rbuf));
|
||||
memmove(rbuf, fb + sa * 2, 0x10000 - 80*25 - sa);
|
||||
memmove(rbuf, tfb + sa * 2, 0x10000 - 80*25 - sa);
|
||||
p = rbuf;
|
||||
}else
|
||||
p = fb + sa * 2;
|
||||
p = tfb + sa * 2;
|
||||
for(y = 0; y < 25; y++){
|
||||
for(x = 0; x < 80; x++)
|
||||
buf[x] = cp437[p[2*x]];
|
||||
|
@ -409,9 +468,9 @@ drawtext(void)
|
|||
p += 160;
|
||||
}
|
||||
cp = (vga.crtc[14] << 8 | vga.crtc[15]);
|
||||
if(cp >= sa && cp < sa + 80*25 && (vga.crtc[10] & 0x20) == 0){
|
||||
buf[0] = cp437[fb[cp*2]];
|
||||
attr = fb[cp*2+1];
|
||||
if(cp >= sa && cp < sa + 80*25 && (vga.crtc[10] & 0x20) == 0 && nsec() / 500000000 % 2 == 0){
|
||||
buf[0] = cp437[tfb[cp*2]];
|
||||
attr = tfb[cp*2+1];
|
||||
r.min = Pt((cp - sa) % 80 * 8, (cp - sa) / 80 * 16);
|
||||
r.max = Pt(r.min.x + 8, r.min.y + (vga.crtc[11] & 0x1f) + 1);
|
||||
r.min.y += vga.crtc[10] & 0x1f;
|
||||
|
@ -422,39 +481,70 @@ drawtext(void)
|
|||
}
|
||||
|
||||
static void
|
||||
drawfb(void)
|
||||
drawfb(int redraw)
|
||||
{
|
||||
u32int *p, *q;
|
||||
Rectangle upd;
|
||||
int xb, y;
|
||||
int xb, y, hb;
|
||||
u32int v;
|
||||
uchar *cp;
|
||||
u32int *buf, *bp;
|
||||
|
||||
p = (u32int *) fb;
|
||||
q = (u32int *) sfb;
|
||||
upd.min.y = upd.max.y = -1;
|
||||
xb = 0;
|
||||
y = 0;
|
||||
while(p < (u32int*)(fb + fbsz)){
|
||||
if(*p != *q){
|
||||
hb = curhbytes;
|
||||
while(p < (u32int*)(fb + curmode->sz)){
|
||||
if(*p != *q || redraw){
|
||||
if(upd.min.y < 0) upd.min.y = y;
|
||||
upd.max.y = y + 1 + (xb + 4 > hbytes);
|
||||
upd.max.y = y + 1 + (xb + 4 > hb);
|
||||
*q = *p;
|
||||
}
|
||||
p++;
|
||||
q++;
|
||||
xb += 4;
|
||||
if(xb >= hbytes){
|
||||
xb -= hbytes;
|
||||
if(xb >= hb){
|
||||
xb -= hb;
|
||||
y++;
|
||||
}
|
||||
}
|
||||
if(upd.min.y == upd.max.y) return;
|
||||
upd.min.x = 0;
|
||||
upd.max.x = picw;
|
||||
if(screenchan != screen->chan){
|
||||
loadimage(img, upd, sfb + upd.min.y * hbytes, (upd.max.y - upd.min.y) * hbytes);
|
||||
upd.max.x = curmode->w;
|
||||
if(vesamode && (curmode->chan >> 4 == CMap)){
|
||||
buf = emalloc(curmode->w * 4 * (upd.max.y - upd.min.y));
|
||||
bp = buf;
|
||||
for(y = upd.min.y; y < upd.max.y; y++){
|
||||
cp = sfb + y * hb;
|
||||
for(xb = 0; xb < curmode->w; xb++){
|
||||
if(curmode->chan == CMAP8)
|
||||
v = *cp++;
|
||||
else if((xb & 1) == 0)
|
||||
v = *cp & 0xf;
|
||||
else
|
||||
v = *cp++ >> 4;
|
||||
*bp++ = vga.pal[v];
|
||||
}
|
||||
}
|
||||
loadimage(img, upd, (void *) buf, curmode->w * 4 * (upd.max.y - upd.min.y));
|
||||
free(buf);
|
||||
draw(screen, rectaddpt(upd, picr.min), img, nil, upd.min);
|
||||
}else
|
||||
loadimage(screen, rectaddpt(upd, picr.min), sfb + upd.min.y * hbytes, (upd.max.y - upd.min.y) * hbytes);
|
||||
}else if(curmode->chan != screen->chan || !rectinrect(picr, screen->r)){
|
||||
if(curmode->hbytes != hb){
|
||||
for(y = upd.min.y; y < upd.max.y; y++)
|
||||
loadimage(img, Rect(0, y, curmode->w, y+1), sfb + y * hb, curmode->hbytes);
|
||||
}else
|
||||
loadimage(img, upd, sfb + upd.min.y * hb, (upd.max.y - upd.min.y) * hb);
|
||||
draw(screen, rectaddpt(upd, picr.min), img, nil, upd.min);
|
||||
}else{
|
||||
if(curmode->hbytes != hb){
|
||||
for(y = upd.min.y; y < upd.max.y; y++)
|
||||
loadimage(screen, Rect(picr.min.x, picr.min.y + y, picr.max.x, picr.min.y + y + 1), sfb + y * hb, curmode->hbytes);
|
||||
}else
|
||||
loadimage(screen, rectaddpt(upd, picr.min), sfb + upd.min.y * hb, (upd.max.y - upd.min.y) * hb);
|
||||
}
|
||||
flushimage(display, 1);
|
||||
}
|
||||
|
||||
|
@ -462,78 +552,172 @@ void
|
|||
drawproc(void *)
|
||||
{
|
||||
ulong ul;
|
||||
int event;
|
||||
VgaMode *m;
|
||||
|
||||
threadsetname("draw");
|
||||
sfb = emalloc(fbsz);
|
||||
for(;; sleep(20)){
|
||||
while(nbrecv(mc->resizec, &ul) > 0){
|
||||
if(getwindow(display, Refnone) < 0)
|
||||
sysfatal("resize failed: %r");
|
||||
screeninit();
|
||||
qlock(&vga);
|
||||
event = 0;
|
||||
m = nextmode;
|
||||
if(m != curmode){
|
||||
event |= 1;
|
||||
curmode = m;
|
||||
curhbytes = m->hbytes;
|
||||
}
|
||||
if(textmode)
|
||||
if(nexthbytes != curhbytes){
|
||||
event |= 1;
|
||||
curhbytes = nexthbytes;
|
||||
}
|
||||
while(nbrecv(mc->resizec, &ul) > 0)
|
||||
event |= 2;
|
||||
if(event != 0){
|
||||
if((event & 2) != 0 && getwindow(display, Refnone) < 0)
|
||||
sysfatal("resize failed: %r");
|
||||
screeninit((event & 2) != 0);
|
||||
}
|
||||
if(curmode == &textmode)
|
||||
drawtext();
|
||||
else
|
||||
drawfb();
|
||||
drawfb(event != 0);
|
||||
qunlock(&vga);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
chancheck(u32int ch)
|
||||
{
|
||||
u8int got;
|
||||
int i, t;
|
||||
|
||||
got = 0;
|
||||
for(i = 0; i < 4; i++){
|
||||
t = ch >> 8 * i + 4 & 15;
|
||||
if((ch >> 8 * i & 15) == 0) continue;
|
||||
if(t >= NChan) return 0;
|
||||
if((got & 1<<t) != 0) return 0;
|
||||
got |= 1<<t;
|
||||
}
|
||||
if(!vesamode) return 1;
|
||||
switch(got){
|
||||
case 1<<CRed|1<<CGreen|1<<CBlue:
|
||||
case 1<<CRed|1<<CGreen|1<<CBlue|1<<CAlpha:
|
||||
case 1<<CRed|1<<CGreen|1<<CBlue|1<<CIgnore:
|
||||
return 1;
|
||||
case 1<<CMap:
|
||||
return chantodepth(ch) == 4 || chantodepth(ch) == 8;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static char *
|
||||
vgamodeparse(char *p, VgaMode **mp)
|
||||
{
|
||||
char *r;
|
||||
VgaMode *m;
|
||||
char c;
|
||||
|
||||
m = emalloc(sizeof(VgaMode));
|
||||
*mp = m;
|
||||
*modeslast = m;
|
||||
modeslast = &m->next;
|
||||
m->w = strtoul(p, &r, 10);
|
||||
if(*r != 'x')
|
||||
nope:
|
||||
sysfatal("invalid mode specifier");
|
||||
p = r + 1;
|
||||
m->h = strtoul(p, &r, 10);
|
||||
if(*r != 'x'){
|
||||
m->chan = XRGB32;
|
||||
goto out;
|
||||
}
|
||||
p = r + 1;
|
||||
while(isalnum(*r))
|
||||
r++;
|
||||
c = *r;
|
||||
*r = 0;
|
||||
m->chan = strtochan(p);
|
||||
*r = c;
|
||||
if(m->chan == 0 || !chancheck(m->chan))
|
||||
goto nope;
|
||||
out:
|
||||
if(m->w > maxw) maxw = m->w;
|
||||
if(m->h > maxh) maxh = m->h;
|
||||
return r;
|
||||
}
|
||||
|
||||
void
|
||||
vgafbparse(char *fbstring)
|
||||
{
|
||||
char buf[512];
|
||||
char *p, *q;
|
||||
uvlong addr;
|
||||
VgaMode *m;
|
||||
|
||||
if(picw != 0) sysfatal("vga specified twice");
|
||||
if(strcmp(fbstring, "text") == 0){
|
||||
picw = 640;
|
||||
pich = 400;
|
||||
fbsz = 80*25*2;
|
||||
fbaddr = 0xb8000;
|
||||
textmode++;
|
||||
screenchan = 0;
|
||||
curmode = &textmode;
|
||||
return;
|
||||
}else if(strncmp(fbstring, "vesa:", 5) == 0){
|
||||
vesamode = 1;
|
||||
p = fbstring + 5;
|
||||
}else
|
||||
p = fbstring;
|
||||
do{
|
||||
q = vgamodeparse(p, &m);
|
||||
if(p == q || m->w <= 0 || m->h <= 0)
|
||||
no: sysfatal("invalid mode specifier");
|
||||
m->hbytes = chantodepth(m->chan) * m->w + 7 >> 3;
|
||||
m->sz = m->hbytes * m->h;
|
||||
if(m->sz > fbsz) fbsz = m->sz;
|
||||
p = q;
|
||||
}while(*p++ == ',');
|
||||
if(*--p == '@'){
|
||||
p++;
|
||||
fbaddr = strtoul(p, &q, 0);
|
||||
if(p == q) goto no;
|
||||
p = q;
|
||||
}else
|
||||
fbaddr = 0xf0000000;
|
||||
if(*p != 0) goto no;
|
||||
if(modes == nil || vesamode == 0 && modes->next != nil)
|
||||
goto no;
|
||||
if(vesamode == 0){
|
||||
curmode = modes;
|
||||
curhbytes = curmode->hbytes;
|
||||
}else{
|
||||
strecpy(buf, buf + nelem(buf), fbstring);
|
||||
picw = strtol(buf, &p, 10);
|
||||
if(*p != 'x')
|
||||
nope:
|
||||
sysfatal("vgafbparse: invalid framebuffer specifier: %#q (should be WxHxCHAN@ADDR or 'text')", fbstring);
|
||||
pich = strtol(p+1, &p, 10);
|
||||
if(*p != 'x') goto nope;
|
||||
q = strchr(p+1, '@');
|
||||
if(q == nil) goto nope;
|
||||
*q = 0;
|
||||
screenchan = strtochan(p+1);
|
||||
if(screenchan == 0) goto nope;
|
||||
p = q + 1;
|
||||
if(*p == 0) goto nope;
|
||||
addr = strtoull(p, &p, 0);
|
||||
fbaddr = addr;
|
||||
if(fbaddr != addr) goto nope;
|
||||
if(*p != 0) goto nope;
|
||||
hbytes = chantodepth(screenchan) * picw + 7 >> 3;
|
||||
fbsz = hbytes * pich;
|
||||
curmode = &textmode;
|
||||
if(fbsz < (1<<22))
|
||||
fbsz = 1<<22;
|
||||
else
|
||||
fbsz = roundpow2(fbsz);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
vgainit(void)
|
||||
{
|
||||
char buf[512];
|
||||
int i;
|
||||
PCIDev *d;
|
||||
extern void vesainit(void);
|
||||
|
||||
if(picw == 0) return;
|
||||
fb = gptr(fbaddr, fbsz);
|
||||
if(fb == nil)
|
||||
sysfatal("got nil ptr for framebuffer");
|
||||
if(textmode)
|
||||
for(i = 0; i < 0x8000; i += 2)
|
||||
PUT16(fb, i, 0x0700);
|
||||
snprint(buf, sizeof(buf), "-dx %d -dy %d", picw+50, pich+50);
|
||||
if(curmode == nil) return;
|
||||
nextmode = curmode;
|
||||
tfb = gptr(0xb8000, 0x8000);
|
||||
if(tfb == nil)
|
||||
sysfatal("got nil ptr for text framebuffer");
|
||||
for(i = 0; i < 0x8000; i += 2)
|
||||
PUT16(tfb, i, 0x0720);
|
||||
if(fbsz != 0){
|
||||
fb = gptr(fbaddr, fbsz);
|
||||
if(fb == nil)
|
||||
sysfatal("got nil ptr for framebuffer");
|
||||
}
|
||||
snprint(buf, sizeof(buf), "-dx %d -dy %d", maxw+50, maxh+50);
|
||||
newwindow(buf);
|
||||
initdraw(nil, nil, "vmx");
|
||||
screeninit();
|
||||
screeninit(1);
|
||||
flushimage(display, 1);
|
||||
kbdlayout("/sys/lib/kbmap/us");
|
||||
mc = initmouse(nil, screen);
|
||||
|
@ -542,4 +726,9 @@ vgainit(void)
|
|||
proccreate(mousethread, nil, 4096);
|
||||
proccreate(keyproc, nil, 4096);
|
||||
proccreate(drawproc, nil, 4096);
|
||||
if(vesamode){
|
||||
d = mkpcidev(allocbdf(), 0x06660666, 0x03000000, 0);
|
||||
mkpcibar(d, BARMEM32 | BARPREF, fbaddr, fbsz, nil, nil);
|
||||
vesainit();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -365,7 +365,7 @@ mkviodev(u16int devid, u32int pciclass, u32int subid)
|
|||
d = emalloc(sizeof(VIODev));
|
||||
d->pci = mkpcidev(allocbdf(), devid << 16 | 0x1AF4, pciclass << 8, 1);
|
||||
d->pci->subid = subid << 16;
|
||||
mkpcibar(d->pci, 1, 256, vioio, d);
|
||||
mkpcibar(d->pci, BARIO, 0, 256, vioio, d);
|
||||
return d;
|
||||
}
|
||||
|
||||
|
@ -501,9 +501,14 @@ vionetwproc(void *vp)
|
|||
continue;
|
||||
}
|
||||
if(len < 14){
|
||||
vmerror("virtio net: ignoring short packet (length=%d)", len);
|
||||
/* openbsd ends up sending lots of zero length packets sometimes */
|
||||
if(len != 0)
|
||||
vmerror("virtio net: ignoring short packet (length=%d)", len);
|
||||
vioputbuf(vb);
|
||||
continue;
|
||||
}else if(len < 60){ /* openbsd doesn't seem to know about ethernet minimum packet lengths either */
|
||||
memset(txbuf + len, 0, 60 - len);
|
||||
len = 60;
|
||||
}
|
||||
rc = write(v->net.writefd, txbuf, len);
|
||||
vioputbuf(vb);
|
||||
|
|
|
@ -331,7 +331,7 @@ launch(void)
|
|||
|
||||
s = rcflush(1);
|
||||
if(ctl("go %s", s == nil ? "" : s) < 0)
|
||||
sysfatal("go: %r");
|
||||
sysfatal("go %s: %r", s == nil ? "" : s);
|
||||
getexit++;
|
||||
}
|
||||
|
||||
|
@ -414,6 +414,7 @@ runloop(void)
|
|||
break;
|
||||
case SLEEP:
|
||||
pitadvance();
|
||||
rtcadvance();
|
||||
break;
|
||||
case NOTIF:
|
||||
notif.f(notif.arg);
|
||||
|
@ -486,7 +487,6 @@ threadmain(int argc, char **argv)
|
|||
static int edevn;
|
||||
static uvlong gmemsz = 64*1024*1024;
|
||||
extern uintptr fbsz, fbaddr;
|
||||
extern int textmode;
|
||||
int i;
|
||||
|
||||
quotefmtinstall();
|
||||
|
@ -534,7 +534,7 @@ threadmain(int argc, char **argv)
|
|||
cmdlinev = argv + 1;
|
||||
|
||||
mkregion(0, gmemsz, REGMEM);
|
||||
if(fbsz != 0 && textmode == 0){
|
||||
if(fbsz != 0){
|
||||
if(fbaddr + fbsz < fbaddr) sysfatal("invalid fb address");
|
||||
if(fbaddr + fbsz < gmemsz) sysfatal("framebuffer overlaps with physical memory");
|
||||
mkregion(fbaddr, fbsz, REGFB);
|
||||
|
|
Loading…
Reference in a new issue