193631029SDavid du Colombier /*
293631029SDavid du Colombier * omap35 8250-like UART
393631029SDavid du Colombier *
493631029SDavid du Colombier * we ignore the first 2 uarts on the omap35 (see below) and use the
593631029SDavid du Colombier * third one but call it 0.
693631029SDavid du Colombier */
793631029SDavid du Colombier
88e32b400SDavid du Colombier #include "u.h"
98e32b400SDavid du Colombier #include "../port/lib.h"
108e32b400SDavid du Colombier #include "mem.h"
118e32b400SDavid du Colombier #include "dat.h"
128e32b400SDavid du Colombier #include "fns.h"
138e32b400SDavid du Colombier
148e32b400SDavid du Colombier enum { /* registers */
158e32b400SDavid du Colombier Rbr = 0, /* Receiver Buffer (RO) */
168e32b400SDavid du Colombier Thr = 0, /* Transmitter Holding (WO) */
178e32b400SDavid du Colombier Ier = 1, /* Interrupt Enable */
188e32b400SDavid du Colombier Iir = 2, /* Interrupt Identification (RO) */
198e32b400SDavid du Colombier Fcr = 2, /* FIFO Control (WO) */
208e32b400SDavid du Colombier Lcr = 3, /* Line Control */
218e32b400SDavid du Colombier Mcr = 4, /* Modem Control */
228e32b400SDavid du Colombier Lsr = 5, /* Line Status */
238e32b400SDavid du Colombier Msr = 6, /* Modem Status */
248e32b400SDavid du Colombier Scr = 7, /* Scratch Pad */
2593631029SDavid du Colombier Mdr = 8, /* Mode Def'n (omap rw) */
2693631029SDavid du Colombier // Usr = 31, /* Uart Status Register; missing in omap? */
278e32b400SDavid du Colombier Dll = 0, /* Divisor Latch LSB */
288e32b400SDavid du Colombier Dlm = 1, /* Divisor Latch MSB */
298e32b400SDavid du Colombier };
308e32b400SDavid du Colombier
318e32b400SDavid du Colombier enum { /* Usr */
328e32b400SDavid du Colombier Busy = 0x01,
338e32b400SDavid du Colombier };
348e32b400SDavid du Colombier
358e32b400SDavid du Colombier enum { /* Ier */
368e32b400SDavid du Colombier Erda = 0x01, /* Enable Received Data Available */
378e32b400SDavid du Colombier Ethre = 0x02, /* Enable Thr Empty */
388e32b400SDavid du Colombier Erls = 0x04, /* Enable Receiver Line Status */
398e32b400SDavid du Colombier Ems = 0x08, /* Enable Modem Status */
408e32b400SDavid du Colombier };
418e32b400SDavid du Colombier
428e32b400SDavid du Colombier enum { /* Iir */
438e32b400SDavid du Colombier Ims = 0x00, /* Ms interrupt */
448e32b400SDavid du Colombier Ip = 0x01, /* Interrupt Pending (not) */
458e32b400SDavid du Colombier Ithre = 0x02, /* Thr Empty */
468e32b400SDavid du Colombier Irda = 0x04, /* Received Data Available */
478e32b400SDavid du Colombier Irls = 0x06, /* Receiver Line Status */
488e32b400SDavid du Colombier Ictoi = 0x0C, /* Character Time-out Indication */
498e32b400SDavid du Colombier IirMASK = 0x3F,
508e32b400SDavid du Colombier Ifena = 0xC0, /* FIFOs enabled */
518e32b400SDavid du Colombier };
528e32b400SDavid du Colombier
538e32b400SDavid du Colombier enum { /* Fcr */
548e32b400SDavid du Colombier FIFOena = 0x01, /* FIFO enable */
558e32b400SDavid du Colombier FIFOrclr = 0x02, /* clear Rx FIFO */
568e32b400SDavid du Colombier FIFOtclr = 0x04, /* clear Tx FIFO */
5793631029SDavid du Colombier // FIFOdma = 0x08,
588e32b400SDavid du Colombier FIFO1 = 0x00, /* Rx FIFO trigger level 1 byte */
598e32b400SDavid du Colombier FIFO4 = 0x40, /* 4 bytes */
608e32b400SDavid du Colombier FIFO8 = 0x80, /* 8 bytes */
618e32b400SDavid du Colombier FIFO14 = 0xC0, /* 14 bytes */
628e32b400SDavid du Colombier };
638e32b400SDavid du Colombier
648e32b400SDavid du Colombier enum { /* Lcr */
658e32b400SDavid du Colombier Wls5 = 0x00, /* Word Length Select 5 bits/byte */
668e32b400SDavid du Colombier Wls6 = 0x01, /* 6 bits/byte */
678e32b400SDavid du Colombier Wls7 = 0x02, /* 7 bits/byte */
688e32b400SDavid du Colombier Wls8 = 0x03, /* 8 bits/byte */
698e32b400SDavid du Colombier WlsMASK = 0x03,
708e32b400SDavid du Colombier Stb = 0x04, /* 2 stop bits */
718e32b400SDavid du Colombier Pen = 0x08, /* Parity Enable */
728e32b400SDavid du Colombier Eps = 0x10, /* Even Parity Select */
738e32b400SDavid du Colombier Stp = 0x20, /* Stick Parity */
748e32b400SDavid du Colombier Brk = 0x40, /* Break */
758e32b400SDavid du Colombier Dlab = 0x80, /* Divisor Latch Access Bit */
768e32b400SDavid du Colombier };
778e32b400SDavid du Colombier
788e32b400SDavid du Colombier enum { /* Mcr */
798e32b400SDavid du Colombier Dtr = 0x01, /* Data Terminal Ready */
808e32b400SDavid du Colombier Rts = 0x02, /* Ready To Send */
818e32b400SDavid du Colombier Out1 = 0x04, /* no longer in use */
8293631029SDavid du Colombier // Ie = 0x08, /* IRQ Enable (cd_sts_ch on omap) */
838e32b400SDavid du Colombier Dm = 0x10, /* Diagnostic Mode loopback */
848e32b400SDavid du Colombier };
858e32b400SDavid du Colombier
868e32b400SDavid du Colombier enum { /* Lsr */
878e32b400SDavid du Colombier Dr = 0x01, /* Data Ready */
888e32b400SDavid du Colombier Oe = 0x02, /* Overrun Error */
898e32b400SDavid du Colombier Pe = 0x04, /* Parity Error */
908e32b400SDavid du Colombier Fe = 0x08, /* Framing Error */
918e32b400SDavid du Colombier Bi = 0x10, /* Break Interrupt */
928e32b400SDavid du Colombier Thre = 0x20, /* Thr Empty */
9393631029SDavid du Colombier Temt = 0x40, /* Transmitter Empty */
948e32b400SDavid du Colombier FIFOerr = 0x80, /* error in receiver FIFO */
958e32b400SDavid du Colombier };
968e32b400SDavid du Colombier
978e32b400SDavid du Colombier enum { /* Msr */
988e32b400SDavid du Colombier Dcts = 0x01, /* Delta Cts */
998e32b400SDavid du Colombier Ddsr = 0x02, /* Delta Dsr */
1008e32b400SDavid du Colombier Teri = 0x04, /* Trailing Edge of Ri */
1018e32b400SDavid du Colombier Ddcd = 0x08, /* Delta Dcd */
1028e32b400SDavid du Colombier Cts = 0x10, /* Clear To Send */
1038e32b400SDavid du Colombier Dsr = 0x20, /* Data Set Ready */
1048e32b400SDavid du Colombier Ri = 0x40, /* Ring Indicator */
10593631029SDavid du Colombier Dcd = 0x80, /* Carrier Detect */
1068e32b400SDavid du Colombier };
1078e32b400SDavid du Colombier
10893631029SDavid du Colombier enum { /* Mdr */
10993631029SDavid du Colombier Modemask = 7,
11093631029SDavid du Colombier Modeuart = 0,
11193631029SDavid du Colombier };
11293631029SDavid du Colombier
11393631029SDavid du Colombier
1148e32b400SDavid du Colombier typedef struct Ctlr {
1158e32b400SDavid du Colombier u32int* io;
1168e32b400SDavid du Colombier int irq;
1178e32b400SDavid du Colombier int tbdf;
1188e32b400SDavid du Colombier int iena;
1198e32b400SDavid du Colombier int poll;
1208e32b400SDavid du Colombier
12193631029SDavid du Colombier uchar sticky[Scr+1];
1228e32b400SDavid du Colombier
1238e32b400SDavid du Colombier Lock;
1248e32b400SDavid du Colombier int hasfifo;
1258e32b400SDavid du Colombier int checkfifo;
1268e32b400SDavid du Colombier int fena;
1278e32b400SDavid du Colombier } Ctlr;
1288e32b400SDavid du Colombier
1298e32b400SDavid du Colombier extern PhysUart i8250physuart;
1308e32b400SDavid du Colombier
1318e32b400SDavid du Colombier static Ctlr i8250ctlr[] = {
132*72969e92SDavid du Colombier { .io = (u32int*)PHYSCONS,
1338e32b400SDavid du Colombier .irq = 74,
1348e32b400SDavid du Colombier .tbdf = -1,
1358e32b400SDavid du Colombier .poll = 0, },
1368e32b400SDavid du Colombier };
1378e32b400SDavid du Colombier
1388e32b400SDavid du Colombier static Uart i8250uart[] = {
1398e32b400SDavid du Colombier { .regs = &i8250ctlr[0], /* not [2] */
1408e32b400SDavid du Colombier .name = "COM3",
1418e32b400SDavid du Colombier .freq = 3686000, /* Not used, we use the global i8250freq */
1428e32b400SDavid du Colombier .phys = &i8250physuart,
1438e32b400SDavid du Colombier .console= 1,
1448e32b400SDavid du Colombier .next = nil, },
1458e32b400SDavid du Colombier };
1468e32b400SDavid du Colombier
14793631029SDavid du Colombier #define csr8r(c, r) ((c)->io[r])
14893631029SDavid du Colombier #define csr8w(c, r, v) ((c)->io[r] = (c)->sticky[r] | (v), coherence())
14993631029SDavid du Colombier #define csr8o(c, r, v) ((c)->io[r] = (v), coherence())
1508e32b400SDavid du Colombier
1518e32b400SDavid du Colombier static long
i8250status(Uart * uart,void * buf,long n,long offset)1528e32b400SDavid du Colombier i8250status(Uart* uart, void* buf, long n, long offset)
1538e32b400SDavid du Colombier {
1548e32b400SDavid du Colombier char *p;
1558e32b400SDavid du Colombier Ctlr *ctlr;
1568e32b400SDavid du Colombier uchar ier, lcr, mcr, msr;
1578e32b400SDavid du Colombier
1588e32b400SDavid du Colombier ctlr = uart->regs;
1598e32b400SDavid du Colombier p = malloc(READSTR);
1608e32b400SDavid du Colombier mcr = ctlr->sticky[Mcr];
1618e32b400SDavid du Colombier msr = csr8r(ctlr, Msr);
1628e32b400SDavid du Colombier ier = ctlr->sticky[Ier];
1638e32b400SDavid du Colombier lcr = ctlr->sticky[Lcr];
1648e32b400SDavid du Colombier snprint(p, READSTR,
1658e32b400SDavid du Colombier "b%d c%d d%d e%d l%d m%d p%c r%d s%d i%d\n"
1668e32b400SDavid du Colombier "dev(%d) type(%d) framing(%d) overruns(%d) "
1678e32b400SDavid du Colombier "berr(%d) serr(%d)%s%s%s%s\n",
1688e32b400SDavid du Colombier
1698e32b400SDavid du Colombier uart->baud,
1708e32b400SDavid du Colombier uart->hup_dcd,
1718e32b400SDavid du Colombier (msr & Dsr) != 0,
1728e32b400SDavid du Colombier uart->hup_dsr,
1738e32b400SDavid du Colombier (lcr & WlsMASK) + 5,
1748e32b400SDavid du Colombier (ier & Ems) != 0,
1758e32b400SDavid du Colombier (lcr & Pen) ? ((lcr & Eps) ? 'e': 'o'): 'n',
1768e32b400SDavid du Colombier (mcr & Rts) != 0,
1778e32b400SDavid du Colombier (lcr & Stb) ? 2: 1,
1788e32b400SDavid du Colombier ctlr->fena,
1798e32b400SDavid du Colombier
1808e32b400SDavid du Colombier uart->dev,
1818e32b400SDavid du Colombier uart->type,
1828e32b400SDavid du Colombier uart->ferr,
1838e32b400SDavid du Colombier uart->oerr,
1848e32b400SDavid du Colombier uart->berr,
1858e32b400SDavid du Colombier uart->serr,
1868e32b400SDavid du Colombier (msr & Cts) ? " cts": "",
1878e32b400SDavid du Colombier (msr & Dsr) ? " dsr": "",
1888e32b400SDavid du Colombier (msr & Dcd) ? " dcd": "",
1898e32b400SDavid du Colombier (msr & Ri) ? " ring": ""
1908e32b400SDavid du Colombier );
1918e32b400SDavid du Colombier n = readstr(offset, buf, n, p);
1928e32b400SDavid du Colombier free(p);
1938e32b400SDavid du Colombier
1948e32b400SDavid du Colombier return n;
1958e32b400SDavid du Colombier }
1968e32b400SDavid du Colombier
1978e32b400SDavid du Colombier static void
i8250fifo(Uart * uart,int level)1988e32b400SDavid du Colombier i8250fifo(Uart* uart, int level)
1998e32b400SDavid du Colombier {
2008e32b400SDavid du Colombier Ctlr *ctlr;
2018e32b400SDavid du Colombier
2028e32b400SDavid du Colombier ctlr = uart->regs;
2038e32b400SDavid du Colombier if(ctlr->hasfifo == 0)
2048e32b400SDavid du Colombier return;
2058e32b400SDavid du Colombier
2068e32b400SDavid du Colombier /*
2078e32b400SDavid du Colombier * Changing the FIFOena bit in Fcr flushes data
2088e32b400SDavid du Colombier * from both receive and transmit FIFOs; there's
2098e32b400SDavid du Colombier * no easy way to guarantee not losing data on
2108e32b400SDavid du Colombier * the receive side, but it's possible to wait until
2118e32b400SDavid du Colombier * the transmitter is really empty.
2128e32b400SDavid du Colombier */
2138e32b400SDavid du Colombier ilock(ctlr);
2148e32b400SDavid du Colombier while(!(csr8r(ctlr, Lsr) & Temt))
2158e32b400SDavid du Colombier ;
2168e32b400SDavid du Colombier
2178e32b400SDavid du Colombier /*
2188e32b400SDavid du Colombier * Set the trigger level, default is the max.
2198e32b400SDavid du Colombier * value.
2208e32b400SDavid du Colombier * Some UARTs require FIFOena to be set before
2218e32b400SDavid du Colombier * other bits can take effect, so set it twice.
2228e32b400SDavid du Colombier */
2238e32b400SDavid du Colombier ctlr->fena = level;
2248e32b400SDavid du Colombier switch(level){
2258e32b400SDavid du Colombier case 0:
2268e32b400SDavid du Colombier break;
2278e32b400SDavid du Colombier case 1:
2288e32b400SDavid du Colombier level = FIFO1|FIFOena;
2298e32b400SDavid du Colombier break;
2308e32b400SDavid du Colombier case 4:
2318e32b400SDavid du Colombier level = FIFO4|FIFOena;
2328e32b400SDavid du Colombier break;
2338e32b400SDavid du Colombier case 8:
2348e32b400SDavid du Colombier level = FIFO8|FIFOena;
2358e32b400SDavid du Colombier break;
2368e32b400SDavid du Colombier default:
2378e32b400SDavid du Colombier level = FIFO14|FIFOena;
2388e32b400SDavid du Colombier break;
2398e32b400SDavid du Colombier }
2408e32b400SDavid du Colombier csr8w(ctlr, Fcr, level);
2418e32b400SDavid du Colombier csr8w(ctlr, Fcr, level);
2428e32b400SDavid du Colombier iunlock(ctlr);
2438e32b400SDavid du Colombier }
2448e32b400SDavid du Colombier
2458e32b400SDavid du Colombier static void
i8250dtr(Uart * uart,int on)2468e32b400SDavid du Colombier i8250dtr(Uart* uart, int on)
2478e32b400SDavid du Colombier {
2488e32b400SDavid du Colombier Ctlr *ctlr;
2498e32b400SDavid du Colombier
2508e32b400SDavid du Colombier /*
2518e32b400SDavid du Colombier * Toggle DTR.
2528e32b400SDavid du Colombier */
2538e32b400SDavid du Colombier ctlr = uart->regs;
2548e32b400SDavid du Colombier if(on)
2558e32b400SDavid du Colombier ctlr->sticky[Mcr] |= Dtr;
2568e32b400SDavid du Colombier else
2578e32b400SDavid du Colombier ctlr->sticky[Mcr] &= ~Dtr;
2588e32b400SDavid du Colombier csr8w(ctlr, Mcr, 0);
2598e32b400SDavid du Colombier }
2608e32b400SDavid du Colombier
2618e32b400SDavid du Colombier static void
i8250rts(Uart * uart,int on)2628e32b400SDavid du Colombier i8250rts(Uart* uart, int on)
2638e32b400SDavid du Colombier {
2648e32b400SDavid du Colombier Ctlr *ctlr;
2658e32b400SDavid du Colombier
2668e32b400SDavid du Colombier /*
2678e32b400SDavid du Colombier * Toggle RTS.
2688e32b400SDavid du Colombier */
2698e32b400SDavid du Colombier ctlr = uart->regs;
2708e32b400SDavid du Colombier if(on)
2718e32b400SDavid du Colombier ctlr->sticky[Mcr] |= Rts;
2728e32b400SDavid du Colombier else
2738e32b400SDavid du Colombier ctlr->sticky[Mcr] &= ~Rts;
2748e32b400SDavid du Colombier csr8w(ctlr, Mcr, 0);
2758e32b400SDavid du Colombier }
2768e32b400SDavid du Colombier
2778e32b400SDavid du Colombier static void
i8250modemctl(Uart * uart,int on)2788e32b400SDavid du Colombier i8250modemctl(Uart* uart, int on)
2798e32b400SDavid du Colombier {
2808e32b400SDavid du Colombier Ctlr *ctlr;
2818e32b400SDavid du Colombier
2828e32b400SDavid du Colombier ctlr = uart->regs;
2838e32b400SDavid du Colombier ilock(&uart->tlock);
2848e32b400SDavid du Colombier if(on){
2858e32b400SDavid du Colombier ctlr->sticky[Ier] |= Ems;
28693631029SDavid du Colombier csr8w(ctlr, Ier, 0);
2878e32b400SDavid du Colombier uart->modem = 1;
2888e32b400SDavid du Colombier uart->cts = csr8r(ctlr, Msr) & Cts;
2898e32b400SDavid du Colombier }
2908e32b400SDavid du Colombier else{
2918e32b400SDavid du Colombier ctlr->sticky[Ier] &= ~Ems;
29293631029SDavid du Colombier csr8w(ctlr, Ier, 0);
2938e32b400SDavid du Colombier uart->modem = 0;
2948e32b400SDavid du Colombier uart->cts = 1;
2958e32b400SDavid du Colombier }
2968e32b400SDavid du Colombier iunlock(&uart->tlock);
2978e32b400SDavid du Colombier
2988e32b400SDavid du Colombier /* modem needs fifo */
2998e32b400SDavid du Colombier (*uart->phys->fifo)(uart, on);
3008e32b400SDavid du Colombier }
3018e32b400SDavid du Colombier
3028e32b400SDavid du Colombier static int
i8250parity(Uart * uart,int parity)3038e32b400SDavid du Colombier i8250parity(Uart* uart, int parity)
3048e32b400SDavid du Colombier {
3058e32b400SDavid du Colombier int lcr;
3068e32b400SDavid du Colombier Ctlr *ctlr;
3078e32b400SDavid du Colombier
3088e32b400SDavid du Colombier ctlr = uart->regs;
3098e32b400SDavid du Colombier lcr = ctlr->sticky[Lcr] & ~(Eps|Pen);
3108e32b400SDavid du Colombier
3118e32b400SDavid du Colombier switch(parity){
3128e32b400SDavid du Colombier case 'e':
3138e32b400SDavid du Colombier lcr |= Eps|Pen;
3148e32b400SDavid du Colombier break;
3158e32b400SDavid du Colombier case 'o':
3168e32b400SDavid du Colombier lcr |= Pen;
3178e32b400SDavid du Colombier break;
3188e32b400SDavid du Colombier case 'n':
3198e32b400SDavid du Colombier break;
3208e32b400SDavid du Colombier default:
3218e32b400SDavid du Colombier return -1;
3228e32b400SDavid du Colombier }
3238e32b400SDavid du Colombier ctlr->sticky[Lcr] = lcr;
3248e32b400SDavid du Colombier csr8w(ctlr, Lcr, 0);
3258e32b400SDavid du Colombier
3268e32b400SDavid du Colombier uart->parity = parity;
3278e32b400SDavid du Colombier
3288e32b400SDavid du Colombier return 0;
3298e32b400SDavid du Colombier }
3308e32b400SDavid du Colombier
3318e32b400SDavid du Colombier static int
i8250stop(Uart * uart,int stop)3328e32b400SDavid du Colombier i8250stop(Uart* uart, int stop)
3338e32b400SDavid du Colombier {
3348e32b400SDavid du Colombier int lcr;
3358e32b400SDavid du Colombier Ctlr *ctlr;
3368e32b400SDavid du Colombier
3378e32b400SDavid du Colombier ctlr = uart->regs;
3388e32b400SDavid du Colombier lcr = ctlr->sticky[Lcr] & ~Stb;
3398e32b400SDavid du Colombier
3408e32b400SDavid du Colombier switch(stop){
3418e32b400SDavid du Colombier case 1:
3428e32b400SDavid du Colombier break;
3438e32b400SDavid du Colombier case 2:
3448e32b400SDavid du Colombier lcr |= Stb;
3458e32b400SDavid du Colombier break;
3468e32b400SDavid du Colombier default:
3478e32b400SDavid du Colombier return -1;
3488e32b400SDavid du Colombier }
3498e32b400SDavid du Colombier ctlr->sticky[Lcr] = lcr;
3508e32b400SDavid du Colombier csr8w(ctlr, Lcr, 0);
3518e32b400SDavid du Colombier
3528e32b400SDavid du Colombier uart->stop = stop;
3538e32b400SDavid du Colombier
3548e32b400SDavid du Colombier return 0;
3558e32b400SDavid du Colombier }
3568e32b400SDavid du Colombier
3578e32b400SDavid du Colombier static int
i8250bits(Uart * uart,int bits)3588e32b400SDavid du Colombier i8250bits(Uart* uart, int bits)
3598e32b400SDavid du Colombier {
3608e32b400SDavid du Colombier int lcr;
3618e32b400SDavid du Colombier Ctlr *ctlr;
3628e32b400SDavid du Colombier
3638e32b400SDavid du Colombier ctlr = uart->regs;
3648e32b400SDavid du Colombier lcr = ctlr->sticky[Lcr] & ~WlsMASK;
3658e32b400SDavid du Colombier
3668e32b400SDavid du Colombier switch(bits){
3678e32b400SDavid du Colombier case 5:
3688e32b400SDavid du Colombier lcr |= Wls5;
3698e32b400SDavid du Colombier break;
3708e32b400SDavid du Colombier case 6:
3718e32b400SDavid du Colombier lcr |= Wls6;
3728e32b400SDavid du Colombier break;
3738e32b400SDavid du Colombier case 7:
3748e32b400SDavid du Colombier lcr |= Wls7;
3758e32b400SDavid du Colombier break;
3768e32b400SDavid du Colombier case 8:
3778e32b400SDavid du Colombier lcr |= Wls8;
3788e32b400SDavid du Colombier break;
3798e32b400SDavid du Colombier default:
3808e32b400SDavid du Colombier return -1;
3818e32b400SDavid du Colombier }
3828e32b400SDavid du Colombier ctlr->sticky[Lcr] = lcr;
3838e32b400SDavid du Colombier csr8w(ctlr, Lcr, 0);
3848e32b400SDavid du Colombier
3858e32b400SDavid du Colombier uart->bits = bits;
3868e32b400SDavid du Colombier
3878e32b400SDavid du Colombier return 0;
3888e32b400SDavid du Colombier }
3898e32b400SDavid du Colombier
3908e32b400SDavid du Colombier static int
i8250baud(Uart * uart,int baud)3918e32b400SDavid du Colombier i8250baud(Uart* uart, int baud)
3928e32b400SDavid du Colombier {
3938e32b400SDavid du Colombier #ifdef notdef /* don't change the speed */
3948e32b400SDavid du Colombier ulong bgc;
3958e32b400SDavid du Colombier Ctlr *ctlr;
3968e32b400SDavid du Colombier extern int i8250freq; /* In the config file */
39793631029SDavid du Colombier
3988e32b400SDavid du Colombier /*
3998e32b400SDavid du Colombier * Set the Baud rate by calculating and setting the Baud rate
4008e32b400SDavid du Colombier * Generator Constant. This will work with fairly non-standard
4018e32b400SDavid du Colombier * Baud rates.
4028e32b400SDavid du Colombier */
4038e32b400SDavid du Colombier if(i8250freq == 0 || baud <= 0)
4048e32b400SDavid du Colombier return -1;
4058e32b400SDavid du Colombier bgc = (i8250freq+8*baud-1)/(16*baud);
4068e32b400SDavid du Colombier
4078e32b400SDavid du Colombier ctlr = uart->regs;
4088e32b400SDavid du Colombier while(csr8r(ctlr, Usr) & Busy)
4098e32b400SDavid du Colombier delay(1);
41093631029SDavid du Colombier csr8w(ctlr, Lcr, Dlab); /* begin kludge */
4118e32b400SDavid du Colombier csr8o(ctlr, Dlm, bgc>>8);
4128e32b400SDavid du Colombier csr8o(ctlr, Dll, bgc);
4138e32b400SDavid du Colombier csr8w(ctlr, Lcr, 0);
4148e32b400SDavid du Colombier #endif
41593631029SDavid du Colombier uart->baud = baud;
4168e32b400SDavid du Colombier return 0;
4178e32b400SDavid du Colombier }
4188e32b400SDavid du Colombier
4198e32b400SDavid du Colombier static void
i8250break(Uart * uart,int ms)4208e32b400SDavid du Colombier i8250break(Uart* uart, int ms)
4218e32b400SDavid du Colombier {
4228e32b400SDavid du Colombier Ctlr *ctlr;
4238e32b400SDavid du Colombier
42493631029SDavid du Colombier if (up == nil)
42593631029SDavid du Colombier panic("i8250break: nil up");
4268e32b400SDavid du Colombier /*
4278e32b400SDavid du Colombier * Send a break.
4288e32b400SDavid du Colombier */
4298e32b400SDavid du Colombier if(ms <= 0)
4308e32b400SDavid du Colombier ms = 200;
4318e32b400SDavid du Colombier
4328e32b400SDavid du Colombier ctlr = uart->regs;
4338e32b400SDavid du Colombier csr8w(ctlr, Lcr, Brk);
4348e32b400SDavid du Colombier tsleep(&up->sleep, return0, 0, ms);
4358e32b400SDavid du Colombier csr8w(ctlr, Lcr, 0);
43693631029SDavid du Colombier }
43793631029SDavid du Colombier
43893631029SDavid du Colombier static void
emptyoutstage(Uart * uart,int n)43993631029SDavid du Colombier emptyoutstage(Uart *uart, int n)
44093631029SDavid du Colombier {
44193631029SDavid du Colombier _uartputs((char *)uart->op, n);
44293631029SDavid du Colombier uart->op = uart->oe = uart->ostage;
4438e32b400SDavid du Colombier }
4448e32b400SDavid du Colombier
4458e32b400SDavid du Colombier static void
i8250kick(Uart * uart)4468e32b400SDavid du Colombier i8250kick(Uart* uart)
4478e32b400SDavid du Colombier {
4488e32b400SDavid du Colombier int i;
4498e32b400SDavid du Colombier Ctlr *ctlr;
4508e32b400SDavid du Colombier
4518e32b400SDavid du Colombier if(/* uart->cts == 0 || */ uart->blocked)
4528e32b400SDavid du Colombier return;
4538e32b400SDavid du Colombier
454bacfa46cSDavid du Colombier if(!normalprint) { /* early */
45593631029SDavid du Colombier if (uart->op < uart->oe)
45693631029SDavid du Colombier emptyoutstage(uart, uart->oe - uart->op);
45793631029SDavid du Colombier while ((i = uartstageoutput(uart)) > 0)
45893631029SDavid du Colombier emptyoutstage(uart, i);
45993631029SDavid du Colombier return;
46093631029SDavid du Colombier }
46193631029SDavid du Colombier
4628e32b400SDavid du Colombier /* nothing more to send? then disable xmit intr */
4638e32b400SDavid du Colombier ctlr = uart->regs;
464bacfa46cSDavid du Colombier if (uart->op >= uart->oe && qlen(uart->oq) == 0 &&
465bacfa46cSDavid du Colombier csr8r(ctlr, Lsr) & Temt) {
4668e32b400SDavid du Colombier ctlr->sticky[Ier] &= ~Ethre;
46793631029SDavid du Colombier csr8w(ctlr, Ier, 0);
4688e32b400SDavid du Colombier return;
4698e32b400SDavid du Colombier }
4708e32b400SDavid du Colombier
4718e32b400SDavid du Colombier /*
4728e32b400SDavid du Colombier * 128 here is an arbitrary limit to make sure
4738e32b400SDavid du Colombier * we don't stay in this loop too long. If the
4748e32b400SDavid du Colombier * chip's output queue is longer than 128, too
4758e32b400SDavid du Colombier * bad -- presotto
4768e32b400SDavid du Colombier */
4778e32b400SDavid du Colombier for(i = 0; i < 128; i++){
4788e32b400SDavid du Colombier if(!(csr8r(ctlr, Lsr) & Thre))
4798e32b400SDavid du Colombier break;
4808e32b400SDavid du Colombier if(uart->op >= uart->oe && uartstageoutput(uart) == 0)
4818e32b400SDavid du Colombier break;
48293631029SDavid du Colombier csr8o(ctlr, Thr, *uart->op++); /* start tx */
4838e32b400SDavid du Colombier ctlr->sticky[Ier] |= Ethre;
48493631029SDavid du Colombier csr8w(ctlr, Ier, 0); /* intr when done */
4858e32b400SDavid du Colombier }
4868e32b400SDavid du Colombier }
4878e32b400SDavid du Colombier
48893631029SDavid du Colombier void
serialkick(void)48993631029SDavid du Colombier serialkick(void)
49093631029SDavid du Colombier {
49193631029SDavid du Colombier uartkick(&i8250uart[CONSOLE]);
49293631029SDavid du Colombier }
49393631029SDavid du Colombier
4948e32b400SDavid du Colombier static void
i8250interrupt(Ureg *,void * arg)4958e32b400SDavid du Colombier i8250interrupt(Ureg*, void* arg)
4968e32b400SDavid du Colombier {
4978e32b400SDavid du Colombier Ctlr *ctlr;
4988e32b400SDavid du Colombier Uart *uart;
4998e32b400SDavid du Colombier int iir, lsr, old, r;
5008e32b400SDavid du Colombier
5018e32b400SDavid du Colombier uart = arg;
5028e32b400SDavid du Colombier ctlr = uart->regs;
5038e32b400SDavid du Colombier for(iir = csr8r(ctlr, Iir); !(iir & Ip); iir = csr8r(ctlr, Iir)){
5048e32b400SDavid du Colombier switch(iir & IirMASK){
5058e32b400SDavid du Colombier case Ims: /* Ms interrupt */
5068e32b400SDavid du Colombier r = csr8r(ctlr, Msr);
5078e32b400SDavid du Colombier if(r & Dcts){
5088e32b400SDavid du Colombier ilock(&uart->tlock);
5098e32b400SDavid du Colombier old = uart->cts;
5108e32b400SDavid du Colombier uart->cts = r & Cts;
5118e32b400SDavid du Colombier if(old == 0 && uart->cts)
5128e32b400SDavid du Colombier uart->ctsbackoff = 2;
5138e32b400SDavid du Colombier iunlock(&uart->tlock);
5148e32b400SDavid du Colombier }
5158e32b400SDavid du Colombier if(r & Ddsr){
5168e32b400SDavid du Colombier old = r & Dsr;
5178e32b400SDavid du Colombier if(uart->hup_dsr && uart->dsr && !old)
5188e32b400SDavid du Colombier uart->dohup = 1;
5198e32b400SDavid du Colombier uart->dsr = old;
5208e32b400SDavid du Colombier }
5218e32b400SDavid du Colombier if(r & Ddcd){
5228e32b400SDavid du Colombier old = r & Dcd;
5238e32b400SDavid du Colombier if(uart->hup_dcd && uart->dcd && !old)
5248e32b400SDavid du Colombier uart->dohup = 1;
5258e32b400SDavid du Colombier uart->dcd = old;
5268e32b400SDavid du Colombier }
5278e32b400SDavid du Colombier break;
5288e32b400SDavid du Colombier case Ithre: /* Thr Empty */
5298e32b400SDavid du Colombier uartkick(uart);
5308e32b400SDavid du Colombier break;
5318e32b400SDavid du Colombier case Irda: /* Received Data Available */
5328e32b400SDavid du Colombier case Irls: /* Receiver Line Status */
5338e32b400SDavid du Colombier case Ictoi: /* Character Time-out Indication */
5348e32b400SDavid du Colombier /*
5358e32b400SDavid du Colombier * Consume any received data.
5368e32b400SDavid du Colombier * If the received byte came in with a break,
5378e32b400SDavid du Colombier * parity or framing error, throw it away;
5388e32b400SDavid du Colombier * overrun is an indication that something has
5398e32b400SDavid du Colombier * already been tossed.
5408e32b400SDavid du Colombier */
5418e32b400SDavid du Colombier while((lsr = csr8r(ctlr, Lsr)) & Dr){
5428e32b400SDavid du Colombier if(lsr & (FIFOerr|Oe))
5438e32b400SDavid du Colombier uart->oerr++;
5448e32b400SDavid du Colombier if(lsr & Pe)
5458e32b400SDavid du Colombier uart->perr++;
5468e32b400SDavid du Colombier if(lsr & Fe)
5478e32b400SDavid du Colombier uart->ferr++;
5488e32b400SDavid du Colombier r = csr8r(ctlr, Rbr);
5498e32b400SDavid du Colombier if(!(lsr & (Bi|Fe|Pe)))
5508e32b400SDavid du Colombier uartrecv(uart, r);
5518e32b400SDavid du Colombier }
5528e32b400SDavid du Colombier break;
5538e32b400SDavid du Colombier
5548e32b400SDavid du Colombier default:
555bacfa46cSDavid du Colombier iprint("weird uart interrupt type %#2.2uX\n", iir);
5568e32b400SDavid du Colombier break;
5578e32b400SDavid du Colombier }
5588e32b400SDavid du Colombier }
5598e32b400SDavid du Colombier }
5608e32b400SDavid du Colombier
5618e32b400SDavid du Colombier static void
i8250disable(Uart * uart)5628e32b400SDavid du Colombier i8250disable(Uart* uart)
5638e32b400SDavid du Colombier {
5648e32b400SDavid du Colombier Ctlr *ctlr;
5658e32b400SDavid du Colombier
5668e32b400SDavid du Colombier /*
5678e32b400SDavid du Colombier * Turn off DTR and RTS, disable interrupts and fifos.
5688e32b400SDavid du Colombier */
5698e32b400SDavid du Colombier (*uart->phys->dtr)(uart, 0);
5708e32b400SDavid du Colombier (*uart->phys->rts)(uart, 0);
5718e32b400SDavid du Colombier (*uart->phys->fifo)(uart, 0);
5728e32b400SDavid du Colombier
5738e32b400SDavid du Colombier ctlr = uart->regs;
5748e32b400SDavid du Colombier ctlr->sticky[Ier] = 0;
57593631029SDavid du Colombier csr8w(ctlr, Ier, 0);
5768e32b400SDavid du Colombier
5778e32b400SDavid du Colombier if(ctlr->iena != 0){
5788e32b400SDavid du Colombier if(irqdisable(ctlr->irq, i8250interrupt, uart, uart->name) == 0)
5798e32b400SDavid du Colombier ctlr->iena = 0;
5808e32b400SDavid du Colombier }
5818e32b400SDavid du Colombier }
5828e32b400SDavid du Colombier
5838e32b400SDavid du Colombier static void
i8250enable(Uart * uart,int ie)5848e32b400SDavid du Colombier i8250enable(Uart* uart, int ie)
5858e32b400SDavid du Colombier {
58693631029SDavid du Colombier int mode;
5878e32b400SDavid du Colombier Ctlr *ctlr;
5888e32b400SDavid du Colombier
58993631029SDavid du Colombier if (up == nil)
59093631029SDavid du Colombier return; /* too soon */
59193631029SDavid du Colombier
5928e32b400SDavid du Colombier ctlr = uart->regs;
5938e32b400SDavid du Colombier
59493631029SDavid du Colombier /* omap only: set uart/irda/cir mode to uart */
59593631029SDavid du Colombier mode = csr8r(ctlr, Mdr);
59693631029SDavid du Colombier csr8o(ctlr, Mdr, (mode & ~Modemask) | Modeuart);
59793631029SDavid du Colombier
59893631029SDavid du Colombier ctlr->sticky[Lcr] = Wls8; /* no parity */
59993631029SDavid du Colombier csr8w(ctlr, Lcr, 0);
60093631029SDavid du Colombier
6018e32b400SDavid du Colombier /*
6028e32b400SDavid du Colombier * Check if there is a FIFO.
6038e32b400SDavid du Colombier * Changing the FIFOena bit in Fcr flushes data
6048e32b400SDavid du Colombier * from both receive and transmit FIFOs; there's
6058e32b400SDavid du Colombier * no easy way to guarantee not losing data on
6068e32b400SDavid du Colombier * the receive side, but it's possible to wait until
6078e32b400SDavid du Colombier * the transmitter is really empty.
6088e32b400SDavid du Colombier * Also, reading the Iir outwith i8250interrupt()
6098e32b400SDavid du Colombier * can be dangerous, but this should only happen
6108e32b400SDavid du Colombier * once, before interrupts are enabled.
6118e32b400SDavid du Colombier */
6128e32b400SDavid du Colombier ilock(ctlr);
6138e32b400SDavid du Colombier if(!ctlr->checkfifo){
6148e32b400SDavid du Colombier /*
6158e32b400SDavid du Colombier * Wait until the transmitter is really empty.
6168e32b400SDavid du Colombier */
6178e32b400SDavid du Colombier while(!(csr8r(ctlr, Lsr) & Temt))
6188e32b400SDavid du Colombier ;
6198e32b400SDavid du Colombier csr8w(ctlr, Fcr, FIFOena);
6208e32b400SDavid du Colombier if(csr8r(ctlr, Iir) & Ifena)
6218e32b400SDavid du Colombier ctlr->hasfifo = 1;
6228e32b400SDavid du Colombier csr8w(ctlr, Fcr, 0);
6238e32b400SDavid du Colombier ctlr->checkfifo = 1;
6248e32b400SDavid du Colombier }
6258e32b400SDavid du Colombier iunlock(ctlr);
6268e32b400SDavid du Colombier
6278e32b400SDavid du Colombier /*
6288e32b400SDavid du Colombier * Enable interrupts and turn on DTR and RTS.
6298e32b400SDavid du Colombier * Be careful if this is called to set up a polled serial line
6308e32b400SDavid du Colombier * early on not to try to enable interrupts as interrupt-
6318e32b400SDavid du Colombier * -enabling mechanisms might not be set up yet.
6328e32b400SDavid du Colombier */
6338e32b400SDavid du Colombier if(ie){
6348e32b400SDavid du Colombier if(ctlr->iena == 0 && !ctlr->poll){
6358e32b400SDavid du Colombier irqenable(ctlr->irq, i8250interrupt, uart, uart->name);
6368e32b400SDavid du Colombier ctlr->iena = 1;
6378e32b400SDavid du Colombier }
63893631029SDavid du Colombier ctlr->sticky[Ier] = Erda;
63993631029SDavid du Colombier // ctlr->sticky[Mcr] |= Ie; /* not on omap */
64093631029SDavid du Colombier ctlr->sticky[Mcr] = 0;
6418e32b400SDavid du Colombier }
6428e32b400SDavid du Colombier else{
6438e32b400SDavid du Colombier ctlr->sticky[Ier] = 0;
6448e32b400SDavid du Colombier ctlr->sticky[Mcr] = 0;
6458e32b400SDavid du Colombier }
64693631029SDavid du Colombier csr8w(ctlr, Ier, 0);
64793631029SDavid du Colombier csr8w(ctlr, Mcr, 0);
6488e32b400SDavid du Colombier
6498e32b400SDavid du Colombier (*uart->phys->dtr)(uart, 1);
6508e32b400SDavid du Colombier (*uart->phys->rts)(uart, 1);
6518e32b400SDavid du Colombier
6528e32b400SDavid du Colombier /*
6538e32b400SDavid du Colombier * During startup, the i8259 interrupt controller is reset.
6548e32b400SDavid du Colombier * This may result in a lost interrupt from the i8250 uart.
6558e32b400SDavid du Colombier * The i8250 thinks the interrupt is still outstanding and does not
6568e32b400SDavid du Colombier * generate any further interrupts. The workaround is to call the
6578e32b400SDavid du Colombier * interrupt handler to clear any pending interrupt events.
6588e32b400SDavid du Colombier * Note: this must be done after setting Ier.
6598e32b400SDavid du Colombier */
6608e32b400SDavid du Colombier if(ie)
6618e32b400SDavid du Colombier i8250interrupt(nil, uart);
6628e32b400SDavid du Colombier }
6638e32b400SDavid du Colombier
6648e32b400SDavid du Colombier static Uart*
i8250pnp(void)6658e32b400SDavid du Colombier i8250pnp(void)
6668e32b400SDavid du Colombier {
6678e32b400SDavid du Colombier return i8250uart;
6688e32b400SDavid du Colombier }
6698e32b400SDavid du Colombier
6708e32b400SDavid du Colombier static int
i8250getc(Uart * uart)6718e32b400SDavid du Colombier i8250getc(Uart* uart)
6728e32b400SDavid du Colombier {
6738e32b400SDavid du Colombier Ctlr *ctlr;
6748e32b400SDavid du Colombier
6758e32b400SDavid du Colombier ctlr = uart->regs;
6768e32b400SDavid du Colombier while(!(csr8r(ctlr, Lsr) & Dr))
6778e32b400SDavid du Colombier delay(1);
6788e32b400SDavid du Colombier return csr8r(ctlr, Rbr);
6798e32b400SDavid du Colombier }
6808e32b400SDavid du Colombier
6818e32b400SDavid du Colombier static void
i8250putc(Uart * uart,int c)6828e32b400SDavid du Colombier i8250putc(Uart* uart, int c)
6838e32b400SDavid du Colombier {
6848e32b400SDavid du Colombier int i;
6858e32b400SDavid du Colombier Ctlr *ctlr;
6868e32b400SDavid du Colombier
6878e32b400SDavid du Colombier if (!normalprint) { /* too early; use brute force */
6888e32b400SDavid du Colombier int s = splhi();
6898e32b400SDavid du Colombier
6908e32b400SDavid du Colombier while (!(((ulong *)PHYSCONS)[Lsr] & Thre))
6918e32b400SDavid du Colombier ;
6928e32b400SDavid du Colombier ((ulong *)PHYSCONS)[Thr] = c;
6938e32b400SDavid du Colombier coherence();
6948e32b400SDavid du Colombier splx(s);
6958e32b400SDavid du Colombier return;
6968e32b400SDavid du Colombier }
6978e32b400SDavid du Colombier
6988e32b400SDavid du Colombier ctlr = uart->regs;
6998e32b400SDavid du Colombier for(i = 0; !(csr8r(ctlr, Lsr) & Thre) && i < 128; i++)
7008e32b400SDavid du Colombier delay(1);
70193631029SDavid du Colombier csr8o(ctlr, Thr, (uchar)c);
7028e32b400SDavid du Colombier for(i = 0; !(csr8r(ctlr, Lsr) & Thre) && i < 128; i++)
7038e32b400SDavid du Colombier delay(1);
7048e32b400SDavid du Colombier }
7058e32b400SDavid du Colombier
7068e32b400SDavid du Colombier void
serialputc(int c)7078e32b400SDavid du Colombier serialputc(int c)
7088e32b400SDavid du Colombier {
7098e32b400SDavid du Colombier i8250putc(&i8250uart[CONSOLE], c);
7108e32b400SDavid du Colombier }
7118e32b400SDavid du Colombier
7128e32b400SDavid du Colombier void
serialputs(char * s,int n)7138e32b400SDavid du Colombier serialputs(char* s, int n)
7148e32b400SDavid du Colombier {
7158e32b400SDavid du Colombier _uartputs(s, n);
7168e32b400SDavid du Colombier }
7178e32b400SDavid du Colombier
71893631029SDavid du Colombier #ifdef notdef
7198e32b400SDavid du Colombier static void
i8250poll(Uart * uart)7208e32b400SDavid du Colombier i8250poll(Uart* uart)
7218e32b400SDavid du Colombier {
7228e32b400SDavid du Colombier Ctlr *ctlr;
7238e32b400SDavid du Colombier
7248e32b400SDavid du Colombier /*
7258e32b400SDavid du Colombier * If PhysUart has a non-nil .poll member, this
7268e32b400SDavid du Colombier * routine will be called from the uartclock timer.
7278e32b400SDavid du Colombier * If the Ctlr .poll member is non-zero, when the
7288e32b400SDavid du Colombier * Uart is enabled interrupts will not be enabled
7298e32b400SDavid du Colombier * and the result is polled input and output.
7308e32b400SDavid du Colombier * Not very useful here, but ports to new hardware
7318e32b400SDavid du Colombier * or simulators can use this to get serial I/O
7328e32b400SDavid du Colombier * without setting up the interrupt mechanism.
7338e32b400SDavid du Colombier */
7348e32b400SDavid du Colombier ctlr = uart->regs;
7358e32b400SDavid du Colombier if(ctlr->iena || !ctlr->poll)
7368e32b400SDavid du Colombier return;
7378e32b400SDavid du Colombier i8250interrupt(nil, uart);
7388e32b400SDavid du Colombier }
73993631029SDavid du Colombier #endif
7408e32b400SDavid du Colombier
7418e32b400SDavid du Colombier PhysUart i8250physuart = {
7428e32b400SDavid du Colombier .name = "i8250",
7438e32b400SDavid du Colombier .pnp = i8250pnp,
7448e32b400SDavid du Colombier .enable = i8250enable,
7458e32b400SDavid du Colombier .disable = i8250disable,
7468e32b400SDavid du Colombier .kick = i8250kick,
7478e32b400SDavid du Colombier .dobreak = i8250break,
7488e32b400SDavid du Colombier .baud = i8250baud,
7498e32b400SDavid du Colombier .bits = i8250bits,
7508e32b400SDavid du Colombier .stop = i8250stop,
7518e32b400SDavid du Colombier .parity = i8250parity,
7528e32b400SDavid du Colombier .modemctl = i8250modemctl,
7538e32b400SDavid du Colombier .rts = i8250rts,
7548e32b400SDavid du Colombier .dtr = i8250dtr,
7558e32b400SDavid du Colombier .status = i8250status,
7568e32b400SDavid du Colombier .fifo = i8250fifo,
7578e32b400SDavid du Colombier .getc = i8250getc,
7588e32b400SDavid du Colombier .putc = i8250putc,
75993631029SDavid du Colombier // .poll = i8250poll, /* only in 9k, not 9 */
7608e32b400SDavid du Colombier };
7618e32b400SDavid du Colombier
7628e32b400SDavid du Colombier static void
i8250dumpregs(Ctlr * ctlr)7638e32b400SDavid du Colombier i8250dumpregs(Ctlr* ctlr)
7648e32b400SDavid du Colombier {
7658e32b400SDavid du Colombier int dlm, dll;
7668e32b400SDavid du Colombier int _uartprint(char*, ...);
7678e32b400SDavid du Colombier
7688e32b400SDavid du Colombier csr8w(ctlr, Lcr, Dlab);
7698e32b400SDavid du Colombier dlm = csr8r(ctlr, Dlm);
7708e32b400SDavid du Colombier dll = csr8r(ctlr, Dll);
7718e32b400SDavid du Colombier csr8w(ctlr, Lcr, 0);
7728e32b400SDavid du Colombier
7738e32b400SDavid du Colombier _uartprint("dlm %#ux dll %#ux\n", dlm, dll);
7748e32b400SDavid du Colombier }
7758e32b400SDavid du Colombier
77693631029SDavid du Colombier Uart* uartenable(Uart *p);
77793631029SDavid du Colombier
77893631029SDavid du Colombier /* must call this from a process's context */
77993631029SDavid du Colombier int
i8250console(void)7808e32b400SDavid du Colombier i8250console(void)
7818e32b400SDavid du Colombier {
7828e32b400SDavid du Colombier Uart *uart = &i8250uart[CONSOLE];
7838e32b400SDavid du Colombier
78493631029SDavid du Colombier if (up == nil)
78593631029SDavid du Colombier return -1; /* too early */
78693631029SDavid du Colombier
78793631029SDavid du Colombier if(uartenable(uart) != nil /* && uart->console */){
788bacfa46cSDavid du Colombier // iprint("i8250console: enabling console uart\n");
78993631029SDavid du Colombier kbdq = uart->iq;
79093631029SDavid du Colombier serialoq = uart->oq;
79193631029SDavid du Colombier uart->putc = kbdcr2nl;
79293631029SDavid du Colombier uart->opens++;
7938e32b400SDavid du Colombier consuart = uart;
7948e32b400SDavid du Colombier }
79593631029SDavid du Colombier uartctl(uart, "b115200 l8 pn r1 s1 i1");
79693631029SDavid du Colombier return 0;
79793631029SDavid du Colombier }
7988e32b400SDavid du Colombier
7998e32b400SDavid du Colombier void
_uartputs(char * s,int n)8008e32b400SDavid du Colombier _uartputs(char* s, int n)
8018e32b400SDavid du Colombier {
8028e32b400SDavid du Colombier char *e;
8038e32b400SDavid du Colombier
8048e32b400SDavid du Colombier for(e = s+n; s < e; s++){
8058e32b400SDavid du Colombier if(*s == '\n')
8068e32b400SDavid du Colombier i8250putc(&i8250uart[CONSOLE], '\r');
8078e32b400SDavid du Colombier i8250putc(&i8250uart[CONSOLE], *s);
8088e32b400SDavid du Colombier }
8098e32b400SDavid du Colombier }
8108e32b400SDavid du Colombier
8118e32b400SDavid du Colombier int
_uartprint(char * fmt,...)8128e32b400SDavid du Colombier _uartprint(char* fmt, ...)
8138e32b400SDavid du Colombier {
8148e32b400SDavid du Colombier int n;
8158e32b400SDavid du Colombier va_list arg;
8168e32b400SDavid du Colombier char buf[PRINTSIZE];
8178e32b400SDavid du Colombier
8188e32b400SDavid du Colombier va_start(arg, fmt);
8198e32b400SDavid du Colombier n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;
8208e32b400SDavid du Colombier va_end(arg);
8218e32b400SDavid du Colombier _uartputs(buf, n);
8228e32b400SDavid du Colombier
8238e32b400SDavid du Colombier return n;
8248e32b400SDavid du Colombier }
825