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%zd ICW1 with unsupported value %#ux", p-pic, (u32int)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%zd in init=%d state", p-pic, p->init);
357 if(p == &pic[0] && val != 4 || p == &pic[1] && val != 2)
358 vmerror("PIC%zd ICW3 with unsupported value %#ux", p-pic, val);
362 if((val & 0xfd) != 1) vmerror("PIC%zd 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 = nanosec();
537 settimer(p->lastnsec + p->count * PERIOD);
543 if(p->state == 0 && (p->access != 3 || hi)){
544 p->count = p->reload;
546 p->lastnsec = nanosec();
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 = nanosec();
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;
676 u8int ratepp, ratep, rate;
682 #define keyputc(c) kbd.buf[kbd.bufw++ & 63] = (c)
683 #define mouseputc(c) mouse.buf[mouse.bufw++ & 63] = (c)
686 i8042putbuf(u16int val)
689 i8042.stat = i8042.stat & ~0x20 | val >> 4 & 0x20;
690 if((i8042.cfg & 1) != 0 && (val & 0x100) != 0){
694 if((i8042.cfg & 2) != 0 && (val & 0x200) != 0){
701 i8042.oport &= ~0x30;
712 case 0xf0: /* set scancode set */
714 if(val == 0) keyputc(1);
717 case 0xed: /* set leds */
723 case 0xed: case 0xf0: kbd.actcmd = val; keyputc(0xfa); break;
725 case 0xff: keyputc(0xfa); keyputc(0xaa); break; /* reset */
726 case 0xf5: kbd.quiet = 1; keyputc(0xfa); break; /* disable scanning */
727 case 0xf4: kbd.quiet = 0; keyputc(0xfa); break; /* enable scanning */
728 case 0xf2: keyputc(0xfa); keyputc(0xab); keyputc(0x41); break; /* keyboard id */
729 case 0xee: keyputc(0xee); break; /* echo */
731 vmdebug("unknown kbd command %#ux", val);
743 while(nbrecv(mousech, &m) > 0){
744 mouse.xy = addpt(mouse.xy, m.xy);
745 mouse.buttons = m.buttons;
747 mouse.scroll += (m.buttons>>2 & 6) - 3;
762 mousepacket(int force)
768 if(!mouse.gotmouse && !force)
772 dz = MIN(7, MAX(-8, mouse.scroll));
774 if((ulong)(dx + 256) > 511) dx = dx >> 31 ^ 0xff;
775 if((ulong)(dy + 256) > 511) dy = dy >> 31 ^ 0xff;
776 b0 |= dx >> 5 & 0x10 | dy >> 4 & 0x20;
777 b0 |= (mouse.buttons * 0x111 & 0x421) % 7;
779 mouseputc((u8int)dx);
780 mouseputc((u8int)dy);
782 mouseputc((u8int)dz);
786 mouse.gotmouse = mouse.xy.x != 0 || mouse.xy.y != 0 || mouse.scroll != 0;
800 if((mouse.state & MOUSEWRAP) != 0 && val != 0xec && val != 0xff){
805 switch(mouse.actcmd){
806 case 0xe8: /* set resolution */
811 case 0xf3: /* set sampling rate */
812 mouse.ratepp = mouse.ratep;
813 mouse.ratep = mouse.rate;
815 if(mouse.ratepp == 200 && mouse.ratep == 100 && mouse.rate == 80)
816 mouse.id = 3; /* magic sequence for IntelliMouse */
822 case 0xf3: case 0xe8: mouseputc(0xfa); mouse.actcmd = val; break;
823 case 0xff: mouseputc(0xfa); mousedefaults(); mouse.state = MOUSERESET; break; /* reset */
824 case 0xf6: mouseputc(0xfa); mousedefaults(); mouse.state = mouse.state & ~0xf | MOUSESTREAM; break; /* set defaults */
825 case 0xf5: mouseputc(0xfa); clearmouse(); if((mouse.state&0xf) == MOUSESTREAM) mouse.state &= ~MOUSEREP; break; /* disable reporting */
826 case 0xf4: mouseputc(0xfa); clearmouse(); if((mouse.state&0xf) == MOUSESTREAM) mouse.state |= MOUSEREP; break; /* enable reporting */
827 case 0xf2: mouseputc(0xfa); mouseputc(mouse.id); clearmouse(); break; /* report device id */
828 case 0xf0: mouseputc(0xfa); clearmouse(); mouse.state = mouse.state & ~0xf | MOUSEREMOTE; break; /* set remote mode */
829 case 0xee: mouseputc(0xfa); clearmouse(); mouse.state |= MOUSEWRAP; break; /* set wrap mode */
830 case 0xec: mouseputc(0xfa); clearmouse(); mouse.state &= ~MOUSEWRAP; break; /* reset wrap mode */
831 case 0xeb: mouseputc(0xfa); mousepacket(1); break; /* read data */
832 case 0xea: mouseputc(0xfa); clearmouse(); mouse.state = mouse.state & ~0xf | MOUSESTREAM; break; /* set stream mode */
833 case 0xe9: /* status request */
835 mouseputc(((mouse.state & 0xf) == MOUSEREMOTE) << 6 | ((mouse.state & MOUSEREP) != 0) << 5 | mouse.scaling21 << 4 | (mouse.buttons * 0x111 & 0x142) % 7);
836 mouseputc(mouse.res);
837 mouseputc(mouse.rate);
839 case 0xe7: mouseputc(0xfa); mouse.scaling21 = 1; break; /* set 2:1 scaling */
840 case 0xe6: mouseputc(0xfa); mouse.scaling21 = 0; break; /* set 1:1 scaling */
842 case 0x88: case 0x00: case 0x0a: /* sentelic & cypress */
843 case 0xe1: /* trackpoint */
847 default: vmerror("unknown mouse command %#ux", val); mouseputc(0xfe);
860 mouse.state = MOUSESTREAM;
862 case MOUSESTREAM | MOUSEREP:
863 if(mouse.actcmd == 0)
875 if((i8042.cfg & 0x10) == 0 && i8042.buf == 0)
876 if(kbd.bufr != kbd.bufw)
877 i8042putbuf(0x100 | kbd.buf[kbd.bufr++ & 63]);
878 else if(!kbd.quiet && nbrecv(kbdch, &ch) > 0)
879 i8042putbuf(0x100 | (u8int)ch);
880 if((i8042.cfg & 0x20) == 0 && i8042.buf == 0){
881 if(mouse.bufr == mouse.bufw)
883 if(mouse.bufr != mouse.bufw)
884 i8042putbuf(0x200 | mouse.buf[mouse.bufr++ & 63]);
889 i8042io(int isin, u16int port, u32int val, int sz, void *)
894 switch(isin << 16 | port){
898 case 0x60: i8042.cfg = val; mouseactive = (val & 0x20) == 0; break;
901 irqline(1, i8042.oport >> 4 & 1);
902 irqline(12, i8042.oport >> 5 & 1);
904 case 0xd2: i8042putbuf(0x100 | val); break;
905 case 0xd3: i8042putbuf(0x200 | val); break;
906 case 0xd4: mousecmd(val); break;
907 case -1: kbdcmd(val); break;
919 case 0x20: i8042putbuf(0x400 | i8042.cfg); return 0;
920 case 0xa1: i8042putbuf(0x4f1); return 0; /* no keyboard password */
921 case 0xa7: i8042.cfg |= 1<<5; mouseactive = 0; return 0;
922 case 0xa8: i8042.cfg &= ~(1<<5); mouseactive = 1; return 0;
923 case 0xa9: i8042putbuf(0x400); return 0; /* test second port */
924 case 0xaa: i8042putbuf(0x455); return 0; /* test controller */
925 case 0xab: i8042putbuf(0x400); return 0; /* test first port */
926 case 0xad: i8042.cfg |= 1<<4; return 0;
927 case 0xae: i8042.cfg &= ~(1<<4); return 0;
928 case 0xd0: i8042putbuf(0x400 | i8042.oport); return 0;
929 case 0x60: case 0xd1: case 0xd2: case 0xd3: case 0xd4:
932 case 0xf0: case 0xf2: case 0xf4: case 0xf6: /* pulse reset line */
933 case 0xf8: case 0xfa: case 0xfc: case 0xfe:
934 sysfatal("i8042: system reset");
935 case 0xf1: case 0xf3: case 0xf5: case 0xf7: /* no-op */
936 case 0xf9: case 0xfb: case 0xfd: case 0xff:
939 vmerror("unknown i8042 command %#ux", val);
943 return i8042.stat | i8042.cfg & 4;
945 return iowhine(isin, port, val, sz, "i8042");
948 typedef struct UART UART;
950 u8int ier, fcr, lcr, lsr, mcr, scr, dll, dlh;
957 Channel *inch, *outch;
958 } uart[2] = { { .lsr = 0x60 }, { .lsr = 0x60 } };
965 irqline(4 - (p - uart), (p->irq & p->ier) != 0);
966 if((p->irq & UARTRXIRQ) == 0 && p->inch != nil && nbrecv(p->inch, &c) > 0){
970 if((p->lsr & 1<<5) == 0){
974 }else if(nbsend(p->outch, &p->tbr) > 0){
980 irqline(4 - (p - uart), (p->irq & p->ier) != 0);
984 uartio(int isin, u16int port, u32int val, int sz, void *)
989 if((port & 0xff8) == 0x3f8) p = &uart[0];
990 else if((port & 0xff8) == 0x2f8) p = &uart[1];
994 switch(isin << 4 | port & 7){
996 if((p->lcr & 1<<7) != 0)
998 else{ /* transmit byte */
999 if((p->mcr & 1<<4) != 0){
1000 p->irq |= UARTRXIRQ;
1006 p->irq &= ~UARTTXIRQ;
1012 if((p->lcr & 1<<7) != 0)
1017 case 0x02: p->fcr = val; return 0;
1018 case 0x03: p->lcr = val; return 0;
1019 case 0x04: p->mcr = val & 0x1f; return 0;
1020 case 0x07: p->scr = val; return 0;
1022 if((p->lcr & 1<<7) != 0) return p->dll;
1023 p->irq &= ~UARTRXIRQ;
1028 if((p->lcr & 1<<7) != 0) return p->dlh;
1033 if((p->irq & UARTRXIRQ) != 0)
1035 else if((p->irq & UARTTXIRQ) != 0){
1036 p->irq &= ~UARTTXIRQ;
1041 case 0x13: return p->lcr;
1042 case 0x14: return p->mcr;
1045 rc = p->lsr; /* line status */
1046 if((p->irq & UARTRXIRQ) != 0)
1049 case 0x16: /* modem status */
1050 if((p->mcr & 0x10) != 0)
1051 return (p->mcr << 1 & 2 | p->mcr >> 1 & 1 | p->mcr & 0xc) << 4;
1052 return 0x90; /* DCD + CTS asserted */
1053 case 0x17: return p->scr;
1055 return iowhine(isin, port, val, sz, "uart");
1059 uartrxproc(void *uv)
1066 threadsetname("uart rx");
1070 rc = read(u->infd, buf, sizeof(buf));
1072 vmerror("read(uartrx): %r");
1073 threadexits("read: %r");
1076 if(++eofctr == 100){ /* keep trying but give up eventually */
1077 vmerror("read(uartrx): eof");
1078 threadexits("read: eof");
1082 for(p = buf; p < buf + rc; p++){
1084 sendnotif((void(*)(void*))uartkick, u);
1090 uarttxproc(void *uv)
1095 threadsetname("uart tx");
1101 sendnotif((void(*)(void*))uartkick, u);
1103 while(sendnotif((void(*)(void*))uartkick, u), p < buf+sizeof(buf) && nbrecv(u->outch, p) > 0)
1105 if(write(u->outfd, buf, p - buf) < p - buf)
1106 vmerror("write(uarttx): %r");
1111 uartinit(int n, char *cfg)
1113 char *p, *infn, *outfn;
1115 p = strchr(cfg, ',');
1124 if(infn != nil && *infn != 0){
1125 uart[n].infd = open(infn, OREAD);
1126 if(uart[n].infd < 0)
1127 sysfatal("open: %r");
1128 uart[n].inch = chancreate(sizeof(char), 256);
1129 proccreate(uartrxproc, &uart[n], 4096);
1131 if(outfn != nil && *outfn != 0){
1132 uart[n].outfd = open(outfn, OWRITE);
1133 if(uart[n].outfd < 0)
1134 sysfatal("open: %r");
1135 uart[n].outch = chancreate(sizeof(char), 256);
1136 proccreate(uarttxproc, &uart[n], 4096);
1141 /* floppy dummy controller */
1142 typedef struct Floppy Floppy;
1150 #define fdcputc(c) (fdc.inq[fdc.inqw++ & 15] = (c))
1155 vmdebug("fdc: cmd %#x", val);
1170 vmerror("unknown fdc command %.2x", val);
1175 fdcio(int isin, u16int port, u32int val, int sz, void *)
1179 if(sz != 1) vmerror("fdc: access size %d != 1", sz);
1181 switch(isin << 4 | port & 7){
1182 case 0x02: fdc.dor = val; return 0;
1185 if(--fdc.dump == 0 && fdc.inqr == fdc.inqw && fdc.irq != 0){
1189 }else if(fdc.inqr == fdc.inqw)
1192 case 0x12: return fdc.dor;
1195 if(fdc.dump == 0 && fdc.inqr != fdc.inqw)
1197 if(fdc.dump != 0 || fdc.inqr != fdc.inqw)
1201 if(fdc.dump == 0 && fdc.inqr != fdc.inqw)
1202 return fdc.inq[fdc.inqr++ & 15];
1205 return iowhine(isin, port, val, sz, "fdc");
1209 nopio(int, u16int, u32int, int, void *)
1215 iowhine(int isin, u16int port, u32int val, int sz, void *mod)
1218 vmdebug("%s%sread from unknown i/o port %#ux ignored (sz=%d, pc=%#ullx)", mod != nil ? mod : "", mod != nil ? ": " : "", port, sz, rget(RPC));
1220 vmdebug("%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));
1224 typedef struct IOHandler IOHandler;
1227 u32int (*io)(int, u16int, u32int, int, void *);
1231 u32int vgaio(int, u16int, u32int, int, void *);
1232 u32int pciio(int, u16int, u32int, int, void *);
1233 u32int vesaio(int, u16int, u32int, int, void *);
1234 u32int ideio(int, u16int, u32int, int, void *);
1235 IOHandler handlers[] = {
1236 0x20, 0x21, picio, nil,
1237 0x40, 0x43, pitio, nil,
1238 0x70, 0x71, rtcio, nil,
1239 0xa0, 0xa1, picio, nil,
1240 0x60, 0x60, i8042io, nil,
1241 0x61, 0x61, pitio, nil, /* pc speaker */
1242 0x64, 0x64, i8042io, nil,
1243 0x2f8, 0x2ff, uartio, nil,
1244 0x3b0, 0x3bb, vgaio, nil,
1245 0x3c0, 0x3df, vgaio, nil,
1246 0x3f8, 0x3ff, uartio, nil,
1247 0x4d0, 0x4d1, picio, nil,
1248 0xcf8, 0xcff, pciio, nil,
1249 0xfee0, 0xfeef, vesaio, nil,
1251 0x170, 0x177, ideio, nil, /* ide secondary */
1252 0x376, 0x376, ideio, nil, /* ide secondary (aux) */
1253 0x1f0, 0x1f7, ideio, nil, /* ide primary */
1254 0x3f6, 0x3f6, ideio, nil, /* ide primary (aux) */
1255 0x3f0, 0x3f7, fdcio, nil, /* floppy */
1257 0x080, 0x080, nopio, nil, /* dma -- used by linux for delay by dummy write */
1258 0x084, 0x084, nopio, nil, /* dma -- used by openbsd for delay by dummy read */
1259 0x100, 0x110, nopio, nil, /* elnk3 */
1260 0x240, 0x25f, nopio, nil, /* ne2000 */
1261 0x278, 0x27a, nopio, nil, /* LPT1 / ISA PNP */
1262 0x280, 0x29f, nopio, nil, /* ne2000 */
1263 0x2e8, 0x2ef, nopio, nil, /* COM4 */
1264 0x300, 0x31f, nopio, nil, /* ne2000 */
1265 0x320, 0x32f, nopio, nil, /* etherexpress */
1266 0x330, 0x33f, nopio, nil, /* uha scsi */
1267 0x340, 0x35f, nopio, nil, /* adaptec scsi */
1268 0x360, 0x373, nopio, nil, /* isolan */
1269 0x378, 0x37a, nopio, nil, /* LPT1 */
1270 0x3e0, 0x3e5, nopio, nil, /* cardbus or isa pci bridges */
1271 0x3e8, 0x3ef, nopio, nil, /* COM3 */
1272 0x650, 0x65f, nopio, nil, /* 3c503 ethernet */
1273 0x778, 0x77a, nopio, nil, /* LPT1 (ECP) */
1274 0xa79, 0xa79, nopio, nil, /* isa pnp */
1278 io0(int dir, u16int port, u32int val, int size)
1281 extern PCIBar iobars;
1284 for(h = handlers; h < handlers + nelem(handlers); h++)
1285 if(port >= h->lo && port <= h->hi)
1286 return h->io(dir, port, val, size, h->aux);
1287 for(p = iobars.busnext; p != &iobars; p = p->busnext)
1288 if(port >= p->addr && port < p->addr + p->length)
1289 return p->io(dir, port - p->addr, val, size, p->aux);
1290 return iowhine(dir, port, val, size, nil);
1296 io(int isin, u16int port, u32int val, int sz)
1300 dbg = port < 0x400 && (iodebug[port >> 5] >> (port & 31) & 1) != 0;
1302 val = io0(isin, port, val, sz);
1303 if(sz == 1) val = (u8int)val;
1304 else if(sz == 2) val = (u16int)val;
1306 vmdebug("in %#.4ux <- %#.*ux", port, sz*2, val);
1309 if(sz == 1) val = (u8int)val;
1310 else if(sz == 2) val = (u16int)val;
1311 io0(isin, port, val, sz);
1313 vmdebug("out %#.4ux <- %#.*ux", port, sz*2, val);