ref: 3dc0a21b4add3f2f9b87dd902650f0367954a7f2
parent: 643991956d99e5958e9f19f1d9783367f8462054
author: aiju <devnull@localhost>
date: Wed Jun 14 13:41:32 EDT 2017
vmx: improve PIT/keyboard support
--- a/sys/src/cmd/vmx/dat.h
+++ b/sys/src/cmd/vmx/dat.h
@@ -62,3 +62,8 @@
void (*write)(PCICap *, u8int, u32int, u32int);
PCICap *next;
};
+
+enum {
+ IRQLTOGGLE = -1,
+ IRQLLOHI = -2,
+};
--- a/sys/src/cmd/vmx/io.c
+++ b/sys/src/cmd/vmx/io.c
@@ -144,16 +144,18 @@
n %= 8;
ol = p->lines;
m = 1<<n;
- if(s == 1)
- p->lines |= m;
- else if(s == 0)
- p->lines &= ~m;
- else if(s == -1)
- p->lines ^= m;
+ switch(s){
+ case 1: case IRQLLOHI: p->lines |= m; break;
+ case 0: p->lines &= ~m; break;
+ case IRQLTOGGLE: p->lines ^= m; break;
+ default: assert(0);
+ }
if((p->elcr & m) != 0)
p->irr = p->irr & ~m | ~p->lines & m;
else
p->irr |= p->lines & ~ol & m;
+ if(s == IRQLLOHI && (p->elcr & m) == 0)
+ p->irr |= m;
picupdate(p);
}
@@ -329,7 +331,9 @@
u8int writestate;
vlong lastnsec;
};
-PITChannel pit[3];
+PITChannel pit[3] = {
+ [0] { .state 1 },
+};
enum { PERIOD = 838 };
void
@@ -366,6 +370,35 @@
t = nt - p->lastnsec;
p->lastnsec = nt;
switch(p->mode){
+ case 0:
+ if(p->state != 0){
+ nc = t / PERIOD;
+ if(p->count <= nc && i == 0)
+ irqline(0, 1);
+ p->count -= nc;
+ p->lastnsec -= t % PERIOD;
+ if(i == 0 && (pic[0].lines & 1<<0) == 0)
+ settimer(p->lastnsec + p->count * PERIOD);
+ }
+ break;
+ case 2:
+ if(p->state != 0){
+ nc = t / PERIOD;
+ if(p->count == 0 || p->count - 1 > nc)
+ p->count -= nc;
+ else{
+ rel = p->reload - 1;
+ if(rel <= 0) rel = 65535;
+ nc -= p->count - 1;
+ nc %= rel;
+ p->count = rel - nc + 1;
+ if(i == 0)
+ irqline(0, IRQLLOHI);
+ }
+ p->lastnsec -= t % PERIOD;
+ settimer(p->lastnsec + p->count * PERIOD);
+ }
+ break;
case 3:
if(p->state != 0){
nc = 2 * (t / PERIOD);
@@ -378,7 +411,7 @@
nc %= rel;
p->count = rel - nc;
if(i == 0)
- irqline(0, -1);
+ irqline(0, IRQLTOGGLE);
}
p->lastnsec -= t % PERIOD;
settimer(p->lastnsec + p->count / 2 * PERIOD);
@@ -399,11 +432,24 @@
else
p->reload = p->reload & 0xff00 | v;
switch(p->mode){
+ case 0:
+ if(n == 0)
+ irqline(0, 0);
+ if(p->access != 3 || hi){
+ p->count = p->reload;
+ p->state = 1;
+ p->lastnsec = nsec();
+ settimer(p->lastnsec + p->count * PERIOD);
+ }else
+ p->state = 0;
+ break;
+ case 2:
case 3:
if(p->state == 0 && (p->access != 3 || hi)){
p->count = p->reload;
p->state = 1;
p->lastnsec = nsec();
+ pitadvance();
}
break;
default:
@@ -468,6 +514,12 @@
pit[n].mode = val >> 1 & 7;
pit[n].access = val >> 4 & 3;
pit[n].bcd = val & 1;
+ if(pit[n].bcd != 0)
+ vmerror("pit: bcd mode not implemented");
+ switch(pit[n].mode){
+ case 0: case 2: case 3: break;
+ default: vmerror("pit: mode %d not implemented", pit[n].mode);
+ }
pit[n].state = 0;
pit[n].count = 0;
pit[n].reload = 0;
@@ -475,7 +527,13 @@
pit[n].writestate = pit[n].access == 1 ? READHI : READLO;
pit[n].lastnsec = nsec();
if(n == 0)
- irqline(0, 1);
+ switch(pit[n].mode){
+ case 0:
+ irqline(0, 0);
+ break;
+ default:
+ irqline(0, 1);
+ }
}
return 0;
}
@@ -494,6 +552,13 @@
.cmd -1,
};
Channel *kbdch, *mousech;
+typedef struct PCKeyb PCKeyb;
+struct PCKeyb {
+ u8int buf[64];
+ u8int bufr, bufw;
+ u8int actcmd;
+ u8int quiet;
+} kbd;
typedef struct PCMouse PCMouse;
struct PCMouse {
Mouse;
@@ -513,6 +578,7 @@
.res = 2,
.rate = 100
};
+#define keyputc(c) kbd.buf[kbd.bufw++ & 63] = (c)
#define mouseputc(c) mouse.buf[mouse.bufw++ & 63] = (c)
static void
@@ -541,7 +607,30 @@
static void
kbdcmd(u8int val)
{
- vmerror("unknown kbd command %#ux", val);
+ switch(kbd.actcmd){
+ case 0xf0: /* set scancode set */
+ keyputc(0xfa);
+ if(val == 0) keyputc(1);
+ kbd.actcmd = 0;
+ break;
+ case 0x3d: /* set leds */
+ keyputc(0xfa);
+ kbd.actcmd = 0;
+ break;
+ default:
+ switch(val){
+ case 0xed: case 0xf0: kbd.actcmd = val; keyputc(0xfa); break;
+
+ case 0xff: keyputc(0xfa); break; /* reset */
+ case 0xf5: kbd.quiet = 1; keyputc(0xfa); break; /* disable scanning */
+ case 0xf4: kbd.quiet = 0; keyputc(0xfa); break; /* enable scanning */
+ case 0xf2: keyputc(0xfa); keyputc(0xab); keyputc(0x83); break; /* keyboard id */
+ case 0xee: keyputc(0xee); break; /* echo */
+ default:
+ vmerror("unknown kbd command %#ux", val);
+ }
+ }
+ i8042kick(nil);
}
static void
@@ -666,7 +755,9 @@
ulong ch;
if((i8042.cfg & 0x10) == 0 && i8042.buf == 0)
- if(nbrecv(kbdch, &ch) > 0)
+ if(kbd.bufr != kbd.bufw)
+ i8042putbuf(0x100 | kbd.buf[kbd.bufr++ & 63]);
+ else if(!kbd.quiet && nbrecv(kbdch, &ch) > 0)
i8042putbuf(0x100 | (u8int)ch);
if((i8042.cfg & 0x20) == 0 && i8042.buf == 0){
if(mouse.bufr == mouse.bufw)
@@ -813,7 +904,7 @@
if((p->lcr & 1<<7) != 0) return p->dlh;
return p->ier;
case 0x12:
- rc = (p->fcr & 1) != 0 ? 0x40 : 0;
+ rc = 0;
uartkick(p);
if((p->irq & UARTRXIRQ) != 0)
return rc | 4;
@@ -881,7 +972,7 @@
while(sendnotif((void(*)(void*))uartkick, u), p < buf+sizeof(buf) && nbrecv(u->outch, p) > 0)
p++;
if(write(u->outfd, buf, p - buf) < p - buf)
- vmdebug("write(uarttx): %r");
+ vmerror("write(uarttx): %r");
}
}
@@ -948,20 +1039,26 @@
0x60, 0x60, i8042io, nil,
0x64, 0x64, i8042io, nil,
0x2f8, 0x2ff, uartio, nil,
- 0x3d4, 0x3d5, vgaio, nil,
+ 0x3b0, 0x3bb, vgaio, nil,
+ 0x3c0, 0x3df, vgaio, nil,
0x3f8, 0x3ff, uartio, nil,
0x4d0, 0x4d1, picio, nil,
0xcf8, 0xcff, pciio, nil,
0x061, 0x061, nopio, nil, /* pc speaker */
- 0x110, 0x110, nopio, nil, /* elnk3 */
+ 0x084, 0x084, nopio, nil, /* dma -- used by openbsd for delay by dummy read */
+ 0x100, 0x110, nopio, nil, /* elnk3 */
0x170, 0x177, nopio, nil, /* ide secondary */
0x1f0, 0x1f7, nopio, nil, /* ide primary */
+ 0x279, 0x279, nopio, nil, /* isa pnp */
0x280, 0x28f, nopio, nil, /* 8003 */
+ 0x2e8, 0x2ef, nopio, nil, /* COM4 */
0x378, 0x37a, nopio, nil, /* LPT1 */
0x3e0, 0x3e3, nopio, nil, /* cardbus */
- 0x3f0, 0x3f5, nopio, nil, /* floppy */
+ 0x3e8, 0x3ef, nopio, nil, /* COM3 */
+ 0x3f0, 0x3f7, nopio, nil, /* floppy */
0x778, 0x77a, nopio, nil, /* LPT1 (ECP) */
+ 0xa79, 0xa79, nopio, nil, /* isa pnp */
};
u32int