diff options
author | aiju <devnull@localhost> | 2017-06-13 14:18:14 +0000 |
---|---|---|
committer | aiju <devnull@localhost> | 2017-06-13 14:18:14 +0000 |
commit | d5e55f51407fe5b8516f6488f5813d026d05fd56 (patch) | |
tree | 4c09c3d8f0cd9095d9058d179db0f05e110c859c /sys/src/cmd/vmx/io.c | |
parent | 8029c3d8c4bdae74b9a68beeff1edb8a21cceeed (diff) |
add vmx(1)
Diffstat (limited to 'sys/src/cmd/vmx/io.c')
-rw-r--r-- | sys/src/cmd/vmx/io.c | 981 |
1 files changed, 981 insertions, 0 deletions
diff --git a/sys/src/cmd/vmx/io.c b/sys/src/cmd/vmx/io.c new file mode 100644 index 000000000..631bfe826 --- /dev/null +++ b/sys/src/cmd/vmx/io.c @@ -0,0 +1,981 @@ +#include <u.h> +#include <libc.h> +#include <thread.h> +#include <draw.h> +#include <cursor.h> +#include <mouse.h> +#include "dat.h" +#include "fns.h" + +static uchar +bcd(uchar c) +{ + return c / 10 << 4 | c % 10; +} + +static u32int +rtcio(int isin, u16int port, u32int val, int sz, void *) +{ + static u8int addr; + uintptr basemem, extmem; + Tm *tm; + + switch(isin << 16 | port){ + case 0x10070: return addr; + case 0x70: addr = val; return 0; + case 0x10071: + tm = gmtime(time(nil)); + basemem = gavail(gptr(0, 0)) >> 10; + if(basemem > 640) basemem = 640; + extmem = gavail(gptr(1<<20, 0)) >> 10; + if(extmem >= 65535) extmem = 65535; + 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 0x0a: return 0x26; + case 0x0b: return 1<<1 | 1<<2; + case 0x0d: return 1<<7; /* cmos valid */ + case 0x0e: return 0; /* diagnostics ok */ + case 0x10: return 0; /* no floppies */ + case 0x15: return basemem; + case 0x16: return basemem >> 8; + case 0x17: return extmem; + case 0x18: return extmem >> 8; + case 0x32: return bcd(tm->year / 100 + 19); + default: vmerror("rtc read from unknown address %#x", addr); return 0; + } + } + return iowhine(isin, port, val, sz, "rtc"); +} + +typedef struct Pic Pic; +struct Pic { + enum { + AEOI = 1, + ROTAEOI = 2, + MASKMODE = 4, + POLL = 8, + READSR = 16, + } flags; + u8int lines; + u8int irr, isr; + u8int imr; + u8int elcr; + u8int init; + u8int prio; + u8int base; +} pic[2]; +int irqactive = -1; + +static u8int +picprio(u8int v, u8int p, u8int *n) +{ + p++; + v = v >> p | v << 8 - p; + v &= -v; + v = v << p | v >> 8 - p; + if(n != nil) + *n = ((v & 0xf0) != 0) << 2 | ((v & 0xcc) != 0) << 1 | (v & 0xaa) != 0; + return v; +} + +static u8int +piccheck(Pic *p, u8int *n) +{ + u8int s; + + s = p->isr; + if((p->flags & MASKMODE) != 0 && p->imr != 0) + s = 0; + return picprio(p->irr & ~p->imr | s, p->prio, n) & ~s; +} + +static void +picaeoi(Pic *p, u8int b) +{ + if((p->flags & AEOI) == 0) + return; + p->isr &= ~(1<<b); + if((p->flags & ROTAEOI) != 0) + p->prio = b; +} + +static void +picupdate(Pic *p) +{ + u8int m, n; + + if(p->init != 4) return; + m = piccheck(p, &n); + if(p == &pic[1]) + irqline(2, m != 0); + else{ + if(m != 0 && n == 2){ + m = piccheck(&pic[1], &n); + n |= pic[1].base; + }else + n |= p->base; + if(m != 0 && irqactive != n){ + if(ctl("irq %d", n) < 0) + sysfatal("ctl: %r"); + halt = 0; + irqactive = n; + }else if(m == 0 && irqactive >= 0){ + if(ctl("irq") < 0) + sysfatal("ctl: %r"); + irqactive = -1; + } + } +} + +void +irqline(int n, int s) +{ + Pic *p; + u8int ol, m; + + assert(n >= 0 && n <= 15); + p = &pic[n / 8]; + 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; + if((p->elcr & m) != 0) + p->irr = p->irr & ~m | ~p->lines & m; + else + p->irr |= p->lines & ~ol & m; + picupdate(p); +} + +void +irqack(int n) +{ + Pic *p; + extern int nextexit; + + irqactive = -1; + if((n & ~7) == pic[0].base) + p = &pic[0]; + else if((n & ~7) == pic[1].base) + p = &pic[1]; + else + return; + if(p == &pic[1]) irqack(pic[0].base + 2); + n &= 7; + p->irr &= ~(1<<n); + p->isr |= 1<<n; + picaeoi(p, n); + picupdate(p); +} + +void +elcr(u16int a) +{ + pic[0].elcr = a; + pic[1].elcr = a >> 8; +} + +static u32int +picio(int isin, u16int port, u32int val, int sz, void *) +{ + Pic *p; + u8int m, b; + + p = &pic[(port & 0x80) != 0]; + val = (u8int)val; + switch(isin << 16 | port){ + case 0x20: + case 0xa0: + if((val & 1<<4) != 0){ /* ICW1 */ + if(irqactive){ + if(ctl("irq") < 0) + sysfatal("ctl: %r"); + irqactive = -1; + } + p->irr = 0; + p->isr = 0; + p->imr = 0; + p->prio = 7; + p->flags = 0; + if((val & 0x0b) != 0x01) vmerror("PIC%ld ICW1 with unsupported value %#ux", p-pic, val); + p->init = 1; + return 0; + } + if((val & 0x18) == 0){ /* OCW2 */ + switch(val >> 5){ + case 0: /* rotate in automatic eoi mode (clear) */ + p->flags &= ~ROTAEOI; + break; + case 1: /* non-specific eoi command */ + p->isr &= ~picprio(p->isr, p->prio, nil); + break; + case 2: /* no operation */ + break; + case 3: /* specific eoi command */ + p->isr &= 1<<(val & 7); + break; + case 4: /* rotate in automatic eoi mode (set) */ + p->flags |= ROTAEOI; + break; + case 5: /* rotate on non-specific eoi command */ + p->isr &= ~picprio(p->isr, p->prio, &p->prio); + break; + case 6: /* set priority */ + p->prio = val & 7; + break; + case 7: /* rotate on specific eoi command */ + p->isr &= 1<<(val & 7); + p->prio = val & 7; + break; + } + picupdate(p); + return 0; + } + if((val & 0x98) == 8){ /* OCW3 */ + if((val & 0x40) != 0) + if((val & 0x20) != 0) + p->flags |= MASKMODE; + else + p->flags &= ~MASKMODE; + if((val & 4) != 0) + p->flags |= POLL; + if((val & 2) != 0) + if((val & 10) != 0) + p->flags |= READSR; + else + p->flags &= ~READSR; + picupdate(p); + + } + return 0; + case 0x21: + case 0xa1: + switch(p->init){ + default: + vmerror("write to PIC%ld in init=%d state", p-pic, p->init); + return 0; + case 1: + p->base = val; + p->init = 2; + return 0; + case 2: + if(p == &pic[0] && val != 4 || p == &pic[1] && val != 2) + vmerror("PIC%ld ICW3 with unsupported value %#ux", p-pic, val); + p->init = 3; + return 0; + case 3: + if((val & 0xfd) != 1) vmerror("PIC%ld ICW4 with unsupported value %#ux", p-pic, val); + if((val & 2) != 0) p->flags |= AEOI; + p->init = 4; + picupdate(p); + return 0; + case 4: + p->imr = val; + picupdate(p); + return 0; + } + break; + case 0x10020: + if((p->flags & READSR) != 0) + return p->isr; + if((p->flags & POLL) != 0){ + p->flags &= ~POLL; + m = piccheck(p, &b); + if(m != 0){ + p->irr &= ~m; + p->isr |= m; + picaeoi(p, b); + picupdate(p); + return 1<<7 | b; + } + return 0; + } + return p->irr; + case 0x100a0: + case 0x10021: + case 0x100a1: + return p->imr; + case 0x4d0: + case 0x4d1: + pic[port & 1].elcr = val; + return 0; + case 0x104d0: + case 0x104d1: + return pic[port & 1].elcr; + } + return iowhine(isin, port, val, sz, "pic"); +} + +typedef struct PITChannel PITChannel; + +struct PITChannel { + u8int mode; + u8int bcd; + u8int access; + u8int state; + u16int count, reload; + int latch; + enum { READLO, READHI, READLATLO, READLATHI } readstate; + u8int writestate; + vlong lastnsec; +}; +PITChannel pit[3]; +enum { PERIOD = 838 }; + +void +settimer(vlong targ) +{ + extern vlong timerevent; + extern Lock timerlock; + extern int timerid; + int sendint; + + sendint = 0; + lock(&timerlock); + if(targ < timerevent){ + timerevent = targ; + sendint = 1; + } + unlock(&timerlock); + if(sendint) + threadint(timerid); +} + +void +pitadvance(void) +{ + int i; + int nc; + PITChannel *p; + vlong nt, t; + int rel; + + for(i = 0; i < 3; i++){ + p = &pit[i]; + nt = nsec(); + t = nt - p->lastnsec; + p->lastnsec = nt; + switch(p->mode){ + case 3: + if(p->state != 0){ + nc = 2 * (t / PERIOD); + if(p->count > nc) + p->count -= nc; + else{ + rel = p->reload; + if(rel <= 1) rel = 65536; + nc -= p->count; + nc %= rel; + p->count = rel - nc; + if(i == 0) + irqline(0, -1); + } + p->lastnsec -= t % PERIOD; + settimer(p->lastnsec + p->count / 2 * PERIOD); + } + break; + } + } +} + +static void +pitsetreload(int n, int hi, u8int v) +{ + PITChannel *p; + + p = &pit[n]; + if(hi) + p->reload = p->reload >> 8 | v << 8; + else + p->reload = p->reload & 0xff00 | v; + switch(p->mode){ + case 3: + if(p->state == 0 && (p->access != 3 || hi)){ + p->count = p->reload; + p->state = 1; + p->lastnsec = nsec(); + } + break; + default: + vmerror("PIT reload in mode %d not implemented", p->mode); + break; + } +} + +static u32int +pitio(int isin, u16int port, u32int val, int sz, void *) +{ + int n; + + val = (u8int) val; + pitadvance(); + switch(isin << 16 | port){ + case 0x10040: + case 0x10041: + case 0x10042: + n = port & 3; + switch(pit[n].readstate){ + case READLO: + if(pit[n].access == 3) + pit[n].readstate = READHI; + return pit[n].count; + case READHI: + if(pit[n].access == 3) + pit[n].readstate = READLO; + return pit[n].count >> 8; + case READLATLO: + pit[n].readstate = READLATHI; + return pit[n].latch; + case READLATHI: + pit[n].readstate = pit[n].access == 1 ? READHI : READLO; + return pit[n].latch >> 8; + } + return 0; + case 0x40: + case 0x41: + case 0x42: + n = port & 3; + switch(pit[n].writestate){ + case READLO: + if(pit[n].access == 3) + pit[n].writestate = READHI; + pitsetreload(n, 0, val); + break; + case READHI: + if(pit[n].access == 3) + pit[n].writestate = READLO; + pitsetreload(n, 1, val); + break; + } + return 0; + case 0x43: + n = val >> 6; + if(n == 3) return 0; + if((val & ~0xc0) == 0){ + pit[n].latch = pit[n].count; + pit[n].readstate = READLATLO; + }else{ + pit[n].mode = val >> 1 & 7; + pit[n].access = val >> 4 & 3; + pit[n].bcd = val & 1; + pit[n].state = 0; + pit[n].count = 0; + pit[n].reload = 0; + pit[n].readstate = pit[n].access == 1 ? READHI : READLO; + pit[n].writestate = pit[n].access == 1 ? READHI : READLO; + pit[n].lastnsec = nsec(); + if(n == 0) + irqline(0, 1); + } + return 0; + } + return iowhine(isin, port, val, sz, "pit"); +} + +typedef struct I8042 I8042; +struct I8042 { + u8int cfg, stat, oport; + int cmd; + u16int buf; /* |0x100 == kbd, |0x200 == mouse, |0x400 == cmd */ +} i8042 = { + .cfg 0x34, + .stat 0x10, + .oport 0x01, + .cmd -1, +}; +Channel *kbdch, *mousech; +typedef struct PCMouse PCMouse; +struct PCMouse { + Mouse; + u8int gotmouse; + enum { + MOUSERESET, + MOUSESTREAM, + MOUSEREMOTE, + MOUSEREP = 0x10, + MOUSEWRAP = 0x20, + } state; + u8int buf[64]; + u8int bufr, bufw; + u8int actcmd; + u8int scaling21, res, rate; +} mouse = { + .res = 2, + .rate = 100 +}; +#define mouseputc(c) mouse.buf[mouse.bufw++ & 63] = (c) + +static void +i8042putbuf(u16int val) +{ + i8042.buf = val; + i8042.stat = i8042.stat & ~0x20 | val >> 4 & 0x20; + if((i8042.cfg & 1) != 0 && (val & 0x100) != 0){ + irqline(1, 1); + i8042.oport |= 0x10; + } + if((i8042.cfg & 2) != 0 && (val & 0x200) != 0){ + irqline(12, 1); + i8042.oport |= 0x20; + } + if(val == 0){ + irqline(1, 0); + irqline(12, 0); + i8042.oport &= ~0x30; + i8042.stat &= ~1; + i8042kick(nil); + }else + i8042.stat |= 1; +} + +static void +kbdcmd(u8int val) +{ + vmerror("unknown kbd command %#ux", val); +} + +static void +updatemouse(void) +{ + Mouse m; + + while(nbrecv(mousech, &m) > 0){ + mouse.xy = addpt(mouse.xy, m.xy); + mouse.buttons = m.buttons; + mouse.gotmouse = 1; + } +} + +static void +clearmouse(void) +{ + updatemouse(); + mouse.xy = Pt(0, 0); + mouse.gotmouse = 0; +} + +static void +mousepacket(int force) +{ + int dx, dy; + u8int b0; + + updatemouse(); + if(!mouse.gotmouse && !force) + return; + 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; + b0 |= dx >> 5 & 0x10 | dy >> 4 & 0x20; + b0 |= (mouse.buttons * 0x111 & 0x421) % 7; + mouseputc(b0); + mouseputc((u8int)dx); + mouseputc((u8int)dy); + mouse.xy.x -= dx; + mouse.xy.y += dy; + mouse.gotmouse = 0; +} + +static void +mousedefaults(void) +{ + clearmouse(); + mouse.res = 2; + mouse.rate = 100; +} + +static void +mousecmd(u8int val) +{ + if((mouse.state & MOUSEWRAP) != 0 && val != 0xec && val != 0xff){ + mouseputc(val); + i8042kick(nil); + return; + } + switch(mouse.actcmd){ + case 0xe8: /* set resolution */ + mouse.res = val; + mouseputc(0xfa); + mouse.actcmd = 0; + break; + case 0xf3: /* set sampling rate */ + mouse.rate = val; + mouseputc(0xfa); + mouse.actcmd = 0; + break; + default: + switch(val){ + case 0xf3: case 0xe8: mouseputc(0xfa); mouse.actcmd = val; break; + + case 0xff: mouseputc(0xfa); mousedefaults(); mouse.state = MOUSERESET; break; /* reset */ + case 0xf6: mouseputc(0xfa); mousedefaults(); mouse.state = mouse.state & ~0xf | MOUSESTREAM; break; /* set defaults */ + case 0xf5: mouseputc(0xfa); clearmouse(); if((mouse.state&0xf) == MOUSESTREAM) mouse.state &= ~MOUSEREP; break; /* disable reporting */ + case 0xf4: mouseputc(0xfa); clearmouse(); if((mouse.state&0xf) == MOUSESTREAM) mouse.state |= MOUSEREP; break; /* enable reporting */ + case 0xf2: mouseputc(0xfa); mouseputc(0x00); clearmouse(); break; /* report device id */ + case 0xf0: mouseputc(0xfa); clearmouse(); mouse.state = mouse.state & ~0xf | MOUSEREMOTE; break; /* set remote mode */ + case 0xee: mouseputc(0xfa); clearmouse(); mouse.state |= MOUSEWRAP; break; /* set wrap mode */ + case 0xec: mouseputc(0xfa); clearmouse(); mouse.state &= ~MOUSEWRAP; break; /* reset wrap mode */ + case 0xeb: mouseputc(0xfa); mousepacket(1); break; /* read data */ + case 0xea: mouseputc(0xfa); clearmouse(); mouse.state = mouse.state & ~0xf | MOUSESTREAM; break; /* set stream mode */ + case 0xe9: /* status request */ + mouseputc(0xfa); + mouseputc(((mouse.state & 0xf) == MOUSEREMOTE) << 6 | ((mouse.state & MOUSEREP) != 0) << 5 | mouse.scaling21 << 4 | (mouse.buttons * 0x111 & 0x142) % 7); + mouseputc(mouse.res); + mouseputc(mouse.rate); + break; + case 0xe7: mouseputc(0xfa); mouse.scaling21 = 1; break; /* set 2:1 scaling */ + case 0xe6: mouseputc(0xfa); mouse.scaling21 = 0; break; /* set 1:1 scaling */ + default: vmerror("unknown mouse command %#ux", val); mouseputc(0xfc); + } + } + i8042kick(nil); +} + +static void +mousekick(void) +{ + switch(mouse.state){ + case MOUSERESET: + mouseputc(0xaa); + mouseputc(0); + mouse.state = MOUSESTREAM; + break; + case MOUSESTREAM | MOUSEREP: + if(mouse.actcmd == 0) + mousepacket(0); + break; + } +} + + +void +i8042kick(void *) +{ + ulong ch; + + if((i8042.cfg & 0x10) == 0 && i8042.buf == 0) + if(nbrecv(kbdch, &ch) > 0) + i8042putbuf(0x100 | (u8int)ch); + if((i8042.cfg & 0x20) == 0 && i8042.buf == 0){ + if(mouse.bufr == mouse.bufw) + mousekick(); + if(mouse.bufr != mouse.bufw) + i8042putbuf(0x200 | mouse.buf[mouse.bufr++ & 63]); + } +} + +static u32int +i8042io(int isin, u16int port, u32int val, int sz, void *) +{ + int rc; + + val = (u8int)val; + switch(isin << 16 | port){ + case 0x60: + i8042.stat &= ~8; + switch(i8042.cmd){ + case 0x60: i8042.cfg = val; break; + case 0xd1: + i8042.oport = val; + irqline(1, i8042.oport >> 4 & 1); + irqline(12, i8042.oport >> 5 & 1); + break; + case 0xd2: i8042putbuf(0x100 | val); break; + case 0xd3: i8042putbuf(0x200 | val); break; + case 0xd4: mousecmd(val); break; + case -1: kbdcmd(val); break; + } + i8042.cmd = -1; + return 0; + case 0x10060: + i8042kick(nil); + rc = i8042.buf; + i8042putbuf(0); + return rc; + case 0x64: + i8042.stat |= 8; + 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 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 */ + case 0xad: i8042.cfg |= 1<<4; return 0; + case 0xae: i8042.cfg &= ~(1<<4); return 0; + case 0xd0: i8042putbuf(0x400 | i8042.oport); return 0; + case 0x60: case 0xd1: case 0xd2: case 0xd3: case 0xd4: + i8042.cmd = val; + return 0; + } + vmerror("unknown i8042 command %#ux", val); + return 0; + case 0x10064: + i8042kick(nil); + return i8042.stat | i8042.cfg & 4; + } + return iowhine(isin, port, val, sz, "i8042"); +} + +typedef struct UART UART; +struct UART { + u8int ier, fcr, lcr, lsr, mcr, scr, dll, dlh; + u8int rbr, tbr; + enum { + UARTTXIRQ = 1, + UARTRXIRQ = 2, + } irq; + int infd, outfd; + Channel *inch, *outch; +} uart[2] = { { .lsr = 0x60 }, { .lsr = 0x60 } }; + +static void +uartkick(UART *p) +{ + char c; + + irqline(4 - (p - uart), (p->irq & p->ier) != 0); + if((p->irq & UARTRXIRQ) == 0 && p->inch != nil && nbrecv(p->inch, &c) > 0){ + p->rbr = c; + p->irq |= UARTRXIRQ; + } + if((p->lsr & 1<<5) == 0){ + if(p->outch == nil){ + p->lsr |= 3<<5; + p->irq |= UARTTXIRQ; + }else if(nbsend(p->outch, &p->tbr) > 0){ + p->tbr = 0; + p->lsr |= 3<<5; + p->irq |= UARTTXIRQ; + } + } + irqline(4 - (p - uart), (p->irq & p->ier) != 0); +} + +static u32int +uartio(int isin, u16int port, u32int val, int sz, void *) +{ + UART *p; + int rc; + + if((port & 0xff8) == 0x3f8) p = &uart[0]; + else if((port & 0xff8) == 0x2f8) p = &uart[1]; + else return 0; + + val = (u8int) val; + switch(isin << 4 | port & 7){ + case 0x00: + if((p->lcr & 1<<7) != 0) + p->dll = val; + else{ /* transmit byte */ + if((p->mcr & 1<<4) != 0){ + p->irq |= UARTRXIRQ; + p->rbr = val; + p->lsr |= 3<<5; + }else{ + p->tbr = val; + p->lsr &= ~(3<<5); + p->irq &= ~UARTTXIRQ; + } + uartkick(p); + } + return 0; + case 0x01: + if((p->lcr & 1<<7) != 0) + p->dlh = val; + else + p->ier = val & 15; + return 0; + case 0x02: p->fcr = val; return 0; + case 0x03: p->lcr = val; return 0; + case 0x04: p->mcr = val & 0x1f; return 0; + case 0x07: p->scr = val; return 0; + case 0x10: + if((p->lcr & 1<<7) != 0) return p->dll; + p->irq &= ~UARTRXIRQ; + rc = p->rbr; + uartkick(p); + return rc; + case 0x11: + if((p->lcr & 1<<7) != 0) return p->dlh; + return p->ier; + case 0x12: + rc = (p->fcr & 1) != 0 ? 0x40 : 0; + uartkick(p); + if((p->irq & UARTRXIRQ) != 0) + return rc | 4; + else if((p->irq & UARTTXIRQ) != 0){ + p->irq &= ~UARTTXIRQ; + uartkick(p); + return rc | 2; + }else + return rc | 1; + case 0x13: return p->lcr; + case 0x14: return p->mcr; + case 0x15: + uartkick(p); + rc = p->lsr; /* line status */ + if((p->irq & UARTRXIRQ) != 0) + rc |= 1; + return rc; + case 0x16: /* modem status */ + if((p->mcr & 0x10) != 0) + return p->mcr << 1 & 2 | p->mcr >> 1 & 1 | p->mcr & 0xc; + return 0; + case 0x17: return p->scr; + } + return iowhine(isin, port, val, sz, "uart"); +} + +static void +uartrxproc(void *uv) +{ + UART *u; + char buf[128], *p; + int rc; + + threadsetname("uart rx"); + u = uv; + for(;;){ + rc = read(u->infd, buf, sizeof(buf)); + if(rc < 0){ + vmerror("read(uartrx): %r"); + threadexits("read: %r"); + } + if(rc == 0){ + vmerror("read(uartrx): eof"); + threadexits("read: eof"); + } + for(p = buf; p < buf + rc; p++){ + send(u->inch, p); + sendnotif((void(*)(void*))uartkick, u); + } + } +} + +static void +uarttxproc(void *uv) +{ + UART *u; + char buf[128], *p; + + threadsetname("uart tx"); + u = uv; + for(;;){ + p = buf; + recv(u->outch, p); + p++; + 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"); + } +} + +void +uartinit(int n, char *cfg) +{ + char *p, *infn, *outfn; + + p = strchr(cfg, ','); + if(p == nil){ + infn = cfg; + outfn = cfg; + }else{ + *p = 0; + infn = cfg; + outfn = p + 1; + } + if(infn != nil && *infn != 0){ + uart[n].infd = open(infn, OREAD); + if(uart[n].infd < 0) + sysfatal("open: %r"); + uart[n].inch = chancreate(sizeof(char), 256); + proccreate(uartrxproc, &uart[n], 4096); + } + if(outfn != nil && *outfn != 0){ + uart[n].outfd = open(outfn, OWRITE); + if(uart[n].outfd < 0) + sysfatal("open: %r"); + uart[n].outch = chancreate(sizeof(char), 256); + proccreate(uarttxproc, &uart[n], 4096); + } +} + +static u32int +nopio(int, u16int, u32int, int, void *) +{ + return 0; +} + +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); + else + vmerror("%s%swrite to unknown i/o port %#ux ignored (val=%#ux, sz=%d)", mod != nil ? mod : "", mod != nil ? ": " : "", port, val, sz); + return 0; +} + +typedef struct IOHandler IOHandler; +struct IOHandler { + u16int lo, hi; + u32int (*io)(int, u16int, u32int, int, void *); + void *aux; +}; + +u32int vgaio(int, u16int, u32int, int, void *); +u32int pciio(int, u16int, u32int, int, void *); +IOHandler handlers[] = { + 0x20, 0x21, picio, nil, + 0x40, 0x43, pitio, nil, + 0x70, 0x71, rtcio, nil, + 0xa0, 0xa1, picio, nil, + 0x60, 0x60, i8042io, nil, + 0x64, 0x64, i8042io, nil, + 0x2f8, 0x2ff, uartio, nil, + 0x3d4, 0x3d5, 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 */ + 0x170, 0x177, nopio, nil, /* ide secondary */ + 0x1f0, 0x1f7, nopio, nil, /* ide primary */ + 0x280, 0x28f, nopio, nil, /* 8003 */ + 0x378, 0x37a, nopio, nil, /* LPT1 */ + 0x3e0, 0x3e3, nopio, nil, /* cardbus */ + 0x3f0, 0x3f5, nopio, nil, /* floppy */ + 0x778, 0x77a, nopio, nil, /* LPT1 (ECP) */ +}; + +u32int +io(int dir, u16int port, u32int val, int size) +{ + IOHandler *h; + extern PCIBar iobars; + PCIBar *p; + + for(h = handlers; h < handlers + nelem(handlers); h++) + if(port >= h->lo && port <= h->hi) + return h->io(dir, port, val, size, h->aux); + for(p = iobars.busnext; p != &iobars; p = p->busnext) + if(port >= p->addr && port < p->addr + p->length) + return p->io(dir, port - p->addr, val, size, p->aux); + return iowhine(dir, port, val, size, nil); +} |