diff options
| author | Konstantin Kirik (snegovick) <snegovick@uprojects.org> | 2025-12-28 12:27:31 +0300 |
|---|---|---|
| committer | Konstantin Kirik (snegovick) <snegovick@uprojects.org> | 2025-12-28 12:27:31 +0300 |
| commit | 78ee7d5717807e6ac779293d0d3c78341de6130a (patch) | |
| tree | a43e3b0f61318ac45e6d907c7cc5bad2c6d7f497 /os/pc/uarti8250.c | |
| parent | bdaf46cf45bbb59261da245d548a179d95a42768 (diff) | |
Move existing boards into subdits split per arch
Diffstat (limited to 'os/pc/uarti8250.c')
| -rw-r--r-- | os/pc/uarti8250.c | 740 |
1 files changed, 0 insertions, 740 deletions
diff --git a/os/pc/uarti8250.c b/os/pc/uarti8250.c deleted file mode 100644 index 2d6c0da2..00000000 --- a/os/pc/uarti8250.c +++ /dev/null @@ -1,740 +0,0 @@ -#include "u.h" -#include "../port/lib.h" -#include "mem.h" -#include "dat.h" -#include "fns.h" -#include "io.h" -#include "../port/error.h" -#include "../port/uart.h" - -/* - * 8250 UART and compatibles. - */ -enum { - Uart0 = 0x3F8, /* COM1 */ - Uart0IRQ = 4, - Uart1 = 0x2F8, /* COM2 */ - Uart1IRQ = 3, - - UartFREQ = 1843200, -}; - -enum { /* I/O ports */ - Rbr = 0, /* Receiver Buffer (RO) */ - Thr = 0, /* Transmitter Holding (WO) */ - Ier = 1, /* Interrupt Enable */ - Iir = 2, /* Interrupt Identification (RO) */ - Fcr = 2, /* FIFO Control (WO) */ - Lcr = 3, /* Line Control */ - Mcr = 4, /* Modem Control */ - Lsr = 5, /* Line Status */ - Msr = 6, /* Modem Status */ - Scr = 7, /* Scratch Pad */ - Dll = 0, /* Divisor Latch LSB */ - Dlm = 1, /* Divisor Latch MSB */ -}; - -enum { /* Ier */ - Erda = 0x01, /* Enable Received Data Available */ - Ethre = 0x02, /* Enable Thr Empty */ - Erls = 0x04, /* Enable Receiver Line Status */ - Ems = 0x08, /* Enable Modem Status */ -}; - -enum { /* Iir */ - Ims = 0x00, /* Ms interrupt */ - Ip = 0x01, /* Interrupt Pending (not) */ - Ithre = 0x02, /* Thr Empty */ - Irda = 0x04, /* Received Data Available */ - Irls = 0x06, /* Receiver Line Status */ - Ictoi = 0x0C, /* Character Time-out Indication */ - IirMASK = 0x3F, - Ifena = 0xC0, /* FIFOs enabled */ -}; - -enum { /* Fcr */ - FIFOena = 0x01, /* FIFO enable */ - FIFOrclr = 0x02, /* clear Rx FIFO */ - FIFOtclr = 0x04, /* clear Tx FIFO */ - FIFO1 = 0x00, /* Rx FIFO trigger level 1 byte */ - FIFO4 = 0x40, /* 4 bytes */ - FIFO8 = 0x80, /* 8 bytes */ - FIFO14 = 0xC0, /* 14 bytes */ -}; - -enum { /* Lcr */ - Wls5 = 0x00, /* Word Length Select 5 bits/byte */ - Wls6 = 0x01, /* 6 bits/byte */ - Wls7 = 0x02, /* 7 bits/byte */ - Wls8 = 0x03, /* 8 bits/byte */ - WlsMASK = 0x03, - Stb = 0x04, /* 2 stop bits */ - Pen = 0x08, /* Parity Enable */ - Eps = 0x10, /* Even Parity Select */ - Stp = 0x20, /* Stick Parity */ - Brk = 0x40, /* Break */ - Dlab = 0x80, /* Divisor Latch Access Bit */ -}; - -enum { /* Mcr */ - Dtr = 0x01, /* Data Terminal Ready */ - Rts = 0x02, /* Ready To Send */ - Out1 = 0x04, /* no longer in use */ - Ie = 0x08, /* IRQ Enable */ - Dm = 0x10, /* Diagnostic Mode loopback */ -}; - -enum { /* Lsr */ - Dr = 0x01, /* Data Ready */ - Oe = 0x02, /* Overrun Error */ - Pe = 0x04, /* Parity Error */ - Fe = 0x08, /* Framing Error */ - Bi = 0x10, /* Break Interrupt */ - Thre = 0x20, /* Thr Empty */ - Temt = 0x40, /* Tramsmitter Empty */ - FIFOerr = 0x80, /* error in receiver FIFO */ -}; - -enum { /* Msr */ - Dcts = 0x01, /* Delta Cts */ - Ddsr = 0x02, /* Delta Dsr */ - Teri = 0x04, /* Trailing Edge of Ri */ - Ddcd = 0x08, /* Delta Dcd */ - Cts = 0x10, /* Clear To Send */ - Dsr = 0x20, /* Data Set Ready */ - Ri = 0x40, /* Ring Indicator */ - Dcd = 0x80, /* Data Set Ready */ -}; - -typedef struct Ctlr { - int io; - int irq; - int tbdf; - int iena; - - uchar sticky[8]; - - Lock; - int hasfifo; - int checkfifo; - int fena; -} Ctlr; - -extern PhysUart i8250physuart; - -static Ctlr i8250ctlr[2] = { -{ .io = Uart0, - .irq = Uart0IRQ, - .tbdf = BUSUNKNOWN, }, - -{ .io = Uart1, - .irq = Uart1IRQ, - .tbdf = BUSUNKNOWN, }, -}; - -static Uart i8250uart[2] = { -{ .regs = &i8250ctlr[0], - .name = "COM1", - .freq = UartFREQ, - .phys = &i8250physuart, - .special= 0, - .next = &i8250uart[1], }, - -{ .regs = &i8250ctlr[1], - .name = "COM2", - .freq = UartFREQ, - .phys = &i8250physuart, - .special= 0, - .next = nil, }, -}; - -#define csr8r(c, r) inb((c)->io+(r)) -#define csr8w(c, r, v) outb((c)->io+(r), (c)->sticky[(r)]|(v)) - -static long -i8250status(Uart* uart, void* buf, long n, long offset) -{ - char *p; - Ctlr *ctlr; - uchar 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 -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 -i8250dtr(Uart* uart, int on) -{ - Ctlr *ctlr; - - /* - * Toggle DTR. - */ - ctlr = uart->regs; - if(on) - ctlr->sticky[Mcr] |= Dtr; - else - ctlr->sticky[Mcr] &= ~Dtr; - csr8w(ctlr, Mcr, 0); -} - -static void -i8250rts(Uart* uart, int on) -{ - Ctlr *ctlr; - - /* - * Toggle RTS. - */ - ctlr = uart->regs; - if(on) - ctlr->sticky[Mcr] |= Rts; - else - ctlr->sticky[Mcr] &= ~Rts; - csr8w(ctlr, Mcr, 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, ctlr->sticky[Ier]); - uart->modem = 1; - uart->cts = csr8r(ctlr, Msr) & Cts; - } - else{ - ctlr->sticky[Ier] &= ~Ems; - csr8w(ctlr, Ier, ctlr->sticky[Ier]); - uart->modem = 0; - uart->cts = 1; - } - iunlock(&uart->tlock); - - /* modem needs fifo */ - (*uart->phys->fifo)(uart, on); -} - -static int -i8250parity(Uart* uart, int parity) -{ - int lcr; - Ctlr *ctlr; - - ctlr = uart->regs; - lcr = ctlr->sticky[Lcr] & ~(Eps|Pen); - - switch(parity){ - case 'e': - lcr |= Eps|Pen; - break; - case 'o': - lcr |= Pen; - break; - case 'n': - break; - default: - return -1; - } - ctlr->sticky[Lcr] = lcr; - csr8w(ctlr, Lcr, 0); - - uart->parity = parity; - - return 0; -} - -static int -i8250stop(Uart* uart, int stop) -{ - int lcr; - Ctlr *ctlr; - - ctlr = uart->regs; - lcr = ctlr->sticky[Lcr] & ~Stb; - - switch(stop){ - case 1: - break; - case 2: - lcr |= Stb; - break; - default: - return -1; - } - ctlr->sticky[Lcr] = lcr; - csr8w(ctlr, Lcr, 0); - - uart->stop = stop; - - return 0; -} - -static int -i8250bits(Uart* uart, int bits) -{ - int lcr; - Ctlr *ctlr; - - ctlr = uart->regs; - lcr = ctlr->sticky[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; - } - ctlr->sticky[Lcr] = lcr; - csr8w(ctlr, Lcr, 0); - - uart->bits = bits; - - return 0; -} - -static int -i8250baud(Uart* uart, int baud) -{ - ulong bgc; - Ctlr *ctlr; - - /* - * Set the Baud rate by calculating and setting the Baud rate - * Generator Constant. This will work with fairly non-standard - * Baud rates. - */ - if(uart->freq == 0 || baud <= 0) - return -1; - bgc = (uart->freq+8*baud-1)/(16*baud); - - ctlr = uart->regs; - csr8w(ctlr, Lcr, Dlab); - outb(ctlr->io+Dlm, bgc>>8); - outb(ctlr->io+Dll, bgc); - csr8w(ctlr, Lcr, 0); - - uart->baud = baud; - - return 0; -} - -static void -i8250break(Uart* uart, int ms) -{ - Ctlr *ctlr; - - /* - * Send a break. - */ - if(ms <= 0) - ms = 200; - - ctlr = uart->regs; - csr8w(ctlr, Lcr, Brk); - tsleep(&up->sleep, return0, 0, ms); - csr8w(ctlr, Lcr, 0); -} - -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 -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 0x%2.2uX\n", iir); - break; - } - } -} - -static void -i8250disable(Uart* uart) -{ - Ctlr *ctlr; - - /* - * Turn off DTR and RTS, disable interrupts and fifos. - */ - (*uart->phys->dtr)(uart, 0); - (*uart->phys->rts)(uart, 0); - (*uart->phys->fifo)(uart, 0); - - ctlr = uart->regs; - ctlr->sticky[Ier] = 0; - csr8w(ctlr, Ier, ctlr->sticky[Ier]); - - if(ctlr->iena != 0){ - if(intrdisable(ctlr->irq, i8250interrupt, uart, ctlr->tbdf, uart->name) == 0) - ctlr->iena = 0; - } -} - -static void -i8250enable(Uart* uart, int ie) -{ - Ctlr *ctlr; - - ctlr = uart->regs; - - /* - * 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){ - intrenable(ctlr->irq, i8250interrupt, uart, ctlr->tbdf, uart->name); - ctlr->iena = 1; - } - ctlr->sticky[Ier] = Ethre|Erda; - ctlr->sticky[Mcr] |= Ie; - } - else{ - ctlr->sticky[Ier] = 0; - ctlr->sticky[Mcr] = 0; - } - csr8w(ctlr, Ier, ctlr->sticky[Ier]); - csr8w(ctlr, Mcr, ctlr->sticky[Mcr]); - - (*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); -} - -void* -i8250alloc(int io, int irq, int tbdf) -{ - Ctlr *ctlr; - - if((ctlr = malloc(sizeof(Ctlr))) != nil){ - ctlr->io = io; - ctlr->irq = irq; - ctlr->tbdf = tbdf; - } - - return ctlr; -} - -static Uart* -i8250pnp(void) -{ - return i8250uart; -} - -static int -i8250getc(Uart *uart) -{ - Ctlr *ctlr; - - ctlr = uart->regs; - while(!(csr8r(ctlr, Lsr)&Dr)) - delay(1); - return csr8r(ctlr, Rbr); -} - -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); -} - -PhysUart i8250physuart = { - .name = "i8250", - .pnp = i8250pnp, - .enable = i8250enable, - .disable = i8250disable, - .kick = i8250kick, - .dobreak = i8250break, - .baud = i8250baud, - .bits = i8250bits, - .stop = i8250stop, - .parity = i8250parity, - .modemctl = i8250modemctl, - .rts = i8250rts, - .dtr = i8250dtr, - .status = i8250status, - .fifo = i8250fifo, - .getc = i8250getc, - .putc = i8250putc, -}; - -void -i8250console(void) -{ - Uart *uart; - int n; - char *cmd, *p; - - if((p = getconf("console")) == nil) - return; - n = strtoul(p, &cmd, 0); - if(p == cmd) - return; - switch(n){ - default: - return; - case 0: - uart = &i8250uart[0]; - break; - case 1: - uart = &i8250uart[1]; - break; - } - - (*uart->phys->enable)(uart, 0); - uartctl(uart, "b9600 l8 pn s1"); - if(*cmd != '\0') - uartctl(uart, cmd); - - consuart = uart; - uart->console = 1; -} - -void -i8250mouse(char* which, int (*putc)(Queue*, int), int setb1200) -{ - char *p; - int port; - - port = strtol(which, &p, 0); - if(p == which || port < 0 || port > 1) - error(Ebadarg); - uartmouse(&i8250uart[port], putc, setb1200); -} - -void -i8250setmouseputc(char* which, int (*putc)(Queue*, int)) -{ - char *p; - int port; - - port = strtol(which, &p, 0); - if(p == which || port < 0 || port > 1) - error(Ebadarg); - uartsetmouseputc(&i8250uart[port], putc); - -} |
