/* * we save up input characters till clock time to reduce * per character interrupt overhead. */ static void uartclock(void) { Uart *p; ilock(&uartalloc); for(p = uartalloc.elist; p; p = p->elist){ /* this hopefully amortizes cost of qproduce to many chars */ if(p->iw != p->ir){ ilock(&p->rlock); uartstageinput(p); iunlock(&p->rlock); } /* hang up if requested */ if(p->dohup){ qhangup(p->iq, 0); qhangup(p->oq, 0); p->dohup = 0; } /* this adds hysteresis to hardware/software flow control */ if(p->ctsbackoff){ ilock(&p->tlock); if(p->ctsbackoff){ if(--(p->ctsbackoff) == 0) (*p->phys->kick)(p); } iunlock(&p->tlock); } uartkick(p); /* keep it moving */ } iunlock(&uartalloc); }
static void interrupt(Ureg*, void *arg) { Uart *uart; u32int *ap; uart = arg; ap = (u32int*)uart->regs; coherence(); if(0 && (ap[Irq] & UartIrq) == 0) return; if(ap[MuLsr] & TxRdy) uartkick(uart); if(ap[MuLsr] & RxRdy){ //if(uart->console){ // if(uart->opens == 1) // uart->putc = kbdcr2nl; // else // uart->putc = nil; //} do{ uartrecv(uart, ap[MuIo] & 0xFF); }while(ap[MuLsr] & RxRdy); } coherence(); }
static void oxinterrupt(Ureg *, void *arg) { Ctlr *ctlr; Port *port; Uart *uart; int i, old; u8int val; char ch; ctlr = arg; ilock(ctlr); if(!(ctlr->im & ctlr->mem[Gis])){ iunlock(ctlr); return; } for(i = 0; i < ctlr->nport; ++i){ if(!(ctlr->im & 1<<i)) continue; port = &ctlr->port[i]; uart = port; /* "Come Clarity" */ switch(port->mem[Isr] & 0x3f){ case 0x06: /* Receiver status error */ case 0x04: /* Receiver data available */ case 0x0c: /* Receiver time-out */ for(;;){ val = port->mem[Lsr]; if(!(val & 1<<0)) /* RxRDY */ break; if(val & 1<<1) /* Overrun Error */ uart->oerr++; if(val & 1<<2) /* Parity Error */ uart->perr++; if(val & 1<<3) /* Framing Error */ uart->ferr++; ch = port->mem[Rhr]; if(!(val & 1<<7)) /* Data Error */ uartrecv(uart, ch); } break; case 0x02: /* Transmitter THR empty */ uartkick(uart); break; case 0x00: /* Modem status change */ val = port->mem[Msr]; if(val & 1<<0){ /* Delta nCTS */ ilock(&uart->tlock); old = uart->cts; uart->cts = val & 1<<4; /* CTS */ if(!old && uart->cts) uart->ctsbackoff = 2; iunlock(&uart->tlock); } if(val & 1<<1){ /* Delta nDSR */ old = val & 1<<5; /* DSR */ if(!old && uart->dsr && uart->hup_dsr) uart->dohup = 1; uart->dsr = old; } port->ri = val & 1<<6; /* RI */ if(val & 1<<3){ /* Delta nDCD */ old = val & 1<<7; /* DCD */ if(!old && uart->dcd && uart->hup_dcd) uart->dohup = 1; uart->dcd = old; } break; } } iunlock(ctlr); }
static void axpinterrupt(Ureg*, void* arg) { int work; Cc *cc; Ctlr *ctlr; u32int ics; u16int r, sr; work = 0; ctlr = arg; ics = csr32r(ctlr, Ics); if(ics & 0x0810C000) print("%s: unexpected interrupt %#ux\n", ctlr->name, ics); if(!(ics & 0x00002000)) { /* we get a steady stream of these on consoles */ // print("%s: non-doorbell interrupt\n", ctlr->name); ctlr->gcb->gcw2 = 0x0001; /* set Gintack */ return; } // while(work to do){ cc = ctlr->cc; for(sr = xchgw(&ctlr->gcb->isr, 0); sr != 0; sr >>= 1){ if(sr & 0x0001) work++, axprecv(cc); cc++; } cc = ctlr->cc; for(sr = xchgw(&ctlr->gcb->osr, 0); sr != 0; sr >>= 1){ if(sr & 0x0001) work++, uartkick(&cc->Uart); cc++; } cc = ctlr->cc; for(sr = xchgw(&ctlr->gcb->csr, 0); sr != 0; sr >>= 1){ if(sr & 0x0001) work++, wakeup(cc); cc++; } cc = ctlr->cc; for(sr = xchgw(&ctlr->gcb->msr, 0); sr != 0; sr >>= 1){ if(sr & 0x0001) work++, axpmc(cc); cc++; } cc = ctlr->cc; for(sr = xchgw(&ctlr->gcb->esr, 0); sr != 0; sr >>= 1){ if(sr & 0x0001){ r = cc->ccb->ms; if(r & Oe) cc->oerr++; if(r & Pe) cc->perr++; if(r & Fe) cc->ferr++; if (r & (Oe|Pe|Fe)) work++; } cc++; } // } /* only meaningful if we don't share the irq */ if (0 && !work) print("%s: interrupt with no work\n", ctlr->name); csr32w(ctlr, Pdb, 1); /* clear doorbell interrupt */ ctlr->gcb->gcw2 = 0x0001; /* set Gintack */ }
static void i8250interrupt(Ureg*, void* arg) { Ctlr *ctlr; Uart *uart; int iir, lsr, old, r; uart = arg; ctlr = uart->regs; for(iir = csr8r(ctlr, Iir); !(iir & Ip); iir = csr8r(ctlr, Iir)){ switch(iir & IirMASK){ case Ims: /* Ms interrupt */ r = csr8r(ctlr, Msr); if(r & Dcts){ ilock(&uart->tlock); old = uart->cts; uart->cts = r & Cts; if(old == 0 && uart->cts) uart->ctsbackoff = 2; iunlock(&uart->tlock); } if(r & Ddsr){ old = r & Dsr; if(uart->hup_dsr && uart->dsr && !old) uart->dohup = 1; uart->dsr = old; } if(r & Ddcd){ old = r & Dcd; if(uart->hup_dcd && uart->dcd && !old) uart->dohup = 1; uart->dcd = old; } break; case Ithre: /* Thr Empty */ uartkick(uart); break; case Irda: /* Received Data Available */ case Irls: /* Receiver Line Status */ case Ictoi: /* Character Time-out Indication */ /* * Consume any received data. * If the received byte came in with a break, * parity or framing error, throw it away; * overrun is an indication that something has * already been tossed. */ while((lsr = csr8r(ctlr, Lsr)) & Dr){ if(lsr & (FIFOerr|Oe)) uart->oerr++; if(lsr & Pe) uart->perr++; if(lsr & Fe) uart->ferr++; r = csr8r(ctlr, Rbr); if(!(lsr & (Bi|Fe|Pe))) uartrecv(uart, r); } break; default: iprint("weird uart interrupt type %#2.2uX\n", iir); break; } } }
void serialkick(void) { uartkick(&i8250uart[CONSOLE]); }
static void ks8695_txintr(Ureg*, void* arg) { uartkick(arg); }