11 [1] 0xff, [3] 0xff, [5] 0xff,
14 [0xd] 1<<7, /* cmos valid */
15 [0xf] 0x56, /* cmos tests pass */
16 [0x11] 0x80, /* mouse enabled */
17 [0x14] 0x2e, /* cga 80-column */
18 [0x2d] 0x1c, /* caches + fpu enabled */
20 static vlong rtcnext = -1;
25 return (m & 1) != 0 ? c : c / 10 << 4 | c % 10;
41 irqline(8, (cmos[0xc] & cmos[0xb] & 0x70) != 0);
51 if((cmos[0xa] >> 4) > 2 || (cmos[0xa] & 15) == 0 || (cmos[0xc] & 0x40) != 0){
56 case 0x21: d = 12; break;
57 case 0x22: d = 13; break;
58 default: d = 4 + (cmos[0xa] & 0xf);
60 b = (1000000000ULL << d) / 1048576;
62 rtcnext = t + b - t % b;
67 rtcio(int isin, u16int port, u32int val, int sz, void *)
70 uintptr basemem, extmem;
77 basemem = gavail(gptr(0, 0)) >> 10;
78 if(basemem > 640) basemem = 640;
79 extmem = gavail(gptr(1<<20, 0)) >> 10;
80 if(extmem >= 65535) extmem = 65535;
82 cmos[0x16] = basemem >> 8;
84 cmos[0x18] = extmem >> 8;
86 for(i = 0x10; i < 0x2e; i++)
92 if(sz != 1) vmerror("rtc: access size %d != 1", sz);
94 switch(isin << 16 | port){
95 case 0x70: addr = val; return 0;
98 case 0xa: cmos[addr] = val & 0x7f; rtcset(); break;
99 case 0xb: cmos[addr] = val | 2; rtcadvance(); break;
100 case 0xc: case 0xd: goto no;
102 if(addr < nelem(cmos))
105 vmerror("rtc: write to unknown address %#x (val=%#x)", addr, val);
108 case 0x10070: return addr;
110 tm = gmtime(time(nil));
112 case 0x00: return bcd(cmos[0xb], tm->sec);
113 case 0x02: return bcd(cmos[0xb], tm->min);
114 case 0x04: return bcd(cmos[0xb], tm->hour);
115 case 0x06: return bcd(cmos[0xb], tm->wday + 1);
116 case 0x07: return bcd(cmos[0xb], tm->mday);
117 case 0x08: return bcd(cmos[0xb], tm->mon + 1);
118 case 0x09: return bcd(cmos[0xb], tm->year % 100);
120 i = cmos[0xc] | ((cmos[0xc] & cmos[0xb] & 0x70) != 0) << 7;
124 case 0x32: return bcd(cmos[0xb], tm->year / 100 + 19);
126 if(addr < nelem(cmos))
128 vmerror("rtc: read from unknown address %#x", addr);
132 return iowhine(isin, port, val, sz, "rtc");
135 typedef struct Pic Pic;
155 picprio(u8int v, u8int p, u8int *n)
158 v = v >> p | v << 8 - p;
160 v = v << p | v >> 8 - p;
162 *n = ((v & 0xf0) != 0) << 2 | ((v & 0xcc) != 0) << 1 | (v & 0xaa) != 0;
167 piccheck(Pic *p, u8int *n)
172 if((p->flags & MASKMODE) != 0 && p->imr != 0)
174 return picprio(p->irr & ~p->imr | s, p->prio, n) & ~s;
178 picaeoi(Pic *p, u8int b)
180 if((p->flags & AEOI) == 0)
183 if((p->flags & ROTAEOI) != 0)
192 if(p->init != 4) return;
197 if(m != 0 && n == 2){
198 m = piccheck(&pic[1], &n);
202 if(m != 0 && irqactive != n){
203 if(ctl("irq %d", n) < 0)
208 }else if(m == 0 && irqactive >= 0){
217 irqline(int n, int s)
222 assert(n >= 0 && n <= 15);
228 case 1: case IRQLLOHI: p->lines |= m; break;
229 case 0: p->lines &= ~m; break;
230 case IRQLTOGGLE: p->lines ^= m; break;
233 if((p->elcr & m) != 0)
234 p->irr = p->irr & ~m | ~p->lines & m;
236 p->irr |= p->lines & ~ol & m;
237 if(s == IRQLLOHI && (p->elcr & m) == 0)
249 if((n & ~7) == pic[0].base)
251 else if((n & ~7) == pic[1].base)
256 irqack(pic[0].base + 2);
270 pic[1].elcr = a >> 8;
274 picio(int isin, u16int port, u32int val, int sz, void *)
279 p = &pic[(port & 0x80) != 0];
281 switch(isin << 16 | port){
284 if((val & 1<<4) != 0){ /* ICW1 */
295 if((val & 0x0b) != 0x01) vmerror("PIC%ld ICW1 with unsupported value %#ux", p-pic, val);
299 if((val & 0x18) == 0){ /* OCW2 */
301 case 0: /* rotate in automatic eoi mode (clear) */
302 p->flags &= ~ROTAEOI;
304 case 1: /* non-specific eoi command */
305 p->isr &= ~picprio(p->isr, p->prio, nil);
307 case 2: /* no operation */
309 case 3: /* specific eoi command */
310 p->isr &= ~(1<<(val & 7));
312 case 4: /* rotate in automatic eoi mode (set) */
315 case 5: /* rotate on non-specific eoi command */
316 p->isr &= ~picprio(p->isr, p->prio, &p->prio);
318 case 6: /* set priority */
321 case 7: /* rotate on specific eoi command */
322 p->isr &= ~(1<<(val & 7));
329 if((val & 0x98) == 8){ /* OCW3 */
330 if((val & 0x40) != 0)
331 if((val & 0x20) != 0)
332 p->flags |= MASKMODE;
334 p->flags &= ~MASKMODE;
350 vmerror("write to PIC%ld in init=%d state", p-pic, p->init);
357 if(p == &pic[0] && val != 4 || p == &pic[1] && val != 2)
358 vmerror("PIC%ld ICW3 with unsupported value %#ux", p-pic, val);
362 if((val & 0xfd) != 1) vmerror("PIC%ld ICW4 with unsupported value %#ux", p-pic, val);
363 if((val & 2) != 0) p->flags |= AEOI;
376 if((p->flags & READSR) != 0)
378 if((p->flags & POLL) != 0){
396 pic[port & 1].elcr = val;
400 return pic[port & 1].elcr;
402 return iowhine(isin, port, val, sz, "pic");
405 typedef struct PITChannel PITChannel;
412 u16int count, reload;
414 enum { READLO, READHI, READLATLO, READLATHI } readstate;
419 PITChannel pit[3] = {
423 enum { PERIOD = 838 };
428 extern vlong timerevent;
429 extern Lock timerlock;
435 if(targ < timerevent){
450 case IRQLLOHI: case 1: pit[n].output = 1; break;
451 case 0: pit[n].output = 0; break;
452 case IRQLTOGGLE: pit[n].output ^= 1; break;
465 for(i = 0; i < 3; i++){
468 t = nt - p->lastnsec;
477 p->lastnsec -= t % PERIOD;
479 settimer(p->lastnsec + p->count * PERIOD);
485 if(p->count == 0 || p->count - 1 > nc)
489 if(rel <= 0) rel = 65535;
492 p->count = rel - nc + 1;
495 p->lastnsec -= t % PERIOD;
496 settimer(p->lastnsec + p->count * PERIOD);
501 nc = 2 * (t / PERIOD);
506 if(rel <= 1) rel = 65536;
510 pitout(i, IRQLTOGGLE);
512 p->lastnsec -= t % PERIOD;
513 settimer(p->lastnsec + p->count / 2 * PERIOD);
521 pitsetreload(int n, int hi, u8int v)
527 p->reload = p->reload >> 8 | v << 8;
529 p->reload = p->reload & 0xff00 | v;
533 if(p->access != 3 || hi){
534 p->count = p->reload;
536 p->lastnsec = nsec();
537 settimer(p->lastnsec + p->count * PERIOD);
543 if(p->state == 0 && (p->access != 3 || hi)){
544 p->count = p->reload;
546 p->lastnsec = nsec();
551 vmerror("PIT reload in mode %d not implemented", p->mode);
557 pitio(int isin, u16int port, u32int val, int sz, void *)
563 switch(isin << 16 | port){
568 switch(pit[n].readstate){
570 if(pit[n].access == 3)
571 pit[n].readstate = READHI;
574 if(pit[n].access == 3)
575 pit[n].readstate = READLO;
576 return pit[n].count >> 8;
578 pit[n].readstate = READLATHI;
581 pit[n].readstate = pit[n].access == 1 ? READHI : READLO;
582 return pit[n].latch >> 8;
585 case 0x10061: return port61 | pit[2].output << 5;
590 switch(pit[n].writestate){
592 if(pit[n].access == 3)
593 pit[n].writestate = READHI;
594 pitsetreload(n, 0, val);
597 if(pit[n].access == 3)
598 pit[n].writestate = READLO;
599 pitsetreload(n, 1, val);
606 if((val & ~0xc0) == 0){
607 pit[n].latch = pit[n].count;
608 pit[n].readstate = READLATLO;
610 pit[n].mode = val >> 1 & 7;
611 pit[n].access = val >> 4 & 3;
612 pit[n].bcd = val & 1;
614 vmerror("pit: bcd mode not implemented");
616 case 0: case 2: case 3: break;
617 default: vmerror("pit: mode %d not implemented", pit[n].mode);
622 pit[n].readstate = pit[n].access == 1 ? READHI : READLO;
623 pit[n].writestate = pit[n].access == 1 ? READHI : READLO;
624 pit[n].lastnsec = nsec();
635 port61 = port61 & 0xf0 | val & 0x0f;
638 return iowhine(isin, port, val, sz, "pit");
641 typedef struct I8042 I8042;
643 u8int cfg, stat, oport;
645 u16int buf; /* |0x100 == kbd, |0x200 == mouse, |0x400 == cmd */
652 Channel *kbdch, *mousech;
654 typedef struct PCKeyb PCKeyb;
661 typedef struct PCMouse PCMouse;
675 u8int scaling21, res, rate;
680 #define keyputc(c) kbd.buf[kbd.bufw++ & 63] = (c)
681 #define mouseputc(c) mouse.buf[mouse.bufw++ & 63] = (c)
684 i8042putbuf(u16int val)
687 i8042.stat = i8042.stat & ~0x20 | val >> 4 & 0x20;
688 if((i8042.cfg & 1) != 0 && (val & 0x100) != 0){
692 if((i8042.cfg & 2) != 0 && (val & 0x200) != 0){
699 i8042.oport &= ~0x30;
710 case 0xf0: /* set scancode set */
712 if(val == 0) keyputc(1);
715 case 0xed: /* set leds */
721 case 0xed: case 0xf0: kbd.actcmd = val; keyputc(0xfa); break;
723 case 0xff: keyputc(0xfa); keyputc(0xaa); break; /* reset */
724 case 0xf5: kbd.quiet = 1; keyputc(0xfa); break; /* disable scanning */
725 case 0xf4: kbd.quiet = 0; keyputc(0xfa); break; /* enable scanning */
726 case 0xf2: keyputc(0xfa); keyputc(0xab); keyputc(0x41); break; /* keyboard id */
727 case 0xee: keyputc(0xee); break; /* echo */
729 vmerror("unknown kbd command %#ux", val);
741 while(nbrecv(mousech, &m) > 0){
742 mouse.xy = addpt(mouse.xy, m.xy);
743 mouse.buttons = m.buttons;
757 mousepacket(int force)
763 if(!mouse.gotmouse && !force)
768 if((ulong)(dx + 256) > 511) dx = dx >> 31 ^ 0xff;
769 if((ulong)(dy + 256) > 511) dy = dy >> 31 ^ 0xff;
770 b0 |= dx >> 5 & 0x10 | dy >> 4 & 0x20;
771 b0 |= (mouse.buttons * 0x111 & 0x421) % 7;
773 mouseputc((u8int)dx);
774 mouseputc((u8int)dy);
777 mouse.gotmouse = mouse.xy.x != 0 || mouse.xy.y != 0;
791 if((mouse.state & MOUSEWRAP) != 0 && val != 0xec && val != 0xff){
796 switch(mouse.actcmd){
797 case 0xe8: /* set resolution */
802 case 0xf3: /* set sampling rate */
809 case 0xf3: case 0xe8: mouseputc(0xfa); mouse.actcmd = val; break;
811 case 0xff: mouseputc(0xfa); mousedefaults(); mouse.state = MOUSERESET; break; /* reset */
812 case 0xf6: mouseputc(0xfa); mousedefaults(); mouse.state = mouse.state & ~0xf | MOUSESTREAM; break; /* set defaults */
813 case 0xf5: mouseputc(0xfa); clearmouse(); if((mouse.state&0xf) == MOUSESTREAM) mouse.state &= ~MOUSEREP; break; /* disable reporting */
814 case 0xf4: mouseputc(0xfa); clearmouse(); if((mouse.state&0xf) == MOUSESTREAM) mouse.state |= MOUSEREP; break; /* enable reporting */
815 case 0xf2: mouseputc(0xfa); mouseputc(0x00); clearmouse(); break; /* report device id */
816 case 0xf0: mouseputc(0xfa); clearmouse(); mouse.state = mouse.state & ~0xf | MOUSEREMOTE; break; /* set remote mode */
817 case 0xee: mouseputc(0xfa); clearmouse(); mouse.state |= MOUSEWRAP; break; /* set wrap mode */
818 case 0xec: mouseputc(0xfa); clearmouse(); mouse.state &= ~MOUSEWRAP; break; /* reset wrap mode */
819 case 0xeb: mouseputc(0xfa); mousepacket(1); break; /* read data */
820 case 0xea: mouseputc(0xfa); clearmouse(); mouse.state = mouse.state & ~0xf | MOUSESTREAM; break; /* set stream mode */
821 case 0xe9: /* status request */
823 mouseputc(((mouse.state & 0xf) == MOUSEREMOTE) << 6 | ((mouse.state & MOUSEREP) != 0) << 5 | mouse.scaling21 << 4 | (mouse.buttons * 0x111 & 0x142) % 7);
824 mouseputc(mouse.res);
825 mouseputc(mouse.rate);
827 case 0xe7: mouseputc(0xfa); mouse.scaling21 = 1; break; /* set 2:1 scaling */
828 case 0xe6: mouseputc(0xfa); mouse.scaling21 = 0; break; /* set 1:1 scaling */
830 case 0x88: case 0x00: case 0x0a: /* sentelic & cypress */
831 case 0xe1: /* trackpoint */
835 default: vmerror("unknown mouse command %#ux", val); mouseputc(0xfe);
848 mouse.state = MOUSESTREAM;
850 case MOUSESTREAM | MOUSEREP:
851 if(mouse.actcmd == 0)
863 if((i8042.cfg & 0x10) == 0 && i8042.buf == 0)
864 if(kbd.bufr != kbd.bufw)
865 i8042putbuf(0x100 | kbd.buf[kbd.bufr++ & 63]);
866 else if(!kbd.quiet && nbrecv(kbdch, &ch) > 0)
867 i8042putbuf(0x100 | (u8int)ch);
868 if((i8042.cfg & 0x20) == 0 && i8042.buf == 0){
869 if(mouse.bufr == mouse.bufw)
871 if(mouse.bufr != mouse.bufw)
872 i8042putbuf(0x200 | mouse.buf[mouse.bufr++ & 63]);
877 i8042io(int isin, u16int port, u32int val, int sz, void *)
882 switch(isin << 16 | port){
886 case 0x60: i8042.cfg = val; mouseactive = (val & 0x20) == 0; break;
889 irqline(1, i8042.oport >> 4 & 1);
890 irqline(12, i8042.oport >> 5 & 1);
892 case 0xd2: i8042putbuf(0x100 | val); break;
893 case 0xd3: i8042putbuf(0x200 | val); break;
894 case 0xd4: mousecmd(val); break;
895 case -1: kbdcmd(val); break;
907 case 0x20: i8042putbuf(0x400 | i8042.cfg); return 0;
908 case 0xa1: i8042putbuf(0x4f1); return 0; /* no keyboard password */
909 case 0xa7: i8042.cfg |= 1<<5; mouseactive = 0; return 0;
910 case 0xa8: i8042.cfg &= ~(1<<5); mouseactive = 1; return 0;
911 case 0xa9: i8042putbuf(0x400); return 0; /* test second port */
912 case 0xaa: i8042putbuf(0x455); return 0; /* test controller */
913 case 0xab: i8042putbuf(0x400); return 0; /* test first port */
914 case 0xad: i8042.cfg |= 1<<4; return 0;
915 case 0xae: i8042.cfg &= ~(1<<4); return 0;
916 case 0xd0: i8042putbuf(0x400 | i8042.oport); return 0;
917 case 0x60: case 0xd1: case 0xd2: case 0xd3: case 0xd4:
920 case 0xf0: case 0xf2: case 0xf4: case 0xf6: /* pulse reset line */
921 case 0xf8: case 0xfa: case 0xfc: case 0xfe:
922 sysfatal("i8042: system reset");
923 case 0xf1: case 0xf3: case 0xf5: case 0xf7: /* no-op */
924 case 0xf9: case 0xfb: case 0xfd: case 0xff:
927 vmerror("unknown i8042 command %#ux", val);
931 return i8042.stat | i8042.cfg & 4;
933 return iowhine(isin, port, val, sz, "i8042");
936 typedef struct UART UART;
938 u8int ier, fcr, lcr, lsr, mcr, scr, dll, dlh;
945 Channel *inch, *outch;
946 } uart[2] = { { .lsr = 0x60 }, { .lsr = 0x60 } };
953 irqline(4 - (p - uart), (p->irq & p->ier) != 0);
954 if((p->irq & UARTRXIRQ) == 0 && p->inch != nil && nbrecv(p->inch, &c) > 0){
958 if((p->lsr & 1<<5) == 0){
962 }else if(nbsend(p->outch, &p->tbr) > 0){
968 irqline(4 - (p - uart), (p->irq & p->ier) != 0);
972 uartio(int isin, u16int port, u32int val, int sz, void *)
977 if((port & 0xff8) == 0x3f8) p = &uart[0];
978 else if((port & 0xff8) == 0x2f8) p = &uart[1];
982 switch(isin << 4 | port & 7){
984 if((p->lcr & 1<<7) != 0)
986 else{ /* transmit byte */
987 if((p->mcr & 1<<4) != 0){
994 p->irq &= ~UARTTXIRQ;
1000 if((p->lcr & 1<<7) != 0)
1005 case 0x02: p->fcr = val; return 0;
1006 case 0x03: p->lcr = val; return 0;
1007 case 0x04: p->mcr = val & 0x1f; return 0;
1008 case 0x07: p->scr = val; return 0;
1010 if((p->lcr & 1<<7) != 0) return p->dll;
1011 p->irq &= ~UARTRXIRQ;
1016 if((p->lcr & 1<<7) != 0) return p->dlh;
1021 if((p->irq & UARTRXIRQ) != 0)
1023 else if((p->irq & UARTTXIRQ) != 0){
1024 p->irq &= ~UARTTXIRQ;
1029 case 0x13: return p->lcr;
1030 case 0x14: return p->mcr;
1033 rc = p->lsr; /* line status */
1034 if((p->irq & UARTRXIRQ) != 0)
1037 case 0x16: /* modem status */
1038 if((p->mcr & 0x10) != 0)
1039 return (p->mcr << 1 & 2 | p->mcr >> 1 & 1 | p->mcr & 0xc) << 4;
1040 return 0x90; /* DCD + CTS asserted */
1041 case 0x17: return p->scr;
1043 return iowhine(isin, port, val, sz, "uart");
1047 uartrxproc(void *uv)
1054 threadsetname("uart rx");
1058 rc = read(u->infd, buf, sizeof(buf));
1060 vmerror("read(uartrx): %r");
1061 threadexits("read: %r");
1064 if(++eofctr == 100){ /* keep trying but give up eventually */
1065 vmerror("read(uartrx): eof");
1066 threadexits("read: eof");
1070 for(p = buf; p < buf + rc; p++){
1072 sendnotif((void(*)(void*))uartkick, u);
1078 uarttxproc(void *uv)
1083 threadsetname("uart tx");
1089 sendnotif((void(*)(void*))uartkick, u);
1091 while(sendnotif((void(*)(void*))uartkick, u), p < buf+sizeof(buf) && nbrecv(u->outch, p) > 0)
1093 if(write(u->outfd, buf, p - buf) < p - buf)
1094 vmerror("write(uarttx): %r");
1099 uartinit(int n, char *cfg)
1101 char *p, *infn, *outfn;
1103 p = strchr(cfg, ',');
1112 if(infn != nil && *infn != 0){
1113 uart[n].infd = open(infn, OREAD);
1114 if(uart[n].infd < 0)
1115 sysfatal("open: %r");
1116 uart[n].inch = chancreate(sizeof(char), 256);
1117 proccreate(uartrxproc, &uart[n], 4096);
1119 if(outfn != nil && *outfn != 0){
1120 uart[n].outfd = open(outfn, OWRITE);
1121 if(uart[n].outfd < 0)
1122 sysfatal("open: %r");
1123 uart[n].outch = chancreate(sizeof(char), 256);
1124 proccreate(uarttxproc, &uart[n], 4096);
1129 /* floppy dummy controller */
1130 typedef struct Floppy Floppy;
1138 #define fdcputc(c) (fdc.inq[fdc.inqw++ & 15] = (c))
1143 vmdebug("fdc: cmd %#x", val);
1158 vmerror("unknown fdc command %.2x", val);
1163 fdcio(int isin, u16int port, u32int val, int sz, void *)
1167 if(sz != 1) vmerror("fdc: access size %d != 1", sz);
1169 switch(isin << 4 | port & 7){
1170 case 0x02: fdc.dor = val; return 0;
1173 if(--fdc.dump == 0 && fdc.inqr == fdc.inqw && fdc.irq != 0){
1177 }else if(fdc.inqr == fdc.inqw)
1180 case 0x12: return fdc.dor;
1183 if(fdc.dump == 0 && fdc.inqr != fdc.inqw)
1185 if(fdc.dump != 0 || fdc.inqr != fdc.inqw)
1189 if(fdc.dump == 0 && fdc.inqr != fdc.inqw)
1190 return fdc.inq[fdc.inqr++ & 15];
1193 return iowhine(isin, port, val, sz, "fdc");
1197 nopio(int, u16int, u32int, int, void *)
1203 iowhine(int isin, u16int port, u32int val, int sz, void *mod)
1206 vmerror("%s%sread from unknown i/o port %#ux ignored (sz=%d, pc=%#ullx)", mod != nil ? mod : "", mod != nil ? ": " : "", port, sz, rget(RPC));
1208 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));
1212 typedef struct IOHandler IOHandler;
1215 u32int (*io)(int, u16int, u32int, int, void *);
1219 u32int vgaio(int, u16int, u32int, int, void *);
1220 u32int pciio(int, u16int, u32int, int, void *);
1221 u32int vesaio(int, u16int, u32int, int, void *);
1222 u32int ideio(int, u16int, u32int, int, void *);
1223 IOHandler handlers[] = {
1224 0x20, 0x21, picio, nil,
1225 0x40, 0x43, pitio, nil,
1226 0x70, 0x71, rtcio, nil,
1227 0xa0, 0xa1, picio, nil,
1228 0x60, 0x60, i8042io, nil,
1229 0x61, 0x61, pitio, nil, /* pc speaker */
1230 0x64, 0x64, i8042io, nil,
1231 0x2f8, 0x2ff, uartio, nil,
1232 0x3b0, 0x3bb, vgaio, nil,
1233 0x3c0, 0x3df, vgaio, nil,
1234 0x3f8, 0x3ff, uartio, nil,
1235 0x4d0, 0x4d1, picio, nil,
1236 0xcf8, 0xcff, pciio, nil,
1237 0xfee0, 0xfeef, vesaio, nil,
1239 0x170, 0x177, ideio, nil, /* ide secondary */
1240 0x376, 0x376, ideio, nil, /* ide secondary (aux) */
1241 0x1f0, 0x1f7, ideio, nil, /* ide primary */
1242 0x3f6, 0x3f6, ideio, nil, /* ide primary (aux) */
1243 0x3f0, 0x3f7, fdcio, nil, /* floppy */
1245 0x080, 0x080, nopio, nil, /* dma -- used by linux for delay by dummy write */
1246 0x084, 0x084, nopio, nil, /* dma -- used by openbsd for delay by dummy read */
1247 0x100, 0x110, nopio, nil, /* elnk3 */
1248 0x240, 0x25f, nopio, nil, /* ne2000 */
1249 0x278, 0x27a, nopio, nil, /* LPT1 / ISA PNP */
1250 0x280, 0x29f, nopio, nil, /* ne2000 */
1251 0x2e8, 0x2ef, nopio, nil, /* COM4 */
1252 0x300, 0x31f, nopio, nil, /* ne2000 */
1253 0x320, 0x32f, nopio, nil, /* etherexpress */
1254 0x330, 0x33f, nopio, nil, /* uha scsi */
1255 0x340, 0x35f, nopio, nil, /* adaptec scsi */
1256 0x360, 0x373, nopio, nil, /* isolan */
1257 0x378, 0x37a, nopio, nil, /* LPT1 */
1258 0x3e0, 0x3e5, nopio, nil, /* cardbus or isa pci bridges */
1259 0x3e8, 0x3ef, nopio, nil, /* COM3 */
1260 0x650, 0x65f, nopio, nil, /* 3c503 ethernet */
1261 0x778, 0x77a, nopio, nil, /* LPT1 (ECP) */
1262 0xa79, 0xa79, nopio, nil, /* isa pnp */
1266 io0(int dir, u16int port, u32int val, int size)
1269 extern PCIBar iobars;
1272 for(h = handlers; h < handlers + nelem(handlers); h++)
1273 if(port >= h->lo && port <= h->hi)
1274 return h->io(dir, port, val, size, h->aux);
1275 for(p = iobars.busnext; p != &iobars; p = p->busnext)
1276 if(port >= p->addr && port < p->addr + p->length)
1277 return p->io(dir, port - p->addr, val, size, p->aux);
1278 return iowhine(dir, port, val, size, nil);
1284 io(int isin, u16int port, u32int val, int sz)
1288 dbg = port < 0x400 && (iodebug[port >> 5] >> (port & 31) & 1) != 0;
1290 val = io0(isin, port, val, sz);
1291 if(sz == 1) val = (u8int)val;
1292 else if(sz == 2) val = (u16int)val;
1294 vmdebug("in %#.4ux <- %#.*ux", port, sz*2, val);
1297 if(sz == 1) val = (u8int)val;
1298 else if(sz == 2) val = (u16int)val;
1299 io0(isin, port, val, sz);
1301 vmdebug("out %#.4ux <- %#.*ux", port, sz*2, val);