19ef1f84bSDavid du Colombier #include "u.h"
29ef1f84bSDavid du Colombier #include "../port/lib.h"
39ef1f84bSDavid du Colombier #include "mem.h"
49ef1f84bSDavid du Colombier #include "dat.h"
59ef1f84bSDavid du Colombier #include "fns.h"
6277b6efdSDavid du Colombier #include "../port/error.h"
79ef1f84bSDavid du Colombier
89ef1f84bSDavid du Colombier /*
99ef1f84bSDavid du Colombier * 8250 UART and compatibles.
109ef1f84bSDavid du Colombier */
119ef1f84bSDavid du Colombier enum {
129ef1f84bSDavid du Colombier Uart0 = 0x3F8, /* COM1 */
139ef1f84bSDavid du Colombier Uart0IRQ = 4,
149ef1f84bSDavid du Colombier Uart1 = 0x2F8, /* COM2 */
159ef1f84bSDavid du Colombier Uart1IRQ = 3,
169ef1f84bSDavid du Colombier
179ef1f84bSDavid du Colombier UartFREQ = 1843200,
189ef1f84bSDavid du Colombier };
199ef1f84bSDavid du Colombier
209ef1f84bSDavid du Colombier enum { /* registers */
219ef1f84bSDavid du Colombier Rbr = 0, /* Receiver Buffer (RO) */
229ef1f84bSDavid du Colombier Thr = 0, /* Transmitter Holding (WO) */
239ef1f84bSDavid du Colombier Ier = 1, /* Interrupt Enable */
249ef1f84bSDavid du Colombier Iir = 2, /* Interrupt Identification (RO) */
259ef1f84bSDavid du Colombier Fcr = 2, /* FIFO Control (WO) */
269ef1f84bSDavid du Colombier Lcr = 3, /* Line Control */
279ef1f84bSDavid du Colombier Mcr = 4, /* Modem Control */
289ef1f84bSDavid du Colombier Lsr = 5, /* Line Status */
299ef1f84bSDavid du Colombier Msr = 6, /* Modem Status */
309ef1f84bSDavid du Colombier Scr = 7, /* Scratch Pad */
319ef1f84bSDavid du Colombier Dll = 0, /* Divisor Latch LSB */
329ef1f84bSDavid du Colombier Dlm = 1, /* Divisor Latch MSB */
339ef1f84bSDavid du Colombier };
349ef1f84bSDavid du Colombier
359ef1f84bSDavid du Colombier enum { /* Ier */
369ef1f84bSDavid du Colombier Erda = 0x01, /* Enable Received Data Available */
379ef1f84bSDavid du Colombier Ethre = 0x02, /* Enable Thr Empty */
389ef1f84bSDavid du Colombier Erls = 0x04, /* Enable Receiver Line Status */
399ef1f84bSDavid du Colombier Ems = 0x08, /* Enable Modem Status */
409ef1f84bSDavid du Colombier };
419ef1f84bSDavid du Colombier
429ef1f84bSDavid du Colombier enum { /* Iir */
439ef1f84bSDavid du Colombier Ims = 0x00, /* Ms interrupt */
449ef1f84bSDavid du Colombier Ip = 0x01, /* Interrupt Pending (not) */
459ef1f84bSDavid du Colombier Ithre = 0x02, /* Thr Empty */
469ef1f84bSDavid du Colombier Irda = 0x04, /* Received Data Available */
479ef1f84bSDavid du Colombier Irls = 0x06, /* Receiver Line Status */
489ef1f84bSDavid du Colombier Ictoi = 0x0C, /* Character Time-out Indication */
499ef1f84bSDavid du Colombier IirMASK = 0x3F,
509ef1f84bSDavid du Colombier Ifena = 0xC0, /* FIFOs enabled */
519ef1f84bSDavid du Colombier };
529ef1f84bSDavid du Colombier
539ef1f84bSDavid du Colombier enum { /* Fcr */
549ef1f84bSDavid du Colombier FIFOena = 0x01, /* FIFO enable */
559ef1f84bSDavid du Colombier FIFOrclr = 0x02, /* clear Rx FIFO */
569ef1f84bSDavid du Colombier FIFOtclr = 0x04, /* clear Tx FIFO */
579ef1f84bSDavid du Colombier FIFO1 = 0x00, /* Rx FIFO trigger level 1 byte */
589ef1f84bSDavid du Colombier FIFO4 = 0x40, /* 4 bytes */
599ef1f84bSDavid du Colombier FIFO8 = 0x80, /* 8 bytes */
609ef1f84bSDavid du Colombier FIFO14 = 0xC0, /* 14 bytes */
619ef1f84bSDavid du Colombier };
629ef1f84bSDavid du Colombier
639ef1f84bSDavid du Colombier enum { /* Lcr */
649ef1f84bSDavid du Colombier Wls5 = 0x00, /* Word Length Select 5 bits/byte */
659ef1f84bSDavid du Colombier Wls6 = 0x01, /* 6 bits/byte */
669ef1f84bSDavid du Colombier Wls7 = 0x02, /* 7 bits/byte */
679ef1f84bSDavid du Colombier Wls8 = 0x03, /* 8 bits/byte */
689ef1f84bSDavid du Colombier WlsMASK = 0x03,
699ef1f84bSDavid du Colombier Stb = 0x04, /* 2 stop bits */
709ef1f84bSDavid du Colombier Pen = 0x08, /* Parity Enable */
719ef1f84bSDavid du Colombier Eps = 0x10, /* Even Parity Select */
729ef1f84bSDavid du Colombier Stp = 0x20, /* Stick Parity */
739ef1f84bSDavid du Colombier Brk = 0x40, /* Break */
749ef1f84bSDavid du Colombier Dlab = 0x80, /* Divisor Latch Access Bit */
759ef1f84bSDavid du Colombier };
769ef1f84bSDavid du Colombier
779ef1f84bSDavid du Colombier enum { /* Mcr */
789ef1f84bSDavid du Colombier Dtr = 0x01, /* Data Terminal Ready */
799ef1f84bSDavid du Colombier Rts = 0x02, /* Ready To Send */
809ef1f84bSDavid du Colombier Out1 = 0x04, /* no longer in use */
819ef1f84bSDavid du Colombier Ie = 0x08, /* IRQ Enable */
829ef1f84bSDavid du Colombier Dm = 0x10, /* Diagnostic Mode loopback */
839ef1f84bSDavid du Colombier };
849ef1f84bSDavid du Colombier
859ef1f84bSDavid du Colombier enum { /* Lsr */
869ef1f84bSDavid du Colombier Dr = 0x01, /* Data Ready */
879ef1f84bSDavid du Colombier Oe = 0x02, /* Overrun Error */
889ef1f84bSDavid du Colombier Pe = 0x04, /* Parity Error */
899ef1f84bSDavid du Colombier Fe = 0x08, /* Framing Error */
909ef1f84bSDavid du Colombier Bi = 0x10, /* Break Interrupt */
919ef1f84bSDavid du Colombier Thre = 0x20, /* Thr Empty */
929ef1f84bSDavid du Colombier Temt = 0x40, /* Tramsmitter Empty */
939ef1f84bSDavid du Colombier FIFOerr = 0x80, /* error in receiver FIFO */
949ef1f84bSDavid du Colombier };
959ef1f84bSDavid du Colombier
969ef1f84bSDavid du Colombier enum { /* Msr */
979ef1f84bSDavid du Colombier Dcts = 0x01, /* Delta Cts */
989ef1f84bSDavid du Colombier Ddsr = 0x02, /* Delta Dsr */
999ef1f84bSDavid du Colombier Teri = 0x04, /* Trailing Edge of Ri */
1009ef1f84bSDavid du Colombier Ddcd = 0x08, /* Delta Dcd */
1019ef1f84bSDavid du Colombier Cts = 0x10, /* Clear To Send */
1029ef1f84bSDavid du Colombier Dsr = 0x20, /* Data Set Ready */
1039ef1f84bSDavid du Colombier Ri = 0x40, /* Ring Indicator */
1049ef1f84bSDavid du Colombier Dcd = 0x80, /* Data Set Ready */
1059ef1f84bSDavid du Colombier };
1069ef1f84bSDavid du Colombier
1079ef1f84bSDavid du Colombier typedef struct Ctlr {
1089ef1f84bSDavid du Colombier int io;
1099ef1f84bSDavid du Colombier int irq;
1109ef1f84bSDavid du Colombier int tbdf;
1119ef1f84bSDavid du Colombier int iena;
1129ef1f84bSDavid du Colombier void* vector;
1139ef1f84bSDavid du Colombier int poll;
1149ef1f84bSDavid du Colombier
1159ef1f84bSDavid du Colombier uchar sticky[8];
1169ef1f84bSDavid du Colombier
1179ef1f84bSDavid du Colombier Lock;
1189ef1f84bSDavid du Colombier int hasfifo;
1199ef1f84bSDavid du Colombier int checkfifo;
1209ef1f84bSDavid du Colombier int fena;
1219ef1f84bSDavid du Colombier } Ctlr;
1229ef1f84bSDavid du Colombier
1239ef1f84bSDavid du Colombier extern PhysUart i8250physuart;
1249ef1f84bSDavid du Colombier
1259ef1f84bSDavid du Colombier static Ctlr i8250ctlr[2] = {
1269ef1f84bSDavid du Colombier { .io = Uart0,
1279ef1f84bSDavid du Colombier .irq = Uart0IRQ,
1289ef1f84bSDavid du Colombier .tbdf = -1,
1299ef1f84bSDavid du Colombier .poll = 0, },
1309ef1f84bSDavid du Colombier
1319ef1f84bSDavid du Colombier { .io = Uart1,
1329ef1f84bSDavid du Colombier .irq = Uart1IRQ,
1339ef1f84bSDavid du Colombier .tbdf = -1,
1349ef1f84bSDavid du Colombier .poll = 0, },
1359ef1f84bSDavid du Colombier };
1369ef1f84bSDavid du Colombier
1379ef1f84bSDavid du Colombier static Uart i8250uart[2] = {
1389ef1f84bSDavid du Colombier { .regs = &i8250ctlr[0],
1399ef1f84bSDavid du Colombier .name = "COM1",
1409ef1f84bSDavid du Colombier .freq = UartFREQ,
1419ef1f84bSDavid du Colombier .phys = &i8250physuart,
1429ef1f84bSDavid du Colombier .special= 0,
1439ef1f84bSDavid du Colombier .next = &i8250uart[1], },
1449ef1f84bSDavid du Colombier
1459ef1f84bSDavid du Colombier { .regs = &i8250ctlr[1],
1469ef1f84bSDavid du Colombier .name = "COM2",
1479ef1f84bSDavid du Colombier .freq = UartFREQ,
1489ef1f84bSDavid du Colombier .phys = &i8250physuart,
1499ef1f84bSDavid du Colombier .special= 0,
1509ef1f84bSDavid du Colombier .next = nil, },
1519ef1f84bSDavid du Colombier };
1529ef1f84bSDavid du Colombier
1539ef1f84bSDavid du Colombier #define csr8r(c, r) inb((c)->io+(r))
1549ef1f84bSDavid du Colombier #define csr8w(c, r, v) outb((c)->io+(r), (c)->sticky[(r)]|(v))
1559ef1f84bSDavid du Colombier #define csr8o(c, r, v) outb((c)->io+(r), (v))
1569ef1f84bSDavid du Colombier
1579ef1f84bSDavid du Colombier static long
i8250status(Uart * uart,void * buf,long n,long offset)1589ef1f84bSDavid du Colombier i8250status(Uart* uart, void* buf, long n, long offset)
1599ef1f84bSDavid du Colombier {
1609ef1f84bSDavid du Colombier char *p;
1619ef1f84bSDavid du Colombier Ctlr *ctlr;
1629ef1f84bSDavid du Colombier uchar ier, lcr, mcr, msr;
1639ef1f84bSDavid du Colombier
1649ef1f84bSDavid du Colombier p = malloc(READSTR);
165277b6efdSDavid du Colombier if(p == nil)
166277b6efdSDavid du Colombier error(Enomem);
167277b6efdSDavid du Colombier ctlr = uart->regs;
1689ef1f84bSDavid du Colombier mcr = ctlr->sticky[Mcr];
1699ef1f84bSDavid du Colombier msr = csr8r(ctlr, Msr);
1709ef1f84bSDavid du Colombier ier = ctlr->sticky[Ier];
1719ef1f84bSDavid du Colombier lcr = ctlr->sticky[Lcr];
1729ef1f84bSDavid du Colombier snprint(p, READSTR,
1739ef1f84bSDavid du Colombier "b%d c%d d%d e%d l%d m%d p%c r%d s%d i%d\n"
1749ef1f84bSDavid du Colombier "dev(%d) type(%d) framing(%d) overruns(%d) "
1759ef1f84bSDavid du Colombier "berr(%d) serr(%d)%s%s%s%s\n",
1769ef1f84bSDavid du Colombier
1779ef1f84bSDavid du Colombier uart->baud,
1789ef1f84bSDavid du Colombier uart->hup_dcd,
1799ef1f84bSDavid du Colombier (msr & Dsr) != 0,
1809ef1f84bSDavid du Colombier uart->hup_dsr,
1819ef1f84bSDavid du Colombier (lcr & WlsMASK) + 5,
1829ef1f84bSDavid du Colombier (ier & Ems) != 0,
1839ef1f84bSDavid du Colombier (lcr & Pen) ? ((lcr & Eps) ? 'e': 'o'): 'n',
1849ef1f84bSDavid du Colombier (mcr & Rts) != 0,
1859ef1f84bSDavid du Colombier (lcr & Stb) ? 2: 1,
1869ef1f84bSDavid du Colombier ctlr->fena,
1879ef1f84bSDavid du Colombier
1889ef1f84bSDavid du Colombier uart->dev,
1899ef1f84bSDavid du Colombier uart->type,
1909ef1f84bSDavid du Colombier uart->ferr,
1919ef1f84bSDavid du Colombier uart->oerr,
1929ef1f84bSDavid du Colombier uart->berr,
1939ef1f84bSDavid du Colombier uart->serr,
1949ef1f84bSDavid du Colombier (msr & Cts) ? " cts": "",
1959ef1f84bSDavid du Colombier (msr & Dsr) ? " dsr": "",
1969ef1f84bSDavid du Colombier (msr & Dcd) ? " dcd": "",
1979ef1f84bSDavid du Colombier (msr & Ri) ? " ring": ""
1989ef1f84bSDavid du Colombier );
1999ef1f84bSDavid du Colombier n = readstr(offset, buf, n, p);
2009ef1f84bSDavid du Colombier free(p);
2019ef1f84bSDavid du Colombier
2029ef1f84bSDavid du Colombier return n;
2039ef1f84bSDavid du Colombier }
2049ef1f84bSDavid du Colombier
2059ef1f84bSDavid du Colombier static void
i8250fifo(Uart * uart,int level)2069ef1f84bSDavid du Colombier i8250fifo(Uart* uart, int level)
2079ef1f84bSDavid du Colombier {
2089ef1f84bSDavid du Colombier Ctlr *ctlr;
2099ef1f84bSDavid du Colombier
2109ef1f84bSDavid du Colombier ctlr = uart->regs;
2119ef1f84bSDavid du Colombier if(ctlr->hasfifo == 0)
2129ef1f84bSDavid du Colombier return;
2139ef1f84bSDavid du Colombier
2149ef1f84bSDavid du Colombier /*
2159ef1f84bSDavid du Colombier * Changing the FIFOena bit in Fcr flushes data
2169ef1f84bSDavid du Colombier * from both receive and transmit FIFOs; there's
2179ef1f84bSDavid du Colombier * no easy way to guarantee not losing data on
2189ef1f84bSDavid du Colombier * the receive side, but it's possible to wait until
2199ef1f84bSDavid du Colombier * the transmitter is really empty.
2209ef1f84bSDavid du Colombier */
2219ef1f84bSDavid du Colombier ilock(ctlr);
2229ef1f84bSDavid du Colombier while(!(csr8r(ctlr, Lsr) & Temt))
2239ef1f84bSDavid du Colombier ;
2249ef1f84bSDavid du Colombier
2259ef1f84bSDavid du Colombier /*
2269ef1f84bSDavid du Colombier * Set the trigger level, default is the max.
2279ef1f84bSDavid du Colombier * value.
2289ef1f84bSDavid du Colombier * Some UARTs require FIFOena to be set before
2299ef1f84bSDavid du Colombier * other bits can take effect, so set it twice.
2309ef1f84bSDavid du Colombier */
2319ef1f84bSDavid du Colombier ctlr->fena = level;
2329ef1f84bSDavid du Colombier switch(level){
2339ef1f84bSDavid du Colombier case 0:
2349ef1f84bSDavid du Colombier break;
2359ef1f84bSDavid du Colombier case 1:
2369ef1f84bSDavid du Colombier level = FIFO1|FIFOena;
2379ef1f84bSDavid du Colombier break;
2389ef1f84bSDavid du Colombier case 4:
2399ef1f84bSDavid du Colombier level = FIFO4|FIFOena;
2409ef1f84bSDavid du Colombier break;
2419ef1f84bSDavid du Colombier case 8:
2429ef1f84bSDavid du Colombier level = FIFO8|FIFOena;
2439ef1f84bSDavid du Colombier break;
2449ef1f84bSDavid du Colombier default:
2459ef1f84bSDavid du Colombier level = FIFO14|FIFOena;
2469ef1f84bSDavid du Colombier break;
2479ef1f84bSDavid du Colombier }
2489ef1f84bSDavid du Colombier csr8w(ctlr, Fcr, level);
2499ef1f84bSDavid du Colombier csr8w(ctlr, Fcr, level);
2509ef1f84bSDavid du Colombier iunlock(ctlr);
2519ef1f84bSDavid du Colombier }
2529ef1f84bSDavid du Colombier
2539ef1f84bSDavid du Colombier static void
i8250dtr(Uart * uart,int on)2549ef1f84bSDavid du Colombier i8250dtr(Uart* uart, int on)
2559ef1f84bSDavid du Colombier {
2569ef1f84bSDavid du Colombier Ctlr *ctlr;
2579ef1f84bSDavid du Colombier
2589ef1f84bSDavid du Colombier /*
2599ef1f84bSDavid du Colombier * Toggle DTR.
2609ef1f84bSDavid du Colombier */
2619ef1f84bSDavid du Colombier ctlr = uart->regs;
2629ef1f84bSDavid du Colombier if(on)
2639ef1f84bSDavid du Colombier ctlr->sticky[Mcr] |= Dtr;
2649ef1f84bSDavid du Colombier else
2659ef1f84bSDavid du Colombier ctlr->sticky[Mcr] &= ~Dtr;
2669ef1f84bSDavid du Colombier csr8w(ctlr, Mcr, 0);
2679ef1f84bSDavid du Colombier }
2689ef1f84bSDavid du Colombier
2699ef1f84bSDavid du Colombier static void
i8250rts(Uart * uart,int on)2709ef1f84bSDavid du Colombier i8250rts(Uart* uart, int on)
2719ef1f84bSDavid du Colombier {
2729ef1f84bSDavid du Colombier Ctlr *ctlr;
2739ef1f84bSDavid du Colombier
2749ef1f84bSDavid du Colombier /*
2759ef1f84bSDavid du Colombier * Toggle RTS.
2769ef1f84bSDavid du Colombier */
2779ef1f84bSDavid du Colombier ctlr = uart->regs;
2789ef1f84bSDavid du Colombier if(on)
2799ef1f84bSDavid du Colombier ctlr->sticky[Mcr] |= Rts;
2809ef1f84bSDavid du Colombier else
2819ef1f84bSDavid du Colombier ctlr->sticky[Mcr] &= ~Rts;
2829ef1f84bSDavid du Colombier csr8w(ctlr, Mcr, 0);
2839ef1f84bSDavid du Colombier }
2849ef1f84bSDavid du Colombier
2859ef1f84bSDavid du Colombier static void
i8250modemctl(Uart * uart,int on)2869ef1f84bSDavid du Colombier i8250modemctl(Uart* uart, int on)
2879ef1f84bSDavid du Colombier {
2889ef1f84bSDavid du Colombier Ctlr *ctlr;
2899ef1f84bSDavid du Colombier
2909ef1f84bSDavid du Colombier ctlr = uart->regs;
2919ef1f84bSDavid du Colombier ilock(&uart->tlock);
2929ef1f84bSDavid du Colombier if(on){
2939ef1f84bSDavid du Colombier ctlr->sticky[Ier] |= Ems;
2949ef1f84bSDavid du Colombier csr8w(ctlr, Ier, ctlr->sticky[Ier]);
2959ef1f84bSDavid du Colombier uart->modem = 1;
2969ef1f84bSDavid du Colombier uart->cts = csr8r(ctlr, Msr) & Cts;
2979ef1f84bSDavid du Colombier }
2989ef1f84bSDavid du Colombier else{
2999ef1f84bSDavid du Colombier ctlr->sticky[Ier] &= ~Ems;
3009ef1f84bSDavid du Colombier csr8w(ctlr, Ier, ctlr->sticky[Ier]);
3019ef1f84bSDavid du Colombier uart->modem = 0;
3029ef1f84bSDavid du Colombier uart->cts = 1;
3039ef1f84bSDavid du Colombier }
3049ef1f84bSDavid du Colombier iunlock(&uart->tlock);
3059ef1f84bSDavid du Colombier
3069ef1f84bSDavid du Colombier /* modem needs fifo */
3079ef1f84bSDavid du Colombier (*uart->phys->fifo)(uart, on);
3089ef1f84bSDavid du Colombier }
3099ef1f84bSDavid du Colombier
3109ef1f84bSDavid du Colombier static int
i8250parity(Uart * uart,int parity)3119ef1f84bSDavid du Colombier i8250parity(Uart* uart, int parity)
3129ef1f84bSDavid du Colombier {
3139ef1f84bSDavid du Colombier int lcr;
3149ef1f84bSDavid du Colombier Ctlr *ctlr;
3159ef1f84bSDavid du Colombier
3169ef1f84bSDavid du Colombier ctlr = uart->regs;
3179ef1f84bSDavid du Colombier lcr = ctlr->sticky[Lcr] & ~(Eps|Pen);
3189ef1f84bSDavid du Colombier
3199ef1f84bSDavid du Colombier switch(parity){
3209ef1f84bSDavid du Colombier case 'e':
3219ef1f84bSDavid du Colombier lcr |= Eps|Pen;
3229ef1f84bSDavid du Colombier break;
3239ef1f84bSDavid du Colombier case 'o':
3249ef1f84bSDavid du Colombier lcr |= Pen;
3259ef1f84bSDavid du Colombier break;
3269ef1f84bSDavid du Colombier case 'n':
3279ef1f84bSDavid du Colombier break;
3289ef1f84bSDavid du Colombier default:
3299ef1f84bSDavid du Colombier return -1;
3309ef1f84bSDavid du Colombier }
3319ef1f84bSDavid du Colombier ctlr->sticky[Lcr] = lcr;
3329ef1f84bSDavid du Colombier csr8w(ctlr, Lcr, 0);
3339ef1f84bSDavid du Colombier
3349ef1f84bSDavid du Colombier uart->parity = parity;
3359ef1f84bSDavid du Colombier
3369ef1f84bSDavid du Colombier return 0;
3379ef1f84bSDavid du Colombier }
3389ef1f84bSDavid du Colombier
3399ef1f84bSDavid du Colombier static int
i8250stop(Uart * uart,int stop)3409ef1f84bSDavid du Colombier i8250stop(Uart* uart, int stop)
3419ef1f84bSDavid du Colombier {
3429ef1f84bSDavid du Colombier int lcr;
3439ef1f84bSDavid du Colombier Ctlr *ctlr;
3449ef1f84bSDavid du Colombier
3459ef1f84bSDavid du Colombier ctlr = uart->regs;
3469ef1f84bSDavid du Colombier lcr = ctlr->sticky[Lcr] & ~Stb;
3479ef1f84bSDavid du Colombier
3489ef1f84bSDavid du Colombier switch(stop){
3499ef1f84bSDavid du Colombier case 1:
3509ef1f84bSDavid du Colombier break;
3519ef1f84bSDavid du Colombier case 2:
3529ef1f84bSDavid du Colombier lcr |= Stb;
3539ef1f84bSDavid du Colombier break;
3549ef1f84bSDavid du Colombier default:
3559ef1f84bSDavid du Colombier return -1;
3569ef1f84bSDavid du Colombier }
3579ef1f84bSDavid du Colombier ctlr->sticky[Lcr] = lcr;
3589ef1f84bSDavid du Colombier csr8w(ctlr, Lcr, 0);
3599ef1f84bSDavid du Colombier
3609ef1f84bSDavid du Colombier uart->stop = stop;
3619ef1f84bSDavid du Colombier
3629ef1f84bSDavid du Colombier return 0;
3639ef1f84bSDavid du Colombier }
3649ef1f84bSDavid du Colombier
3659ef1f84bSDavid du Colombier static int
i8250bits(Uart * uart,int bits)3669ef1f84bSDavid du Colombier i8250bits(Uart* uart, int bits)
3679ef1f84bSDavid du Colombier {
3689ef1f84bSDavid du Colombier int lcr;
3699ef1f84bSDavid du Colombier Ctlr *ctlr;
3709ef1f84bSDavid du Colombier
3719ef1f84bSDavid du Colombier ctlr = uart->regs;
3729ef1f84bSDavid du Colombier lcr = ctlr->sticky[Lcr] & ~WlsMASK;
3739ef1f84bSDavid du Colombier
3749ef1f84bSDavid du Colombier switch(bits){
3759ef1f84bSDavid du Colombier case 5:
3769ef1f84bSDavid du Colombier lcr |= Wls5;
3779ef1f84bSDavid du Colombier break;
3789ef1f84bSDavid du Colombier case 6:
3799ef1f84bSDavid du Colombier lcr |= Wls6;
3809ef1f84bSDavid du Colombier break;
3819ef1f84bSDavid du Colombier case 7:
3829ef1f84bSDavid du Colombier lcr |= Wls7;
3839ef1f84bSDavid du Colombier break;
3849ef1f84bSDavid du Colombier case 8:
3859ef1f84bSDavid du Colombier lcr |= Wls8;
3869ef1f84bSDavid du Colombier break;
3879ef1f84bSDavid du Colombier default:
3889ef1f84bSDavid du Colombier return -1;
3899ef1f84bSDavid du Colombier }
3909ef1f84bSDavid du Colombier ctlr->sticky[Lcr] = lcr;
3919ef1f84bSDavid du Colombier csr8w(ctlr, Lcr, 0);
3929ef1f84bSDavid du Colombier
3939ef1f84bSDavid du Colombier uart->bits = bits;
3949ef1f84bSDavid du Colombier
3959ef1f84bSDavid du Colombier return 0;
3969ef1f84bSDavid du Colombier }
3979ef1f84bSDavid du Colombier
3989ef1f84bSDavid du Colombier static int
i8250baud(Uart * uart,int baud)3999ef1f84bSDavid du Colombier i8250baud(Uart* uart, int baud)
4009ef1f84bSDavid du Colombier {
4019ef1f84bSDavid du Colombier ulong bgc;
4029ef1f84bSDavid du Colombier Ctlr *ctlr;
4039ef1f84bSDavid du Colombier
4049ef1f84bSDavid du Colombier /*
4059ef1f84bSDavid du Colombier * Set the Baud rate by calculating and setting the Baud rate
4069ef1f84bSDavid du Colombier * Generator Constant. This will work with fairly non-standard
4079ef1f84bSDavid du Colombier * Baud rates.
4089ef1f84bSDavid du Colombier */
4099ef1f84bSDavid du Colombier if(uart->freq == 0 || baud <= 0)
4109ef1f84bSDavid du Colombier return -1;
4119ef1f84bSDavid du Colombier bgc = (uart->freq+8*baud-1)/(16*baud);
4129ef1f84bSDavid du Colombier
4139ef1f84bSDavid du Colombier ctlr = uart->regs;
4149ef1f84bSDavid du Colombier csr8w(ctlr, Lcr, Dlab);
4159ef1f84bSDavid du Colombier csr8o(ctlr, Dlm, bgc>>8);
4169ef1f84bSDavid du Colombier csr8o(ctlr, Dll, bgc);
4179ef1f84bSDavid du Colombier csr8w(ctlr, Lcr, 0);
4189ef1f84bSDavid du Colombier
4199ef1f84bSDavid du Colombier uart->baud = baud;
4209ef1f84bSDavid du Colombier
4219ef1f84bSDavid du Colombier return 0;
4229ef1f84bSDavid du Colombier }
4239ef1f84bSDavid du Colombier
4249ef1f84bSDavid du Colombier static void
i8250break(Uart * uart,int ms)4259ef1f84bSDavid du Colombier i8250break(Uart* uart, int ms)
4269ef1f84bSDavid du Colombier {
4279ef1f84bSDavid du Colombier Ctlr *ctlr;
4289ef1f84bSDavid du Colombier
4299ef1f84bSDavid du Colombier /*
4309ef1f84bSDavid du Colombier * Send a break.
4319ef1f84bSDavid du Colombier */
4329ef1f84bSDavid du Colombier if(ms <= 0)
4339ef1f84bSDavid du Colombier ms = 200;
4349ef1f84bSDavid du Colombier
4359ef1f84bSDavid du Colombier ctlr = uart->regs;
4369ef1f84bSDavid du Colombier csr8w(ctlr, Lcr, Brk);
4379ef1f84bSDavid du Colombier tsleep(&up->sleep, return0, 0, ms);
4389ef1f84bSDavid du Colombier csr8w(ctlr, Lcr, 0);
4399ef1f84bSDavid du Colombier }
4409ef1f84bSDavid du Colombier
4419ef1f84bSDavid du Colombier static void
i8250kick(Uart * uart)4429ef1f84bSDavid du Colombier i8250kick(Uart* uart)
4439ef1f84bSDavid du Colombier {
4449ef1f84bSDavid du Colombier int i;
4459ef1f84bSDavid du Colombier Ctlr *ctlr;
4469ef1f84bSDavid du Colombier
4479ef1f84bSDavid du Colombier if(uart->cts == 0 || uart->blocked)
4489ef1f84bSDavid du Colombier return;
4499ef1f84bSDavid du Colombier
4509ef1f84bSDavid du Colombier /*
4519ef1f84bSDavid du Colombier * 128 here is an arbitrary limit to make sure
4529ef1f84bSDavid du Colombier * we don't stay in this loop too long. If the
4539ef1f84bSDavid du Colombier * chip's output queue is longer than 128, too
4549ef1f84bSDavid du Colombier * bad -- presotto
4559ef1f84bSDavid du Colombier */
4569ef1f84bSDavid du Colombier ctlr = uart->regs;
4579ef1f84bSDavid du Colombier for(i = 0; i < 128; i++){
4589ef1f84bSDavid du Colombier if(!(csr8r(ctlr, Lsr) & Thre))
4599ef1f84bSDavid du Colombier break;
4609ef1f84bSDavid du Colombier if(uart->op >= uart->oe && uartstageoutput(uart) == 0)
4619ef1f84bSDavid du Colombier break;
4629ef1f84bSDavid du Colombier csr8o(ctlr, Thr, *(uart->op++));
4639ef1f84bSDavid du Colombier }
4649ef1f84bSDavid du Colombier }
4659ef1f84bSDavid du Colombier
4669ef1f84bSDavid du Colombier static void
i8250interrupt(Ureg *,void * arg)4679ef1f84bSDavid du Colombier i8250interrupt(Ureg*, void* arg)
4689ef1f84bSDavid du Colombier {
4699ef1f84bSDavid du Colombier Ctlr *ctlr;
4709ef1f84bSDavid du Colombier Uart *uart;
4719ef1f84bSDavid du Colombier int iir, lsr, old, r;
4729ef1f84bSDavid du Colombier
4739ef1f84bSDavid du Colombier uart = arg;
4749ef1f84bSDavid du Colombier
4759ef1f84bSDavid du Colombier ctlr = uart->regs;
4769ef1f84bSDavid du Colombier for(iir = csr8r(ctlr, Iir); !(iir & Ip); iir = csr8r(ctlr, Iir)){
4779ef1f84bSDavid du Colombier switch(iir & IirMASK){
4789ef1f84bSDavid du Colombier case Ims: /* Ms interrupt */
4799ef1f84bSDavid du Colombier r = csr8r(ctlr, Msr);
4809ef1f84bSDavid du Colombier if(r & Dcts){
4819ef1f84bSDavid du Colombier ilock(&uart->tlock);
4829ef1f84bSDavid du Colombier old = uart->cts;
4839ef1f84bSDavid du Colombier uart->cts = r & Cts;
4849ef1f84bSDavid du Colombier if(old == 0 && uart->cts)
4859ef1f84bSDavid du Colombier uart->ctsbackoff = 2;
4869ef1f84bSDavid du Colombier iunlock(&uart->tlock);
4879ef1f84bSDavid du Colombier }
4889ef1f84bSDavid du Colombier if(r & Ddsr){
4899ef1f84bSDavid du Colombier old = r & Dsr;
4909ef1f84bSDavid du Colombier if(uart->hup_dsr && uart->dsr && !old)
4919ef1f84bSDavid du Colombier uart->dohup = 1;
4929ef1f84bSDavid du Colombier uart->dsr = old;
4939ef1f84bSDavid du Colombier }
4949ef1f84bSDavid du Colombier if(r & Ddcd){
4959ef1f84bSDavid du Colombier old = r & Dcd;
4969ef1f84bSDavid du Colombier if(uart->hup_dcd && uart->dcd && !old)
4979ef1f84bSDavid du Colombier uart->dohup = 1;
4989ef1f84bSDavid du Colombier uart->dcd = old;
4999ef1f84bSDavid du Colombier }
5009ef1f84bSDavid du Colombier break;
5019ef1f84bSDavid du Colombier case Ithre: /* Thr Empty */
5029ef1f84bSDavid du Colombier uartkick(uart);
5039ef1f84bSDavid du Colombier break;
5049ef1f84bSDavid du Colombier case Irda: /* Received Data Available */
5059ef1f84bSDavid du Colombier case Irls: /* Receiver Line Status */
5069ef1f84bSDavid du Colombier case Ictoi: /* Character Time-out Indication */
5079ef1f84bSDavid du Colombier /*
5089ef1f84bSDavid du Colombier * Consume any received data.
5099ef1f84bSDavid du Colombier * If the received byte came in with a break,
5109ef1f84bSDavid du Colombier * parity or framing error, throw it away;
5119ef1f84bSDavid du Colombier * overrun is an indication that something has
5129ef1f84bSDavid du Colombier * already been tossed.
5139ef1f84bSDavid du Colombier */
5149ef1f84bSDavid du Colombier while((lsr = csr8r(ctlr, Lsr)) & Dr){
5159ef1f84bSDavid du Colombier if(lsr & (FIFOerr|Oe))
5169ef1f84bSDavid du Colombier uart->oerr++;
5179ef1f84bSDavid du Colombier if(lsr & Pe)
5189ef1f84bSDavid du Colombier uart->perr++;
5199ef1f84bSDavid du Colombier if(lsr & Fe)
5209ef1f84bSDavid du Colombier uart->ferr++;
5219ef1f84bSDavid du Colombier r = csr8r(ctlr, Rbr);
5229ef1f84bSDavid du Colombier if(!(lsr & (Bi|Fe|Pe)))
5239ef1f84bSDavid du Colombier uartrecv(uart, r);
5249ef1f84bSDavid du Colombier }
5259ef1f84bSDavid du Colombier break;
5269ef1f84bSDavid du Colombier
5279ef1f84bSDavid du Colombier default:
5289ef1f84bSDavid du Colombier iprint("weird uart interrupt %#2.2ux\n", iir);
5299ef1f84bSDavid du Colombier break;
5309ef1f84bSDavid du Colombier }
5319ef1f84bSDavid du Colombier }
5329ef1f84bSDavid du Colombier }
5339ef1f84bSDavid du Colombier
5349ef1f84bSDavid du Colombier static void
i8250disable(Uart * uart)5359ef1f84bSDavid du Colombier i8250disable(Uart* uart)
5369ef1f84bSDavid du Colombier {
5379ef1f84bSDavid du Colombier Ctlr *ctlr;
5389ef1f84bSDavid du Colombier
5399ef1f84bSDavid du Colombier /*
5409ef1f84bSDavid du Colombier * Turn off DTR and RTS, disable interrupts and fifos.
5419ef1f84bSDavid du Colombier */
5429ef1f84bSDavid du Colombier (*uart->phys->dtr)(uart, 0);
5439ef1f84bSDavid du Colombier (*uart->phys->rts)(uart, 0);
5449ef1f84bSDavid du Colombier (*uart->phys->fifo)(uart, 0);
5459ef1f84bSDavid du Colombier
5469ef1f84bSDavid du Colombier ctlr = uart->regs;
5479ef1f84bSDavid du Colombier ctlr->sticky[Ier] = 0;
5489ef1f84bSDavid du Colombier csr8w(ctlr, Ier, ctlr->sticky[Ier]);
5499ef1f84bSDavid du Colombier
5509ef1f84bSDavid du Colombier if(ctlr->iena != 0){
5519ef1f84bSDavid du Colombier if(intrdisable(ctlr->vector) == 0)
5529ef1f84bSDavid du Colombier ctlr->iena = 0;
5539ef1f84bSDavid du Colombier }
5549ef1f84bSDavid du Colombier }
5559ef1f84bSDavid du Colombier
5569ef1f84bSDavid du Colombier static void
i8250enable(Uart * uart,int ie)5579ef1f84bSDavid du Colombier i8250enable(Uart* uart, int ie)
5589ef1f84bSDavid du Colombier {
5599ef1f84bSDavid du Colombier Ctlr *ctlr;
5609ef1f84bSDavid du Colombier
5619ef1f84bSDavid du Colombier ctlr = uart->regs;
5629ef1f84bSDavid du Colombier
5639ef1f84bSDavid du Colombier /*
5649ef1f84bSDavid du Colombier * Check if there is a FIFO.
5659ef1f84bSDavid du Colombier * Changing the FIFOena bit in Fcr flushes data
5669ef1f84bSDavid du Colombier * from both receive and transmit FIFOs; there's
5679ef1f84bSDavid du Colombier * no easy way to guarantee not losing data on
5689ef1f84bSDavid du Colombier * the receive side, but it's possible to wait until
5699ef1f84bSDavid du Colombier * the transmitter is really empty.
5709ef1f84bSDavid du Colombier * Also, reading the Iir outwith i8250interrupt()
5719ef1f84bSDavid du Colombier * can be dangerous, but this should only happen
572277b6efdSDavid du Colombier * once before interrupts are enabled.
5739ef1f84bSDavid du Colombier */
5749ef1f84bSDavid du Colombier ilock(ctlr);
5759ef1f84bSDavid du Colombier if(!ctlr->checkfifo){
5769ef1f84bSDavid du Colombier /*
5779ef1f84bSDavid du Colombier * Wait until the transmitter is really empty.
5789ef1f84bSDavid du Colombier */
5799ef1f84bSDavid du Colombier while(!(csr8r(ctlr, Lsr) & Temt))
5809ef1f84bSDavid du Colombier ;
5819ef1f84bSDavid du Colombier csr8w(ctlr, Fcr, FIFOena);
5829ef1f84bSDavid du Colombier if(csr8r(ctlr, Iir) & Ifena)
5839ef1f84bSDavid du Colombier ctlr->hasfifo = 1;
5849ef1f84bSDavid du Colombier csr8w(ctlr, Fcr, 0);
5859ef1f84bSDavid du Colombier ctlr->checkfifo = 1;
5869ef1f84bSDavid du Colombier }
5879ef1f84bSDavid du Colombier iunlock(ctlr);
5889ef1f84bSDavid du Colombier
5899ef1f84bSDavid du Colombier /*
5909ef1f84bSDavid du Colombier * Enable interrupts and turn on DTR and RTS.
5919ef1f84bSDavid du Colombier * Be careful if this is called to set up a polled serial line
5929ef1f84bSDavid du Colombier * early on not to try to enable interrupts as interrupt-
5939ef1f84bSDavid du Colombier * -enabling mechanisms might not be set up yet.
5949ef1f84bSDavid du Colombier */
5959ef1f84bSDavid du Colombier if(ie){
5969ef1f84bSDavid du Colombier if(ctlr->iena == 0 && !ctlr->poll){
5979ef1f84bSDavid du Colombier ctlr->vector = intrenable(ctlr->irq, i8250interrupt, uart, ctlr->tbdf, uart->name);
5989ef1f84bSDavid du Colombier ctlr->iena = 1;
5999ef1f84bSDavid du Colombier }
6009ef1f84bSDavid du Colombier ctlr->sticky[Ier] = Ethre|Erda;
6019ef1f84bSDavid du Colombier ctlr->sticky[Mcr] |= Ie;
6029ef1f84bSDavid du Colombier }
6039ef1f84bSDavid du Colombier else{
6049ef1f84bSDavid du Colombier ctlr->sticky[Ier] = 0;
6059ef1f84bSDavid du Colombier ctlr->sticky[Mcr] = 0;
6069ef1f84bSDavid du Colombier }
6079ef1f84bSDavid du Colombier csr8w(ctlr, Ier, ctlr->sticky[Ier]);
6089ef1f84bSDavid du Colombier csr8w(ctlr, Mcr, ctlr->sticky[Mcr]);
6099ef1f84bSDavid du Colombier
6109ef1f84bSDavid du Colombier (*uart->phys->dtr)(uart, 1);
6119ef1f84bSDavid du Colombier (*uart->phys->rts)(uart, 1);
6129ef1f84bSDavid du Colombier
6139ef1f84bSDavid du Colombier /*
6149ef1f84bSDavid du Colombier * During startup, the i8259 interrupt controller is reset.
6159ef1f84bSDavid du Colombier * This may result in a lost interrupt from the i8250 uart.
6169ef1f84bSDavid du Colombier * The i8250 thinks the interrupt is still outstanding and does not
6179ef1f84bSDavid du Colombier * generate any further interrupts. The workaround is to call the
6189ef1f84bSDavid du Colombier * interrupt handler to clear any pending interrupt events.
6199ef1f84bSDavid du Colombier * Note: this must be done after setting Ier.
6209ef1f84bSDavid du Colombier */
6219ef1f84bSDavid du Colombier if(ie)
6229ef1f84bSDavid du Colombier i8250interrupt(nil, uart);
6239ef1f84bSDavid du Colombier }
6249ef1f84bSDavid du Colombier
6259ef1f84bSDavid du Colombier void*
i8250alloc(int io,int irq,int tbdf)6269ef1f84bSDavid du Colombier i8250alloc(int io, int irq, int tbdf)
6279ef1f84bSDavid du Colombier {
6289ef1f84bSDavid du Colombier Ctlr *ctlr;
6299ef1f84bSDavid du Colombier
6309ef1f84bSDavid du Colombier if((ctlr = malloc(sizeof(Ctlr))) != nil){
6319ef1f84bSDavid du Colombier ctlr->io = io;
6329ef1f84bSDavid du Colombier ctlr->irq = irq;
6339ef1f84bSDavid du Colombier ctlr->tbdf = tbdf;
6349ef1f84bSDavid du Colombier }
6359ef1f84bSDavid du Colombier
6369ef1f84bSDavid du Colombier return ctlr;
6379ef1f84bSDavid du Colombier }
6389ef1f84bSDavid du Colombier
6399ef1f84bSDavid du Colombier static Uart*
i8250pnp(void)6409ef1f84bSDavid du Colombier i8250pnp(void)
6419ef1f84bSDavid du Colombier {
6429ef1f84bSDavid du Colombier int i;
6439ef1f84bSDavid du Colombier Ctlr *ctlr;
6449ef1f84bSDavid du Colombier Uart *head, *uart;
6459ef1f84bSDavid du Colombier
6469ef1f84bSDavid du Colombier head = i8250uart;
6479ef1f84bSDavid du Colombier for(i = 0; i < nelem(i8250uart); i++){
6489ef1f84bSDavid du Colombier /*
6499ef1f84bSDavid du Colombier * Does it exist?
6509ef1f84bSDavid du Colombier * Should be able to write/read the Scratch Pad
6519ef1f84bSDavid du Colombier * and reserve the I/O space.
6529ef1f84bSDavid du Colombier */
6539ef1f84bSDavid du Colombier uart = &i8250uart[i];
6549ef1f84bSDavid du Colombier ctlr = uart->regs;
6559ef1f84bSDavid du Colombier csr8o(ctlr, Scr, 0x55);
6569ef1f84bSDavid du Colombier if(csr8r(ctlr, Scr) == 0x55)
6579ef1f84bSDavid du Colombier continue;
6589ef1f84bSDavid du Colombier if(ioalloc(ctlr->io, 8, 0, uart->name) < 0)
6599ef1f84bSDavid du Colombier continue;
6609ef1f84bSDavid du Colombier if(uart == head)
6619ef1f84bSDavid du Colombier head = uart->next;
6629ef1f84bSDavid du Colombier else
6639ef1f84bSDavid du Colombier (uart-1)->next = uart->next;
6649ef1f84bSDavid du Colombier }
6659ef1f84bSDavid du Colombier
6669ef1f84bSDavid du Colombier return head;
6679ef1f84bSDavid du Colombier }
6689ef1f84bSDavid du Colombier
6699ef1f84bSDavid du Colombier static int
i8250getc(Uart * uart)6709ef1f84bSDavid du Colombier i8250getc(Uart* uart)
6719ef1f84bSDavid du Colombier {
6729ef1f84bSDavid du Colombier Ctlr *ctlr;
6739ef1f84bSDavid du Colombier
6749ef1f84bSDavid du Colombier ctlr = uart->regs;
6759ef1f84bSDavid du Colombier while(!(csr8r(ctlr, Lsr) & Dr))
6769ef1f84bSDavid du Colombier delay(1);
6779ef1f84bSDavid du Colombier return csr8r(ctlr, Rbr);
6789ef1f84bSDavid du Colombier }
6799ef1f84bSDavid du Colombier
6809ef1f84bSDavid du Colombier static void
i8250putc(Uart * uart,int c)6819ef1f84bSDavid du Colombier i8250putc(Uart* uart, int c)
6829ef1f84bSDavid du Colombier {
6839ef1f84bSDavid du Colombier int i;
6849ef1f84bSDavid du Colombier Ctlr *ctlr;
6859ef1f84bSDavid du Colombier
6869ef1f84bSDavid du Colombier ctlr = uart->regs;
6879ef1f84bSDavid du Colombier for(i = 0; !(csr8r(ctlr, Lsr) & Thre) && i < 128; i++)
6889ef1f84bSDavid du Colombier delay(1);
6899ef1f84bSDavid du Colombier csr8o(ctlr, Thr, c);
6909ef1f84bSDavid du Colombier for(i = 0; !(csr8r(ctlr, Lsr) & Thre) && i < 128; i++)
6919ef1f84bSDavid du Colombier delay(1);
6929ef1f84bSDavid du Colombier }
6939ef1f84bSDavid du Colombier
6949ef1f84bSDavid du Colombier static void
i8250poll(Uart * uart)6959ef1f84bSDavid du Colombier i8250poll(Uart* uart)
6969ef1f84bSDavid du Colombier {
6979ef1f84bSDavid du Colombier Ctlr *ctlr;
6989ef1f84bSDavid du Colombier
6999ef1f84bSDavid du Colombier /*
7009ef1f84bSDavid du Colombier * If PhysUart has a non-nil .poll member, this
7019ef1f84bSDavid du Colombier * routine will be called from the uartclock timer.
7029ef1f84bSDavid du Colombier * If the Ctlr .poll member is non-zero, when the
7039ef1f84bSDavid du Colombier * Uart is enabled interrupts will not be enabled
7049ef1f84bSDavid du Colombier * and the result is polled input and output.
7059ef1f84bSDavid du Colombier * Not very useful here, but ports to new hardware
7069ef1f84bSDavid du Colombier * or simulators can use this to get serial I/O
7079ef1f84bSDavid du Colombier * without setting up the interrupt mechanism.
7089ef1f84bSDavid du Colombier */
7099ef1f84bSDavid du Colombier ctlr = uart->regs;
7109ef1f84bSDavid du Colombier if(ctlr->iena || !ctlr->poll)
7119ef1f84bSDavid du Colombier return;
7129ef1f84bSDavid du Colombier i8250interrupt(nil, uart);
7139ef1f84bSDavid du Colombier }
7149ef1f84bSDavid du Colombier
7159ef1f84bSDavid du Colombier PhysUart i8250physuart = {
7169ef1f84bSDavid du Colombier .name = "i8250",
7179ef1f84bSDavid du Colombier .pnp = i8250pnp,
7189ef1f84bSDavid du Colombier .enable = i8250enable,
7199ef1f84bSDavid du Colombier .disable = i8250disable,
7209ef1f84bSDavid du Colombier .kick = i8250kick,
7219ef1f84bSDavid du Colombier .dobreak = i8250break,
7229ef1f84bSDavid du Colombier .baud = i8250baud,
7239ef1f84bSDavid du Colombier .bits = i8250bits,
7249ef1f84bSDavid du Colombier .stop = i8250stop,
7259ef1f84bSDavid du Colombier .parity = i8250parity,
7269ef1f84bSDavid du Colombier .modemctl = i8250modemctl,
7279ef1f84bSDavid du Colombier .rts = i8250rts,
7289ef1f84bSDavid du Colombier .dtr = i8250dtr,
7299ef1f84bSDavid du Colombier .status = i8250status,
7309ef1f84bSDavid du Colombier .fifo = i8250fifo,
7319ef1f84bSDavid du Colombier .getc = i8250getc,
7329ef1f84bSDavid du Colombier .putc = i8250putc,
7339ef1f84bSDavid du Colombier .poll = i8250poll,
7349ef1f84bSDavid du Colombier };
7359ef1f84bSDavid du Colombier
7369ef1f84bSDavid du Colombier Uart*
i8250console(char * cfg)7379ef1f84bSDavid du Colombier i8250console(char* cfg)
7389ef1f84bSDavid du Colombier {
7399ef1f84bSDavid du Colombier int i;
7409ef1f84bSDavid du Colombier Uart *uart;
7419ef1f84bSDavid du Colombier Ctlr *ctlr;
7429ef1f84bSDavid du Colombier char *cmd, *p;
7439ef1f84bSDavid du Colombier ISAConf isa;
7449ef1f84bSDavid du Colombier
7459ef1f84bSDavid du Colombier /*
7469ef1f84bSDavid du Colombier * Before i8250pnp() is run can only set the console
7479ef1f84bSDavid du Colombier * to 0 or 1 because those are the only uart structs which
7489ef1f84bSDavid du Colombier * will be the same before and after that.
7499ef1f84bSDavid du Colombier */
7509ef1f84bSDavid du Colombier if((p = getconf("console")) == nil && (p = cfg) == nil)
7519ef1f84bSDavid du Colombier return nil;
7529ef1f84bSDavid du Colombier i = strtoul(p, &cmd, 0);
7539ef1f84bSDavid du Colombier if(p == cmd)
7549ef1f84bSDavid du Colombier return nil;
7559ef1f84bSDavid du Colombier //WTF? Something to do with the PCIe-only machine?
7569ef1f84bSDavid du Colombier if((uart = uartconsole(i, cmd)) != nil){
7579ef1f84bSDavid du Colombier consuart = uart;
7589ef1f84bSDavid du Colombier return uart;
7599ef1f84bSDavid du Colombier }
7609ef1f84bSDavid du Colombier switch(i){
7619ef1f84bSDavid du Colombier default:
7629ef1f84bSDavid du Colombier return nil;
7639ef1f84bSDavid du Colombier case 0:
7649ef1f84bSDavid du Colombier uart = &i8250uart[0];
7659ef1f84bSDavid du Colombier break;
7669ef1f84bSDavid du Colombier case 1:
7679ef1f84bSDavid du Colombier uart = &i8250uart[1];
7689ef1f84bSDavid du Colombier break;
7699ef1f84bSDavid du Colombier }
7709ef1f84bSDavid du Colombier
7719ef1f84bSDavid du Colombier //Madness. Something to do with the PCIe-only machine?
7729ef1f84bSDavid du Colombier memset(&isa, 0, sizeof(isa));
7739ef1f84bSDavid du Colombier ctlr = uart->regs;
7749ef1f84bSDavid du Colombier if(isaconfig("eia", i, &isa) != 0){
7759ef1f84bSDavid du Colombier if(isa.port != 0)
7769ef1f84bSDavid du Colombier ctlr->io = isa.port;
7779ef1f84bSDavid du Colombier if(isa.irq != 0)
7789ef1f84bSDavid du Colombier ctlr->irq = isa.irq;
7799ef1f84bSDavid du Colombier if(isa.freq != 0)
7809ef1f84bSDavid du Colombier uart->freq = isa.freq;
7819ef1f84bSDavid du Colombier }
7829ef1f84bSDavid du Colombier
7839ef1f84bSDavid du Colombier /*
7849ef1f84bSDavid du Colombier * Does it exist?
7859ef1f84bSDavid du Colombier * Should be able to write/read
7869ef1f84bSDavid du Colombier * the Scratch Pad.
7879ef1f84bSDavid du Colombier */
7889ef1f84bSDavid du Colombier // ctlr = uart->regs;
7899ef1f84bSDavid du Colombier // csr8o(ctlr, Scr, 0x55);
7909ef1f84bSDavid du Colombier // if(csr8r(ctlr, Scr) != 0x55)
7919ef1f84bSDavid du Colombier // return nil;
7929ef1f84bSDavid du Colombier
793277b6efdSDavid du Colombier if(!uart->enabled)
7949ef1f84bSDavid du Colombier (*uart->phys->enable)(uart, 0);
7959ef1f84bSDavid du Colombier uartctl(uart, "b9600 l8 pn s1 i1");
7969ef1f84bSDavid du Colombier if(*cmd != '\0')
7979ef1f84bSDavid du Colombier uartctl(uart, cmd);
7989ef1f84bSDavid du Colombier
7999ef1f84bSDavid du Colombier consuart = uart;
8009ef1f84bSDavid du Colombier uart->console = 1;
8019ef1f84bSDavid du Colombier
8029ef1f84bSDavid du Colombier return uart;
8039ef1f84bSDavid du Colombier }
804*45e6af3bSDavid du Colombier
805*45e6af3bSDavid du Colombier void
i8250mouse(char * which,int (* putc)(Queue *,int),int setb1200)806*45e6af3bSDavid du Colombier i8250mouse(char* which, int (*putc)(Queue*, int), int setb1200)
807*45e6af3bSDavid du Colombier {
808*45e6af3bSDavid du Colombier char *p;
809*45e6af3bSDavid du Colombier int port;
810*45e6af3bSDavid du Colombier
811*45e6af3bSDavid du Colombier port = strtol(which, &p, 0);
812*45e6af3bSDavid du Colombier if(p == which || port < 0 || port > 1)
813*45e6af3bSDavid du Colombier error(Ebadarg);
814*45e6af3bSDavid du Colombier uartmouse(&i8250uart[port], putc, setb1200);
815*45e6af3bSDavid du Colombier }
816*45e6af3bSDavid du Colombier
817*45e6af3bSDavid du Colombier void
i8250setmouseputc(char * which,int (* putc)(Queue *,int))818*45e6af3bSDavid du Colombier i8250setmouseputc(char* which, int (*putc)(Queue*, int))
819*45e6af3bSDavid du Colombier {
820*45e6af3bSDavid du Colombier char *p;
821*45e6af3bSDavid du Colombier int port;
822*45e6af3bSDavid du Colombier
823*45e6af3bSDavid du Colombier port = strtol(which, &p, 0);
824*45e6af3bSDavid du Colombier if(p == which || port < 0 || port > 1)
825*45e6af3bSDavid du Colombier error(Ebadarg);
826*45e6af3bSDavid du Colombier uartsetmouseputc(&i8250uart[port], putc);
827*45e6af3bSDavid du Colombier }
828