xref: /plan9/sys/src/9/omap/uarti8250.c (revision 72969e92894ce84d47b280f1c71775a26a40f042)
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