static void i8250fifo(Uart* uart, int on) { int i; Ctlr *ctlr; /* * Toggle FIFOs: * if none, do nothing; * reset the Rx and Tx FIFOs; * empty the Rx buffer and clear any interrupt conditions; * if enabling, try to turn them on. */ ctlr = uart->regs; ilock(ctlr); if(!ctlr->fifo){ csr8w(ctlr, Fcr, FIFOtclr|FIFOrclr); for(i = 0; i < 16; i++){ csr8r(ctlr, Iir); csr8r(ctlr, Rbr); } ctlr->fena = 0; if(on){ csr8w(ctlr, Fcr, FIFO4|FIFOena); if(!(csr8r(ctlr, Iir) & Ife)) ctlr->fifo = 1; ctlr->fena = 1; } } iunlock(ctlr); }
static void ks8695_rxintr(Ureg*, void* arg) { Ctlr *ctlr; Uart *uart; int lsr, r; /* handle line error status here as well */ uart = arg; ctlr = uart->regs; while((lsr = csr8r(ctlr, Lsr) & LsrInput) != 0){ /* * 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. */ if(lsr & (FIFOerr|Oe)) uart->oerr++; if(lsr & Pe) uart->perr++; if(lsr & Fe) uart->ferr++; if(lsr & Dr){ r = csr8r(ctlr, Rbr); if(!(lsr & (Bi|Fe|Pe))) uartrecv(uart, r); } } }
static int i8250getc(Uart* uart) { Ctlr *ctlr; ctlr = uart->regs; while(!(csr8r(ctlr, Lsr) & Dr)) delay(1); return csr8r(ctlr, Rbr); }
void putc(int c) { int i; for(i = 0; !(csr8r(Lsr) & Thre) && i < 1000000; i++) ; csr8o(Thr, (uchar)c); for(i = 0; !(csr8r(Lsr) & Thre) && i < 1000000; i++) ; }
static void i8250putc(Uart *uart, int c) { int i; Ctlr *ctlr; ctlr = uart->regs; for(i = 0; !(csr8r(ctlr, Lsr)&Thre) && i < 128; i++) delay(1); outb(ctlr->io+Thr, c); for(i = 0; !(csr8r(ctlr, Lsr)&Thre) && i < 128; i++) delay(1); }
static void i8250dumpregs(Ctlr* ctlr) { int dlm, dll; int _uartprint(char*, ...); csr8w(ctlr, Lcr, Dlab); dlm = csr8r(ctlr, Dlm); dll = csr8r(ctlr, Dll); csr8w(ctlr, Lcr, 0); _uartprint("dlm %#ux dll %#ux\n", dlm, dll); }
static void ks8695_modemintr(Ureg*, void *arg) { Ctlr *ctlr; Uart *uart; int old, r; uart = arg; ctlr = uart->regs; 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; } }
static int ks8695_bits(Uart* uart, int bits) { int lcr; Ctlr *ctlr; ctlr = uart->regs; lcr = csr8r(ctlr, Lcr) & ~WlsMASK; switch(bits){ case 5: lcr |= Wls5; break; case 6: lcr |= Wls6; break; case 7: lcr |= Wls7; break; case 8: lcr |= Wls8; break; default: return -1; } csr8w(ctlr, Lcr, lcr); uart->bits = bits; return 0; }
static int i8250baud(Uart* uart, int baud) { #ifdef notdef /* don't change the speed */ ulong bgc; Ctlr *ctlr; extern int i8250freq; /* In the config file */ /* * Set the Baud rate by calculating and setting the Baud rate * Generator Constant. This will work with fairly non-standard * Baud rates. */ if(i8250freq == 0 || baud <= 0) return -1; bgc = (i8250freq+8*baud-1)/(16*baud); ctlr = uart->regs; while(csr8r(ctlr, Usr) & Busy) delay(1); csr8w(ctlr, Lcr, Dlab); /* begin kludge */ csr8o(ctlr, Dlm, bgc>>8); csr8o(ctlr, Dll, bgc); csr8w(ctlr, Lcr, 0); #endif uart->baud = baud; return 0; }
static int ks8695_parity(Uart* uart, int parity) { int lcr; Ctlr *ctlr; ctlr = uart->regs; lcr = csr8r(ctlr, Lcr) & ~(Eps|Pen); switch(parity){ case 'e': lcr |= Eps|Pen; break; case 'o': lcr |= Pen; break; case 'n': default: break; } csr8w(ctlr, Lcr, lcr); uart->parity = parity; return 0; }
static Uart* i8250pnp(void) { int i; Ctlr *ctlr; Uart *head, *uart; head = i8250uart; for(i = 0; i < nelem(i8250uart); i++){ /* * Does it exist? * Should be able to write/read the Scratch Pad * and reserve the I/O space. */ uart = &i8250uart[i]; ctlr = uart->regs; csr8o(ctlr, Scr, 0x55); if(csr8r(ctlr, Scr) == 0x55) continue; if(ioalloc(ctlr->io, 8, 0, uart->name) < 0) continue; if(uart == head) head = uart->next; else (uart-1)->next = uart->next; } return head; }
static void ks8695_putc(Uart *uart, int c) { serialputc(c); #ifdef ROT int i; Ctlr *ctlr; ctlr = uart->regs; for(i = 0; !(csr8r(ctlr, Lsr)&Thre) && i < 256; i++) delay(1); csr8w(ctlr, Thr, c); if(c == '\n') while((csr8r(ctlr, Lsr) & Temt) == 0){ /* let fifo drain */ /* skip */ } #endif }
static long ks8695_status(Uart* uart, void* buf, long n, long offset) { char *p; Ctlr *ctlr; uchar ier, lcr, mcr, msr; ctlr = uart->regs; p = malloc(READSTR); mcr = csr8r(ctlr, Mcr); msr = csr8r(ctlr, Msr); ier = INTRREG->en; lcr = csr8r(ctlr, Lcr); snprint(p, READSTR, "b%d c%d d%d e%d l%d m%d p%c r%d s%d i%d ier=%ux\n" "dev(%d) type(%d) framing(%d) overruns(%d)%s%s%s%s\n", uart->baud, uart->hup_dcd, (msr & Dsr) != 0, uart->hup_dsr, (lcr & WlsMASK) + 5, (ier & (1<<IRQums)) != 0, (lcr & Pen) ? ((lcr & Eps) ? 'e': 'o'): 'n', (mcr & Rts) != 0, (lcr & Stb) ? 2: 1, ctlr->fena, ier, uart->dev, uart->type, uart->ferr, uart->oerr, (msr & Cts) ? " cts": "", (msr & Dsr) ? " dsr": "", (msr & Dcd) ? " dcd": "", (msr & Ri) ? " ring": "" ); n = readstr(offset, buf, n, p); free(p); return n; }
static void i8250kick(Uart* uart) { int i; Ctlr *ctlr; if(/* uart->cts == 0 || */ uart->blocked) return; if(!normalprint) { /* early */ if (uart->op < uart->oe) emptyoutstage(uart, uart->oe - uart->op); while ((i = uartstageoutput(uart)) > 0) emptyoutstage(uart, i); return; } /* nothing more to send? then disable xmit intr */ ctlr = uart->regs; if (uart->op >= uart->oe && qlen(uart->oq) == 0 && csr8r(ctlr, Lsr) & Temt) { ctlr->sticky[Ier] &= ~Ethre; csr8w(ctlr, Ier, 0); return; } /* * 128 here is an arbitrary limit to make sure * we don't stay in this loop too long. If the * chip's output queue is longer than 128, too * bad -- presotto */ for(i = 0; i < 128; i++){ if(!(csr8r(ctlr, Lsr) & Thre)) break; if(uart->op >= uart->oe && uartstageoutput(uart) == 0) break; csr8o(ctlr, Thr, *uart->op++); /* start tx */ ctlr->sticky[Ier] |= Ethre; csr8w(ctlr, Ier, 0); /* intr when done */ } }
static int rtl8139reset(Ctlr* ctlr) { /* * Soft reset the controller. */ csr8w(ctlr, Cr, Rst); while(csr8r(ctlr, Cr) & Rst) ; return 0; }
Uart* i8250console(char* cfg) { int i; Uart *uart; Ctlr *ctlr; char *cmd, *p; /* * Before i8250pnp() is run can only set the console * to 0 or 1 because those are the only uart structs which * will be the same before and after that. */ if((p = getconf("console")) == nil && (p = cfg) == nil) return nil; i = strtoul(p, &cmd, 0); if(p == cmd) return nil; if((uart = uartconsole(i, cmd)) != nil){ consuart = uart; return uart; } switch(i){ default: return nil; case 0: uart = &i8250uart[0]; break; case 1: uart = &i8250uart[1]; break; } /* * Does it exist? * Should be able to write/read * the Scratch Pad. */ ctlr = uart->regs; csr8o(ctlr, Scr, 0x55); if(csr8r(ctlr, Scr) != 0x55) return nil; (*uart->phys->enable)(uart, 0); uartctl(uart, "b9600 l8 pn s1 i1"); if(*cmd != '\0') uartctl(uart, cmd); consuart = uart; uart->console = 1; return uart; }
static void i8250putc(Uart* uart, int c) { int i; Ctlr *ctlr; if (!normalprint) { /* too early; use brute force */ int s = splhi(); while (!(((ulong *)PHYSCONS)[Lsr] & Thre)) ; ((ulong *)PHYSCONS)[Thr] = c; coherence(); splx(s); return; } ctlr = uart->regs; for(i = 0; !(csr8r(ctlr, Lsr) & Thre) && i < 128; i++) delay(1); csr8o(ctlr, Thr, (uchar)c); for(i = 0; !(csr8r(ctlr, Lsr) & Thre) && i < 128; i++) delay(1); }
static void vt6102promiscuous(void* arg, int on) { int rcr; Ctlr *ctlr; Ether *edev; edev = arg; ctlr = edev->ctlr; rcr = csr8r(ctlr, Rcr); if(on) rcr |= Prom; else rcr &= ~Prom; csr8w(ctlr, Rcr, rcr); }
static void i8250fifo(Uart* uart, int level) { Ctlr *ctlr; ctlr = uart->regs; if(ctlr->hasfifo == 0) return; /* * Changing the FIFOena bit in Fcr flushes data * from both receive and transmit FIFOs; there's * no easy way to guarantee not losing data on * the receive side, but it's possible to wait until * the transmitter is really empty. */ ilock(ctlr); while(!(csr8r(ctlr, Lsr) & Temt)) ; /* * Set the trigger level, default is the max. * value. * Some UARTs require FIFOena to be set before * other bits can take effect, so set it twice. */ ctlr->fena = level; switch(level){ case 0: break; case 1: level = FIFO1|FIFOena; break; case 4: level = FIFO4|FIFOena; break; case 8: level = FIFO8|FIFOena; break; default: level = FIFO14|FIFOena; break; } csr8w(ctlr, Fcr, level); csr8w(ctlr, Fcr, level); iunlock(ctlr); }
static void ks8695_dtr(Uart* uart, int on) { Ctlr *ctlr; int r; /* * Toggle DTR. */ ctlr = uart->regs; r = csr8r(ctlr, Mcr); if(on) r |= Dtr; else r &= ~Dtr; csr8w(ctlr, Mcr, r); }
static void ks8695_rts(Uart* uart, int on) { Ctlr *ctlr; int r; /* * Toggle RTS. */ ctlr = uart->regs; r = csr8r(ctlr, Mcr); if(on) r |= Rts; else r &= ~Rts; csr8w(ctlr, Mcr, r); }
static int32_t i8250status(Uart* uart, void* buf, int32_t n, int32_t offset) { char *p; Ctlr *ctlr; uint8_t ier, lcr, mcr, msr; ctlr = uart->regs; p = malloc(READSTR); mcr = ctlr->sticky[Mcr]; msr = csr8r(ctlr, Msr); ier = ctlr->sticky[Ier]; lcr = ctlr->sticky[Lcr]; snprint(p, READSTR, "b%d c%d d%d e%d l%d m%d p%c r%d s%d i%d\n" "dev(%d) type(%d) framing(%d) overruns(%d) " "berr(%d) serr(%d)%s%s%s%s\n", uart->baud, uart->hup_dcd, (msr & Dsr) != 0, uart->hup_dsr, (lcr & WlsMASK) + 5, (ier & Ems) != 0, (lcr & Pen) ? ((lcr & Eps) ? 'e': 'o'): 'n', (mcr & Rts) != 0, (lcr & Stb) ? 2: 1, ctlr->fena, uart->dev, uart->type, uart->ferr, uart->oerr, uart->berr, uart->serr, (msr & Cts) ? " cts": "", (msr & Dsr) ? " dsr": "", (msr & Dcd) ? " dcd": "", (msr & Ri) ? " ring": "" ); n = readstr(offset, buf, n, p); free(p); return n; }
static void ks8695_break(Uart* uart, int ms) { Ctlr *ctlr; int lcr; /* * Send a break. */ if(ms == 0) ms = 200; ctlr = uart->regs; lcr = csr8r(ctlr, Lcr); csr8w(ctlr, Lcr, lcr|Brk); tsleep(&up->sleep, return0, 0, ms); csr8w(ctlr, Lcr, lcr); }
static void ks8695_kick(Uart* uart) { int i; Ctlr *ctlr; if(uart->cts == 0 || uart->blocked) return; ctlr = uart->regs; for(i = 0; i < 16; i++){ if(!(csr8r(ctlr, Lsr) & Thre)) break; if(uart->op >= uart->oe && uartstageoutput(uart) == 0) break; csr8w(ctlr, Thr, *uart->op++); } }
static void ks8695_fifo(Uart* uart, int level) { Ctlr *ctlr; ctlr = uart->regs; /* * Changing the FIFOena bit in Fcr flushes data * from both receive and transmit FIFOs; there's * no easy way to guarantee not losing data on * the receive side, but it's possible to wait until * the transmitter is really empty. */ ilock(ctlr); while(!(csr8r(ctlr, Lsr) & Temt)) ; /* * Set the trigger level, default is the max. * value. */ ctlr->fena = level; switch(level){ case 0: break; case 1: level = FIFO1|FIFOena; break; case 4: level = FIFO4|FIFOena; break; case 8: level = FIFO8|FIFOena; break; default: level = FIFO14|FIFOena; break; } csr8w(ctlr, Fcr, level); iunlock(ctlr); }
static void ks8695_modemctl(Uart* uart, int on) { Ctlr *ctlr; ctlr = uart->regs; ilock(&uart->tlock); if(on){ INTRREG->en |= 1<<IRQums; /* TO DO */ uart->modem = 1; uart->cts = csr8r(ctlr, Msr) & Cts; } else{ INTRREG->en &= ~(1<<IRQums); uart->modem = 0; uart->cts = 1; } iunlock(&uart->tlock); /* modem needs fifo */ (*uart->phys->fifo)(uart, on); }
static int ks8695_stop(Uart* uart, int stop) { int lcr; Ctlr *ctlr; ctlr = uart->regs; lcr = csr8r(ctlr, Lcr); switch(stop){ case 1: lcr &= ~Stb; break; case 2: lcr |= Stb; break; default: return -1; } csr8w(ctlr, Lcr, lcr); uart->stop = stop; return 0; }
static void i8250modemctl(Uart* uart, int on) { Ctlr *ctlr; ctlr = uart->regs; ilock(&uart->tlock); if(on){ ctlr->sticky[Ier] |= Ems; csr8w(ctlr, Ier, 0); uart->modem = 1; uart->cts = csr8r(ctlr, Msr) & Cts; } else{ ctlr->sticky[Ier] &= ~Ems; csr8w(ctlr, Ier, 0); uart->modem = 0; uart->cts = 1; } iunlock(&uart->tlock); /* modem needs fifo */ (*uart->phys->fifo)(uart, on); }
static void i8250kick(Uart* uart) { int i; Ctlr *ctlr; if(uart->cts == 0 || uart->blocked) return; /* * 128 here is an arbitrary limit to make sure * we don't stay in this loop too long. If the * chip's output queue is longer than 128, too * bad -- presotto */ ctlr = uart->regs; for(i = 0; i < 128; i++){ if(!(csr8r(ctlr, Lsr) & Thre)) break; if(uart->op >= uart->oe && uartstageoutput(uart) == 0) break; outb(ctlr->io+Thr, *(uart->op++)); } }
static void i8250enable(Uart* uart, int ie) { int mode; Ctlr *ctlr; if (up == nil) return; /* too soon */ ctlr = uart->regs; /* omap only: set uart/irda/cir mode to uart */ mode = csr8r(ctlr, Mdr); csr8o(ctlr, Mdr, (mode & ~Modemask) | Modeuart); ctlr->sticky[Lcr] = Wls8; /* no parity */ csr8w(ctlr, Lcr, 0); /* * Check if there is a FIFO. * Changing the FIFOena bit in Fcr flushes data * from both receive and transmit FIFOs; there's * no easy way to guarantee not losing data on * the receive side, but it's possible to wait until * the transmitter is really empty. * Also, reading the Iir outwith i8250interrupt() * can be dangerous, but this should only happen * once, before interrupts are enabled. */ ilock(ctlr); if(!ctlr->checkfifo){ /* * Wait until the transmitter is really empty. */ while(!(csr8r(ctlr, Lsr) & Temt)) ; csr8w(ctlr, Fcr, FIFOena); if(csr8r(ctlr, Iir) & Ifena) ctlr->hasfifo = 1; csr8w(ctlr, Fcr, 0); ctlr->checkfifo = 1; } iunlock(ctlr); /* * Enable interrupts and turn on DTR and RTS. * Be careful if this is called to set up a polled serial line * early on not to try to enable interrupts as interrupt- * -enabling mechanisms might not be set up yet. */ if(ie){ if(ctlr->iena == 0 && !ctlr->poll){ irqenable(ctlr->irq, i8250interrupt, uart, uart->name); ctlr->iena = 1; } ctlr->sticky[Ier] = Erda; // ctlr->sticky[Mcr] |= Ie; /* not on omap */ ctlr->sticky[Mcr] = 0; } else{ ctlr->sticky[Ier] = 0; ctlr->sticky[Mcr] = 0; } csr8w(ctlr, Ier, 0); csr8w(ctlr, Mcr, 0); (*uart->phys->dtr)(uart, 1); (*uart->phys->rts)(uart, 1); /* * During startup, the i8259 interrupt controller is reset. * This may result in a lost interrupt from the i8250 uart. * The i8250 thinks the interrupt is still outstanding and does not * generate any further interrupts. The workaround is to call the * interrupt handler to clear any pending interrupt events. * Note: this must be done after setting Ier. */ if(ie) i8250interrupt(nil, uart); }