xref: /plan9/sys/src/9/teg2/uarti8250.c (revision 3de6a9c0b3d5cf34fc4090d0bf1930d83799a7fd)
1*3de6a9c0SDavid du Colombier /*
2*3de6a9c0SDavid du Colombier  * 8250-like UART
3*3de6a9c0SDavid du Colombier  */
4*3de6a9c0SDavid du Colombier 
5*3de6a9c0SDavid du Colombier #include "u.h"
6*3de6a9c0SDavid du Colombier #include "../port/lib.h"
7*3de6a9c0SDavid du Colombier #include "mem.h"
8*3de6a9c0SDavid du Colombier #include "dat.h"
9*3de6a9c0SDavid du Colombier #include "fns.h"
10*3de6a9c0SDavid du Colombier 
11*3de6a9c0SDavid du Colombier enum {					/* registers */
12*3de6a9c0SDavid du Colombier 	Rbr		= 0,		/* Receiver Buffer (RO) */
13*3de6a9c0SDavid du Colombier 	Thr		= 0,		/* Transmitter Holding (WO) */
14*3de6a9c0SDavid du Colombier 	Ier		= 1,		/* Interrupt Enable */
15*3de6a9c0SDavid du Colombier 	Iir		= 2,		/* Interrupt Identification (RO) */
16*3de6a9c0SDavid du Colombier 	Fcr		= 2,		/* FIFO Control (WO) */
17*3de6a9c0SDavid du Colombier 	Lcr		= 3,		/* Line Control */
18*3de6a9c0SDavid du Colombier 	Mcr		= 4,		/* Modem Control */
19*3de6a9c0SDavid du Colombier 	Lsr		= 5,		/* Line Status */
20*3de6a9c0SDavid du Colombier 	Msr		= 6,		/* Modem Status */
21*3de6a9c0SDavid du Colombier 	Scr		= 7,		/* Scratch Pad */
22*3de6a9c0SDavid du Colombier 	Mdr		= 8,		/* Mode Def'n (omap rw) */
23*3de6a9c0SDavid du Colombier //	Usr		= 31,		/* Uart Status Register; missing in omap? */
24*3de6a9c0SDavid du Colombier 	Dll		= 0,		/* Divisor Latch LSB */
25*3de6a9c0SDavid du Colombier 	Dlm		= 1,		/* Divisor Latch MSB */
26*3de6a9c0SDavid du Colombier };
27*3de6a9c0SDavid du Colombier 
28*3de6a9c0SDavid du Colombier enum {					/* Usr */
29*3de6a9c0SDavid du Colombier 	Busy		= 0x01,
30*3de6a9c0SDavid du Colombier };
31*3de6a9c0SDavid du Colombier 
32*3de6a9c0SDavid du Colombier enum {					/* Ier */
33*3de6a9c0SDavid du Colombier 	Erda		= 0x01,		/* Enable Received Data Available */
34*3de6a9c0SDavid du Colombier 	Ethre		= 0x02,		/* Enable Thr Empty */
35*3de6a9c0SDavid du Colombier 	Erls		= 0x04,		/* Enable Receiver Line Status */
36*3de6a9c0SDavid du Colombier 	Ems		= 0x08,		/* Enable Modem Status */
37*3de6a9c0SDavid du Colombier };
38*3de6a9c0SDavid du Colombier 
39*3de6a9c0SDavid du Colombier enum {					/* Iir */
40*3de6a9c0SDavid du Colombier 	Ims		= 0x00,		/* Ms interrupt */
41*3de6a9c0SDavid du Colombier 	Ip		= 0x01,		/* Interrupt Pending (not) */
42*3de6a9c0SDavid du Colombier 	Ithre		= 0x02,		/* Thr Empty */
43*3de6a9c0SDavid du Colombier 	Irda		= 0x04,		/* Received Data Available */
44*3de6a9c0SDavid du Colombier 	Irls		= 0x06,		/* Receiver Line Status */
45*3de6a9c0SDavid du Colombier 	Ictoi		= 0x0C,		/* Character Time-out Indication */
46*3de6a9c0SDavid du Colombier 	IirMASK		= 0x3F,
47*3de6a9c0SDavid du Colombier 	Ifena		= 0xC0,		/* FIFOs enabled */
48*3de6a9c0SDavid du Colombier };
49*3de6a9c0SDavid du Colombier 
50*3de6a9c0SDavid du Colombier enum {					/* Fcr */
51*3de6a9c0SDavid du Colombier 	FIFOena		= 0x01,		/* FIFO enable */
52*3de6a9c0SDavid du Colombier 	FIFOrclr	= 0x02,		/* clear Rx FIFO */
53*3de6a9c0SDavid du Colombier 	FIFOtclr	= 0x04,		/* clear Tx FIFO */
54*3de6a9c0SDavid du Colombier //	FIFOdma		= 0x08,
55*3de6a9c0SDavid du Colombier 	FIFO1		= 0x00,		/* Rx FIFO trigger level 1 byte */
56*3de6a9c0SDavid du Colombier 	FIFO4		= 0x40,		/*	4 bytes */
57*3de6a9c0SDavid du Colombier 	FIFO8		= 0x80,		/*	8 bytes */
58*3de6a9c0SDavid du Colombier 	FIFO14		= 0xC0,		/*	14 bytes */
59*3de6a9c0SDavid du Colombier };
60*3de6a9c0SDavid du Colombier 
61*3de6a9c0SDavid du Colombier enum {					/* Lcr */
62*3de6a9c0SDavid du Colombier 	Wls5		= 0x00,		/* Word Length Select 5 bits/byte */
63*3de6a9c0SDavid du Colombier 	Wls6		= 0x01,		/*	6 bits/byte */
64*3de6a9c0SDavid du Colombier 	Wls7		= 0x02,		/*	7 bits/byte */
65*3de6a9c0SDavid du Colombier 	Wls8		= 0x03,		/*	8 bits/byte */
66*3de6a9c0SDavid du Colombier 	WlsMASK		= 0x03,
67*3de6a9c0SDavid du Colombier 	Stb		= 0x04,		/* 2 stop bits */
68*3de6a9c0SDavid du Colombier 	Pen		= 0x08,		/* Parity Enable */
69*3de6a9c0SDavid du Colombier 	Eps		= 0x10,		/* Even Parity Select */
70*3de6a9c0SDavid du Colombier 	Stp		= 0x20,		/* Stick Parity */
71*3de6a9c0SDavid du Colombier 	Brk		= 0x40,		/* Break */
72*3de6a9c0SDavid du Colombier 	Dlab		= 0x80,		/* Divisor Latch Access Bit */
73*3de6a9c0SDavid du Colombier };
74*3de6a9c0SDavid du Colombier 
75*3de6a9c0SDavid du Colombier enum {					/* Mcr */
76*3de6a9c0SDavid du Colombier 	Dtr		= 0x01,		/* Data Terminal Ready */
77*3de6a9c0SDavid du Colombier 	Rts		= 0x02,		/* Ready To Send */
78*3de6a9c0SDavid du Colombier 	Out1		= 0x04,		/* no longer in use */
79*3de6a9c0SDavid du Colombier //	Ie		= 0x08,		/* IRQ Enable (cd_sts_ch on omap) */
80*3de6a9c0SDavid du Colombier 	Dm		= 0x10,		/* Diagnostic Mode loopback */
81*3de6a9c0SDavid du Colombier };
82*3de6a9c0SDavid du Colombier 
83*3de6a9c0SDavid du Colombier enum {					/* Lsr */
84*3de6a9c0SDavid du Colombier 	Dr		= 0x01,		/* Data Ready */
85*3de6a9c0SDavid du Colombier 	Oe		= 0x02,		/* Overrun Error */
86*3de6a9c0SDavid du Colombier 	Pe		= 0x04,		/* Parity Error */
87*3de6a9c0SDavid du Colombier 	Fe		= 0x08,		/* Framing Error */
88*3de6a9c0SDavid du Colombier 	Bi		= 0x10,		/* Break Interrupt */
89*3de6a9c0SDavid du Colombier 	Thre		= 0x20,		/* Thr Empty */
90*3de6a9c0SDavid du Colombier 	Temt		= 0x40,		/* Transmitter Empty */
91*3de6a9c0SDavid du Colombier 	FIFOerr		= 0x80,		/* error in receiver FIFO */
92*3de6a9c0SDavid du Colombier };
93*3de6a9c0SDavid du Colombier 
94*3de6a9c0SDavid du Colombier enum {					/* Msr */
95*3de6a9c0SDavid du Colombier 	Dcts		= 0x01,		/* Delta Cts */
96*3de6a9c0SDavid du Colombier 	Ddsr		= 0x02,		/* Delta Dsr */
97*3de6a9c0SDavid du Colombier 	Teri		= 0x04,		/* Trailing Edge of Ri */
98*3de6a9c0SDavid du Colombier 	Ddcd		= 0x08,		/* Delta Dcd */
99*3de6a9c0SDavid du Colombier 	Cts		= 0x10,		/* Clear To Send */
100*3de6a9c0SDavid du Colombier 	Dsr		= 0x20,		/* Data Set Ready */
101*3de6a9c0SDavid du Colombier 	Ri		= 0x40,		/* Ring Indicator */
102*3de6a9c0SDavid du Colombier 	Dcd		= 0x80,		/* Carrier Detect */
103*3de6a9c0SDavid du Colombier };
104*3de6a9c0SDavid du Colombier 
105*3de6a9c0SDavid du Colombier enum {					/* Mdr */
106*3de6a9c0SDavid du Colombier 	Modemask	= 7,
107*3de6a9c0SDavid du Colombier 	Modeuart	= 0,
108*3de6a9c0SDavid du Colombier };
109*3de6a9c0SDavid du Colombier 
110*3de6a9c0SDavid du Colombier 
111*3de6a9c0SDavid du Colombier typedef struct Ctlr {
112*3de6a9c0SDavid du Colombier 	u32int*	io;
113*3de6a9c0SDavid du Colombier 	int	irq;
114*3de6a9c0SDavid du Colombier 	int	tbdf;
115*3de6a9c0SDavid du Colombier 	int	iena;
116*3de6a9c0SDavid du Colombier 	int	poll;
117*3de6a9c0SDavid du Colombier 
118*3de6a9c0SDavid du Colombier 	uchar	sticky[Scr+1];
119*3de6a9c0SDavid du Colombier 
120*3de6a9c0SDavid du Colombier 	Lock;
121*3de6a9c0SDavid du Colombier 	int	hasfifo;
122*3de6a9c0SDavid du Colombier 	int	checkfifo;
123*3de6a9c0SDavid du Colombier 	int	fena;
124*3de6a9c0SDavid du Colombier } Ctlr;
125*3de6a9c0SDavid du Colombier 
126*3de6a9c0SDavid du Colombier extern PhysUart i8250physuart;
127*3de6a9c0SDavid du Colombier 
128*3de6a9c0SDavid du Colombier static Ctlr i8250ctlr[] = {
129*3de6a9c0SDavid du Colombier {	.io	= (u32int*)PHYSCONS,
130*3de6a9c0SDavid du Colombier 	.irq	= Uartirq,
131*3de6a9c0SDavid du Colombier 	.tbdf	= -1,
132*3de6a9c0SDavid du Colombier 	.poll	= 0, },
133*3de6a9c0SDavid du Colombier };
134*3de6a9c0SDavid du Colombier 
135*3de6a9c0SDavid du Colombier static Uart i8250uart[] = {
136*3de6a9c0SDavid du Colombier {	.regs	= &i8250ctlr[0], /* not [2] */
137*3de6a9c0SDavid du Colombier 	.name	= "COM3",
138*3de6a9c0SDavid du Colombier 	.freq	= 3686000,	/* Not used, we use the global i8250freq */
139*3de6a9c0SDavid du Colombier 	.phys	= &i8250physuart,
140*3de6a9c0SDavid du Colombier 	.console= 1,
141*3de6a9c0SDavid du Colombier 	.next	= nil, },
142*3de6a9c0SDavid du Colombier };
143*3de6a9c0SDavid du Colombier 
144*3de6a9c0SDavid du Colombier #define csr8r(c, r)	((c)->io[r])
145*3de6a9c0SDavid du Colombier #define csr8w(c, r, v)	((c)->io[r] = (c)->sticky[r] | (v), coherence())
146*3de6a9c0SDavid du Colombier #define csr8o(c, r, v)	((c)->io[r] = (v), coherence())
147*3de6a9c0SDavid du Colombier 
148*3de6a9c0SDavid du Colombier static long
i8250status(Uart * uart,void * buf,long n,long offset)149*3de6a9c0SDavid du Colombier i8250status(Uart* uart, void* buf, long n, long offset)
150*3de6a9c0SDavid du Colombier {
151*3de6a9c0SDavid du Colombier 	char *p;
152*3de6a9c0SDavid du Colombier 	Ctlr *ctlr;
153*3de6a9c0SDavid du Colombier 	uchar ier, lcr, mcr, msr;
154*3de6a9c0SDavid du Colombier 
155*3de6a9c0SDavid du Colombier 	ctlr = uart->regs;
156*3de6a9c0SDavid du Colombier 	p = malloc(READSTR);
157*3de6a9c0SDavid du Colombier 	mcr = ctlr->sticky[Mcr];
158*3de6a9c0SDavid du Colombier 	msr = csr8r(ctlr, Msr);
159*3de6a9c0SDavid du Colombier 	ier = ctlr->sticky[Ier];
160*3de6a9c0SDavid du Colombier 	lcr = ctlr->sticky[Lcr];
161*3de6a9c0SDavid du Colombier 	snprint(p, READSTR,
162*3de6a9c0SDavid du Colombier 		"b%d c%d d%d e%d l%d m%d p%c r%d s%d i%d\n"
163*3de6a9c0SDavid du Colombier 		"dev(%d) type(%d) framing(%d) overruns(%d) "
164*3de6a9c0SDavid du Colombier 		"berr(%d) serr(%d)%s%s%s%s\n",
165*3de6a9c0SDavid du Colombier 
166*3de6a9c0SDavid du Colombier 		uart->baud,
167*3de6a9c0SDavid du Colombier 		uart->hup_dcd,
168*3de6a9c0SDavid du Colombier 		(msr & Dsr) != 0,
169*3de6a9c0SDavid du Colombier 		uart->hup_dsr,
170*3de6a9c0SDavid du Colombier 		(lcr & WlsMASK) + 5,
171*3de6a9c0SDavid du Colombier 		(ier & Ems) != 0,
172*3de6a9c0SDavid du Colombier 		(lcr & Pen) ? ((lcr & Eps) ? 'e': 'o'): 'n',
173*3de6a9c0SDavid du Colombier 		(mcr & Rts) != 0,
174*3de6a9c0SDavid du Colombier 		(lcr & Stb) ? 2: 1,
175*3de6a9c0SDavid du Colombier 		ctlr->fena,
176*3de6a9c0SDavid du Colombier 
177*3de6a9c0SDavid du Colombier 		uart->dev,
178*3de6a9c0SDavid du Colombier 		uart->type,
179*3de6a9c0SDavid du Colombier 		uart->ferr,
180*3de6a9c0SDavid du Colombier 		uart->oerr,
181*3de6a9c0SDavid du Colombier 		uart->berr,
182*3de6a9c0SDavid du Colombier 		uart->serr,
183*3de6a9c0SDavid du Colombier 		(msr & Cts) ? " cts": "",
184*3de6a9c0SDavid du Colombier 		(msr & Dsr) ? " dsr": "",
185*3de6a9c0SDavid du Colombier 		(msr & Dcd) ? " dcd": "",
186*3de6a9c0SDavid du Colombier 		(msr & Ri) ? " ring": ""
187*3de6a9c0SDavid du Colombier 	);
188*3de6a9c0SDavid du Colombier 	n = readstr(offset, buf, n, p);
189*3de6a9c0SDavid du Colombier 	free(p);
190*3de6a9c0SDavid du Colombier 
191*3de6a9c0SDavid du Colombier 	return n;
192*3de6a9c0SDavid du Colombier }
193*3de6a9c0SDavid du Colombier 
194*3de6a9c0SDavid du Colombier static void
i8250fifo(Uart * uart,int level)195*3de6a9c0SDavid du Colombier i8250fifo(Uart* uart, int level)
196*3de6a9c0SDavid du Colombier {
197*3de6a9c0SDavid du Colombier 	Ctlr *ctlr;
198*3de6a9c0SDavid du Colombier 
199*3de6a9c0SDavid du Colombier 	ctlr = uart->regs;
200*3de6a9c0SDavid du Colombier 	if(ctlr->hasfifo == 0)
201*3de6a9c0SDavid du Colombier 		return;
202*3de6a9c0SDavid du Colombier 
203*3de6a9c0SDavid du Colombier 	/*
204*3de6a9c0SDavid du Colombier 	 * Changing the FIFOena bit in Fcr flushes data
205*3de6a9c0SDavid du Colombier 	 * from both receive and transmit FIFOs; there's
206*3de6a9c0SDavid du Colombier 	 * no easy way to guarantee not losing data on
207*3de6a9c0SDavid du Colombier 	 * the receive side, but it's possible to wait until
208*3de6a9c0SDavid du Colombier 	 * the transmitter is really empty.
209*3de6a9c0SDavid du Colombier 	 */
210*3de6a9c0SDavid du Colombier 	ilock(ctlr);
211*3de6a9c0SDavid du Colombier 	while(!(csr8r(ctlr, Lsr) & Temt))
212*3de6a9c0SDavid du Colombier 		;
213*3de6a9c0SDavid du Colombier 
214*3de6a9c0SDavid du Colombier 	/*
215*3de6a9c0SDavid du Colombier 	 * Set the trigger level, default is the max.
216*3de6a9c0SDavid du Colombier 	 * value.
217*3de6a9c0SDavid du Colombier 	 * Some UARTs require FIFOena to be set before
218*3de6a9c0SDavid du Colombier 	 * other bits can take effect, so set it twice.
219*3de6a9c0SDavid du Colombier 	 */
220*3de6a9c0SDavid du Colombier 	ctlr->fena = level;
221*3de6a9c0SDavid du Colombier 	switch(level){
222*3de6a9c0SDavid du Colombier 	case 0:
223*3de6a9c0SDavid du Colombier 		break;
224*3de6a9c0SDavid du Colombier 	case 1:
225*3de6a9c0SDavid du Colombier 		level = FIFO1|FIFOena;
226*3de6a9c0SDavid du Colombier 		break;
227*3de6a9c0SDavid du Colombier 	case 4:
228*3de6a9c0SDavid du Colombier 		level = FIFO4|FIFOena;
229*3de6a9c0SDavid du Colombier 		break;
230*3de6a9c0SDavid du Colombier 	case 8:
231*3de6a9c0SDavid du Colombier 		level = FIFO8|FIFOena;
232*3de6a9c0SDavid du Colombier 		break;
233*3de6a9c0SDavid du Colombier 	default:
234*3de6a9c0SDavid du Colombier 		level = FIFO14|FIFOena;
235*3de6a9c0SDavid du Colombier 		break;
236*3de6a9c0SDavid du Colombier 	}
237*3de6a9c0SDavid du Colombier 	csr8w(ctlr, Fcr, level);
238*3de6a9c0SDavid du Colombier 	csr8w(ctlr, Fcr, level);
239*3de6a9c0SDavid du Colombier 	iunlock(ctlr);
240*3de6a9c0SDavid du Colombier }
241*3de6a9c0SDavid du Colombier 
242*3de6a9c0SDavid du Colombier static void
i8250dtr(Uart * uart,int on)243*3de6a9c0SDavid du Colombier i8250dtr(Uart* uart, int on)
244*3de6a9c0SDavid du Colombier {
245*3de6a9c0SDavid du Colombier 	Ctlr *ctlr;
246*3de6a9c0SDavid du Colombier 
247*3de6a9c0SDavid du Colombier 	/*
248*3de6a9c0SDavid du Colombier 	 * Toggle DTR.
249*3de6a9c0SDavid du Colombier 	 */
250*3de6a9c0SDavid du Colombier 	ctlr = uart->regs;
251*3de6a9c0SDavid du Colombier 	if(on)
252*3de6a9c0SDavid du Colombier 		ctlr->sticky[Mcr] |= Dtr;
253*3de6a9c0SDavid du Colombier 	else
254*3de6a9c0SDavid du Colombier 		ctlr->sticky[Mcr] &= ~Dtr;
255*3de6a9c0SDavid du Colombier 	csr8w(ctlr, Mcr, 0);
256*3de6a9c0SDavid du Colombier }
257*3de6a9c0SDavid du Colombier 
258*3de6a9c0SDavid du Colombier static void
i8250rts(Uart * uart,int on)259*3de6a9c0SDavid du Colombier i8250rts(Uart* uart, int on)
260*3de6a9c0SDavid du Colombier {
261*3de6a9c0SDavid du Colombier 	Ctlr *ctlr;
262*3de6a9c0SDavid du Colombier 
263*3de6a9c0SDavid du Colombier 	/*
264*3de6a9c0SDavid du Colombier 	 * Toggle RTS.
265*3de6a9c0SDavid du Colombier 	 */
266*3de6a9c0SDavid du Colombier 	ctlr = uart->regs;
267*3de6a9c0SDavid du Colombier 	if(on)
268*3de6a9c0SDavid du Colombier 		ctlr->sticky[Mcr] |= Rts;
269*3de6a9c0SDavid du Colombier 	else
270*3de6a9c0SDavid du Colombier 		ctlr->sticky[Mcr] &= ~Rts;
271*3de6a9c0SDavid du Colombier 	csr8w(ctlr, Mcr, 0);
272*3de6a9c0SDavid du Colombier }
273*3de6a9c0SDavid du Colombier 
274*3de6a9c0SDavid du Colombier static void
i8250modemctl(Uart * uart,int on)275*3de6a9c0SDavid du Colombier i8250modemctl(Uart* uart, int on)
276*3de6a9c0SDavid du Colombier {
277*3de6a9c0SDavid du Colombier 	Ctlr *ctlr;
278*3de6a9c0SDavid du Colombier 
279*3de6a9c0SDavid du Colombier 	ctlr = uart->regs;
280*3de6a9c0SDavid du Colombier 	ilock(&uart->tlock);
281*3de6a9c0SDavid du Colombier 	if(on){
282*3de6a9c0SDavid du Colombier 		ctlr->sticky[Ier] |= Ems;
283*3de6a9c0SDavid du Colombier 		csr8w(ctlr, Ier, 0);
284*3de6a9c0SDavid du Colombier 		uart->modem = 1;
285*3de6a9c0SDavid du Colombier 		uart->cts = csr8r(ctlr, Msr) & Cts;
286*3de6a9c0SDavid du Colombier 	}
287*3de6a9c0SDavid du Colombier 	else{
288*3de6a9c0SDavid du Colombier 		ctlr->sticky[Ier] &= ~Ems;
289*3de6a9c0SDavid du Colombier 		csr8w(ctlr, Ier, 0);
290*3de6a9c0SDavid du Colombier 		uart->modem = 0;
291*3de6a9c0SDavid du Colombier 		uart->cts = 1;
292*3de6a9c0SDavid du Colombier 	}
293*3de6a9c0SDavid du Colombier 	iunlock(&uart->tlock);
294*3de6a9c0SDavid du Colombier 
295*3de6a9c0SDavid du Colombier 	/* modem needs fifo */
296*3de6a9c0SDavid du Colombier 	(*uart->phys->fifo)(uart, on);
297*3de6a9c0SDavid du Colombier }
298*3de6a9c0SDavid du Colombier 
299*3de6a9c0SDavid du Colombier static int
i8250parity(Uart * uart,int parity)300*3de6a9c0SDavid du Colombier i8250parity(Uart* uart, int parity)
301*3de6a9c0SDavid du Colombier {
302*3de6a9c0SDavid du Colombier 	int lcr;
303*3de6a9c0SDavid du Colombier 	Ctlr *ctlr;
304*3de6a9c0SDavid du Colombier 
305*3de6a9c0SDavid du Colombier 	ctlr = uart->regs;
306*3de6a9c0SDavid du Colombier 	lcr = ctlr->sticky[Lcr] & ~(Eps|Pen);
307*3de6a9c0SDavid du Colombier 
308*3de6a9c0SDavid du Colombier 	switch(parity){
309*3de6a9c0SDavid du Colombier 	case 'e':
310*3de6a9c0SDavid du Colombier 		lcr |= Eps|Pen;
311*3de6a9c0SDavid du Colombier 		break;
312*3de6a9c0SDavid du Colombier 	case 'o':
313*3de6a9c0SDavid du Colombier 		lcr |= Pen;
314*3de6a9c0SDavid du Colombier 		break;
315*3de6a9c0SDavid du Colombier 	case 'n':
316*3de6a9c0SDavid du Colombier 		break;
317*3de6a9c0SDavid du Colombier 	default:
318*3de6a9c0SDavid du Colombier 		return -1;
319*3de6a9c0SDavid du Colombier 	}
320*3de6a9c0SDavid du Colombier 	ctlr->sticky[Lcr] = lcr;
321*3de6a9c0SDavid du Colombier 	csr8w(ctlr, Lcr, 0);
322*3de6a9c0SDavid du Colombier 
323*3de6a9c0SDavid du Colombier 	uart->parity = parity;
324*3de6a9c0SDavid du Colombier 
325*3de6a9c0SDavid du Colombier 	return 0;
326*3de6a9c0SDavid du Colombier }
327*3de6a9c0SDavid du Colombier 
328*3de6a9c0SDavid du Colombier static int
i8250stop(Uart * uart,int stop)329*3de6a9c0SDavid du Colombier i8250stop(Uart* uart, int stop)
330*3de6a9c0SDavid du Colombier {
331*3de6a9c0SDavid du Colombier 	int lcr;
332*3de6a9c0SDavid du Colombier 	Ctlr *ctlr;
333*3de6a9c0SDavid du Colombier 
334*3de6a9c0SDavid du Colombier 	ctlr = uart->regs;
335*3de6a9c0SDavid du Colombier 	lcr = ctlr->sticky[Lcr] & ~Stb;
336*3de6a9c0SDavid du Colombier 
337*3de6a9c0SDavid du Colombier 	switch(stop){
338*3de6a9c0SDavid du Colombier 	case 1:
339*3de6a9c0SDavid du Colombier 		break;
340*3de6a9c0SDavid du Colombier 	case 2:
341*3de6a9c0SDavid du Colombier 		lcr |= Stb;
342*3de6a9c0SDavid du Colombier 		break;
343*3de6a9c0SDavid du Colombier 	default:
344*3de6a9c0SDavid du Colombier 		return -1;
345*3de6a9c0SDavid du Colombier 	}
346*3de6a9c0SDavid du Colombier 	ctlr->sticky[Lcr] = lcr;
347*3de6a9c0SDavid du Colombier 	csr8w(ctlr, Lcr, 0);
348*3de6a9c0SDavid du Colombier 
349*3de6a9c0SDavid du Colombier 	uart->stop = stop;
350*3de6a9c0SDavid du Colombier 
351*3de6a9c0SDavid du Colombier 	return 0;
352*3de6a9c0SDavid du Colombier }
353*3de6a9c0SDavid du Colombier 
354*3de6a9c0SDavid du Colombier static int
i8250bits(Uart * uart,int bits)355*3de6a9c0SDavid du Colombier i8250bits(Uart* uart, int bits)
356*3de6a9c0SDavid du Colombier {
357*3de6a9c0SDavid du Colombier 	int lcr;
358*3de6a9c0SDavid du Colombier 	Ctlr *ctlr;
359*3de6a9c0SDavid du Colombier 
360*3de6a9c0SDavid du Colombier 	ctlr = uart->regs;
361*3de6a9c0SDavid du Colombier 	lcr = ctlr->sticky[Lcr] & ~WlsMASK;
362*3de6a9c0SDavid du Colombier 
363*3de6a9c0SDavid du Colombier 	switch(bits){
364*3de6a9c0SDavid du Colombier 	case 5:
365*3de6a9c0SDavid du Colombier 		lcr |= Wls5;
366*3de6a9c0SDavid du Colombier 		break;
367*3de6a9c0SDavid du Colombier 	case 6:
368*3de6a9c0SDavid du Colombier 		lcr |= Wls6;
369*3de6a9c0SDavid du Colombier 		break;
370*3de6a9c0SDavid du Colombier 	case 7:
371*3de6a9c0SDavid du Colombier 		lcr |= Wls7;
372*3de6a9c0SDavid du Colombier 		break;
373*3de6a9c0SDavid du Colombier 	case 8:
374*3de6a9c0SDavid du Colombier 		lcr |= Wls8;
375*3de6a9c0SDavid du Colombier 		break;
376*3de6a9c0SDavid du Colombier 	default:
377*3de6a9c0SDavid du Colombier 		return -1;
378*3de6a9c0SDavid du Colombier 	}
379*3de6a9c0SDavid du Colombier 	ctlr->sticky[Lcr] = lcr;
380*3de6a9c0SDavid du Colombier 	csr8w(ctlr, Lcr, 0);
381*3de6a9c0SDavid du Colombier 
382*3de6a9c0SDavid du Colombier 	uart->bits = bits;
383*3de6a9c0SDavid du Colombier 
384*3de6a9c0SDavid du Colombier 	return 0;
385*3de6a9c0SDavid du Colombier }
386*3de6a9c0SDavid du Colombier 
387*3de6a9c0SDavid du Colombier static int
i8250baud(Uart * uart,int baud)388*3de6a9c0SDavid du Colombier i8250baud(Uart* uart, int baud)
389*3de6a9c0SDavid du Colombier {
390*3de6a9c0SDavid du Colombier #ifdef notdef				/* don't change the speed */
391*3de6a9c0SDavid du Colombier 	ulong bgc;
392*3de6a9c0SDavid du Colombier 	Ctlr *ctlr;
393*3de6a9c0SDavid du Colombier 	extern int i8250freq;	/* In the config file */
394*3de6a9c0SDavid du Colombier 
395*3de6a9c0SDavid du Colombier 	/*
396*3de6a9c0SDavid du Colombier 	 * Set the Baud rate by calculating and setting the Baud rate
397*3de6a9c0SDavid du Colombier 	 * Generator Constant. This will work with fairly non-standard
398*3de6a9c0SDavid du Colombier 	 * Baud rates.
399*3de6a9c0SDavid du Colombier 	 */
400*3de6a9c0SDavid du Colombier 	if(i8250freq == 0 || baud <= 0)
401*3de6a9c0SDavid du Colombier 		return -1;
402*3de6a9c0SDavid du Colombier 	bgc = (i8250freq+8*baud-1)/(16*baud);
403*3de6a9c0SDavid du Colombier 
404*3de6a9c0SDavid du Colombier 	ctlr = uart->regs;
405*3de6a9c0SDavid du Colombier 	while(csr8r(ctlr, Usr) & Busy)
406*3de6a9c0SDavid du Colombier 		delay(1);
407*3de6a9c0SDavid du Colombier 	csr8w(ctlr, Lcr, Dlab);		/* begin kludge */
408*3de6a9c0SDavid du Colombier 	csr8o(ctlr, Dlm, bgc>>8);
409*3de6a9c0SDavid du Colombier 	csr8o(ctlr, Dll, bgc);
410*3de6a9c0SDavid du Colombier 	csr8w(ctlr, Lcr, 0);
411*3de6a9c0SDavid du Colombier #endif
412*3de6a9c0SDavid du Colombier 	uart->baud = baud;
413*3de6a9c0SDavid du Colombier 	return 0;
414*3de6a9c0SDavid du Colombier }
415*3de6a9c0SDavid du Colombier 
416*3de6a9c0SDavid du Colombier static void
i8250break(Uart * uart,int ms)417*3de6a9c0SDavid du Colombier i8250break(Uart* uart, int ms)
418*3de6a9c0SDavid du Colombier {
419*3de6a9c0SDavid du Colombier 	Ctlr *ctlr;
420*3de6a9c0SDavid du Colombier 
421*3de6a9c0SDavid du Colombier 	if (up == nil)
422*3de6a9c0SDavid du Colombier 		panic("i8250break: nil up");
423*3de6a9c0SDavid du Colombier 	/*
424*3de6a9c0SDavid du Colombier 	 * Send a break.
425*3de6a9c0SDavid du Colombier 	 */
426*3de6a9c0SDavid du Colombier 	if(ms <= 0)
427*3de6a9c0SDavid du Colombier 		ms = 200;
428*3de6a9c0SDavid du Colombier 
429*3de6a9c0SDavid du Colombier 	ctlr = uart->regs;
430*3de6a9c0SDavid du Colombier 	csr8w(ctlr, Lcr, Brk);
431*3de6a9c0SDavid du Colombier 	tsleep(&up->sleep, return0, 0, ms);
432*3de6a9c0SDavid du Colombier 	csr8w(ctlr, Lcr, 0);
433*3de6a9c0SDavid du Colombier }
434*3de6a9c0SDavid du Colombier 
435*3de6a9c0SDavid du Colombier static void
emptyoutstage(Uart * uart,int n)436*3de6a9c0SDavid du Colombier emptyoutstage(Uart *uart, int n)
437*3de6a9c0SDavid du Colombier {
438*3de6a9c0SDavid du Colombier 	_uartputs((char *)uart->op, n);
439*3de6a9c0SDavid du Colombier 	uart->op = uart->oe = uart->ostage;
440*3de6a9c0SDavid du Colombier }
441*3de6a9c0SDavid du Colombier 
442*3de6a9c0SDavid du Colombier static void
i8250kick(Uart * uart)443*3de6a9c0SDavid du Colombier i8250kick(Uart* uart)
444*3de6a9c0SDavid du Colombier {
445*3de6a9c0SDavid du Colombier 	int i;
446*3de6a9c0SDavid du Colombier 	Ctlr *ctlr;
447*3de6a9c0SDavid du Colombier 
448*3de6a9c0SDavid du Colombier 	if(/* uart->cts == 0 || */ uart->blocked)
449*3de6a9c0SDavid du Colombier 		return;
450*3de6a9c0SDavid du Colombier 
451*3de6a9c0SDavid du Colombier 	if(!normalprint) {			/* early */
452*3de6a9c0SDavid du Colombier 		if (uart->op < uart->oe)
453*3de6a9c0SDavid du Colombier 			emptyoutstage(uart, uart->oe - uart->op);
454*3de6a9c0SDavid du Colombier 		while ((i = uartstageoutput(uart)) > 0)
455*3de6a9c0SDavid du Colombier 			emptyoutstage(uart, i);
456*3de6a9c0SDavid du Colombier 		return;
457*3de6a9c0SDavid du Colombier 	}
458*3de6a9c0SDavid du Colombier 
459*3de6a9c0SDavid du Colombier 	/* nothing more to send? then disable xmit intr */
460*3de6a9c0SDavid du Colombier 	ctlr = uart->regs;
461*3de6a9c0SDavid du Colombier 	if (uart->op >= uart->oe && qlen(uart->oq) == 0 &&
462*3de6a9c0SDavid du Colombier 	    csr8r(ctlr, Lsr) & Temt) {
463*3de6a9c0SDavid du Colombier 		ctlr->sticky[Ier] &= ~Ethre;
464*3de6a9c0SDavid du Colombier 		csr8w(ctlr, Ier, 0);
465*3de6a9c0SDavid du Colombier 		return;
466*3de6a9c0SDavid du Colombier 	}
467*3de6a9c0SDavid du Colombier 
468*3de6a9c0SDavid du Colombier 	/*
469*3de6a9c0SDavid du Colombier 	 *  128 here is an arbitrary limit to make sure
470*3de6a9c0SDavid du Colombier 	 *  we don't stay in this loop too long.  If the
471*3de6a9c0SDavid du Colombier 	 *  chip's output queue is longer than 128, too
472*3de6a9c0SDavid du Colombier 	 *  bad -- presotto
473*3de6a9c0SDavid du Colombier 	 */
474*3de6a9c0SDavid du Colombier 	for(i = 0; i < 128; i++){
475*3de6a9c0SDavid du Colombier 		if(!(csr8r(ctlr, Lsr) & Thre))
476*3de6a9c0SDavid du Colombier 			break;
477*3de6a9c0SDavid du Colombier 		if(uart->op >= uart->oe && uartstageoutput(uart) == 0)
478*3de6a9c0SDavid du Colombier 			break;
479*3de6a9c0SDavid du Colombier 		csr8o(ctlr, Thr, *uart->op++);		/* start tx */
480*3de6a9c0SDavid du Colombier 		ctlr->sticky[Ier] |= Ethre;
481*3de6a9c0SDavid du Colombier 		csr8w(ctlr, Ier, 0);			/* intr when done */
482*3de6a9c0SDavid du Colombier 	}
483*3de6a9c0SDavid du Colombier }
484*3de6a9c0SDavid du Colombier 
485*3de6a9c0SDavid du Colombier void
serialkick(void)486*3de6a9c0SDavid du Colombier serialkick(void)
487*3de6a9c0SDavid du Colombier {
488*3de6a9c0SDavid du Colombier 	uartkick(&i8250uart[CONSOLE]);
489*3de6a9c0SDavid du Colombier }
490*3de6a9c0SDavid du Colombier 
491*3de6a9c0SDavid du Colombier static void
i8250interrupt(Ureg *,void * arg)492*3de6a9c0SDavid du Colombier i8250interrupt(Ureg*, void* arg)
493*3de6a9c0SDavid du Colombier {
494*3de6a9c0SDavid du Colombier 	Ctlr *ctlr;
495*3de6a9c0SDavid du Colombier 	Uart *uart;
496*3de6a9c0SDavid du Colombier 	int iir, lsr, old, r;
497*3de6a9c0SDavid du Colombier 
498*3de6a9c0SDavid du Colombier 	uart = arg;
499*3de6a9c0SDavid du Colombier 	ctlr = uart->regs;
500*3de6a9c0SDavid du Colombier 	for(iir = csr8r(ctlr, Iir); !(iir & Ip); iir = csr8r(ctlr, Iir)){
501*3de6a9c0SDavid du Colombier 		switch(iir & IirMASK){
502*3de6a9c0SDavid du Colombier 		case Ims:		/* Ms interrupt */
503*3de6a9c0SDavid du Colombier 			r = csr8r(ctlr, Msr);
504*3de6a9c0SDavid du Colombier 			if(r & Dcts){
505*3de6a9c0SDavid du Colombier 				ilock(&uart->tlock);
506*3de6a9c0SDavid du Colombier 				old = uart->cts;
507*3de6a9c0SDavid du Colombier 				uart->cts = r & Cts;
508*3de6a9c0SDavid du Colombier 				if(old == 0 && uart->cts)
509*3de6a9c0SDavid du Colombier 					uart->ctsbackoff = 2;
510*3de6a9c0SDavid du Colombier 				iunlock(&uart->tlock);
511*3de6a9c0SDavid du Colombier 			}
512*3de6a9c0SDavid du Colombier 		 	if(r & Ddsr){
513*3de6a9c0SDavid du Colombier 				old = r & Dsr;
514*3de6a9c0SDavid du Colombier 				if(uart->hup_dsr && uart->dsr && !old)
515*3de6a9c0SDavid du Colombier 					uart->dohup = 1;
516*3de6a9c0SDavid du Colombier 				uart->dsr = old;
517*3de6a9c0SDavid du Colombier 			}
518*3de6a9c0SDavid du Colombier 		 	if(r & Ddcd){
519*3de6a9c0SDavid du Colombier 				old = r & Dcd;
520*3de6a9c0SDavid du Colombier 				if(uart->hup_dcd && uart->dcd && !old)
521*3de6a9c0SDavid du Colombier 					uart->dohup = 1;
522*3de6a9c0SDavid du Colombier 				uart->dcd = old;
523*3de6a9c0SDavid du Colombier 			}
524*3de6a9c0SDavid du Colombier 			break;
525*3de6a9c0SDavid du Colombier 		case Ithre:		/* Thr Empty */
526*3de6a9c0SDavid du Colombier 			uartkick(uart);
527*3de6a9c0SDavid du Colombier 			break;
528*3de6a9c0SDavid du Colombier 		case Irda:		/* Received Data Available */
529*3de6a9c0SDavid du Colombier 		case Irls:		/* Receiver Line Status */
530*3de6a9c0SDavid du Colombier 		case Ictoi:		/* Character Time-out Indication */
531*3de6a9c0SDavid du Colombier 			/*
532*3de6a9c0SDavid du Colombier 			 * Consume any received data.
533*3de6a9c0SDavid du Colombier 			 * If the received byte came in with a break,
534*3de6a9c0SDavid du Colombier 			 * parity or framing error, throw it away;
535*3de6a9c0SDavid du Colombier 			 * overrun is an indication that something has
536*3de6a9c0SDavid du Colombier 			 * already been tossed.
537*3de6a9c0SDavid du Colombier 			 */
538*3de6a9c0SDavid du Colombier 			while((lsr = csr8r(ctlr, Lsr)) & Dr){
539*3de6a9c0SDavid du Colombier 				if(lsr & (FIFOerr|Oe))
540*3de6a9c0SDavid du Colombier 					uart->oerr++;
541*3de6a9c0SDavid du Colombier 				if(lsr & Pe)
542*3de6a9c0SDavid du Colombier 					uart->perr++;
543*3de6a9c0SDavid du Colombier 				if(lsr & Fe)
544*3de6a9c0SDavid du Colombier 					uart->ferr++;
545*3de6a9c0SDavid du Colombier 				r = csr8r(ctlr, Rbr);
546*3de6a9c0SDavid du Colombier 				if(!(lsr & (Bi|Fe|Pe)))
547*3de6a9c0SDavid du Colombier 					uartrecv(uart, r);
548*3de6a9c0SDavid du Colombier 			}
549*3de6a9c0SDavid du Colombier 			break;
550*3de6a9c0SDavid du Colombier 
551*3de6a9c0SDavid du Colombier 		default:
552*3de6a9c0SDavid du Colombier 			iprint("weird uart interrupt type %#2.2uX\n", iir);
553*3de6a9c0SDavid du Colombier 			break;
554*3de6a9c0SDavid du Colombier 		}
555*3de6a9c0SDavid du Colombier 	}
556*3de6a9c0SDavid du Colombier }
557*3de6a9c0SDavid du Colombier 
558*3de6a9c0SDavid du Colombier static void
i8250disable(Uart * uart)559*3de6a9c0SDavid du Colombier i8250disable(Uart* uart)
560*3de6a9c0SDavid du Colombier {
561*3de6a9c0SDavid du Colombier 	Ctlr *ctlr;
562*3de6a9c0SDavid du Colombier 
563*3de6a9c0SDavid du Colombier 	/*
564*3de6a9c0SDavid du Colombier 	 * Turn off DTR and RTS, disable interrupts and fifos.
565*3de6a9c0SDavid du Colombier 	 */
566*3de6a9c0SDavid du Colombier 	(*uart->phys->dtr)(uart, 0);
567*3de6a9c0SDavid du Colombier 	(*uart->phys->rts)(uart, 0);
568*3de6a9c0SDavid du Colombier 	(*uart->phys->fifo)(uart, 0);
569*3de6a9c0SDavid du Colombier 
570*3de6a9c0SDavid du Colombier 	ctlr = uart->regs;
571*3de6a9c0SDavid du Colombier 	ctlr->sticky[Ier] = 0;
572*3de6a9c0SDavid du Colombier 	csr8w(ctlr, Ier, 0);
573*3de6a9c0SDavid du Colombier 
574*3de6a9c0SDavid du Colombier 	if(ctlr->iena != 0){
575*3de6a9c0SDavid du Colombier 		if(irqdisable(ctlr->irq, i8250interrupt, uart, uart->name) == 0)
576*3de6a9c0SDavid du Colombier 			ctlr->iena = 0;
577*3de6a9c0SDavid du Colombier 	}
578*3de6a9c0SDavid du Colombier }
579*3de6a9c0SDavid du Colombier 
580*3de6a9c0SDavid du Colombier static void
i8250enable(Uart * uart,int ie)581*3de6a9c0SDavid du Colombier i8250enable(Uart* uart, int ie)
582*3de6a9c0SDavid du Colombier {
583*3de6a9c0SDavid du Colombier 	int mode;
584*3de6a9c0SDavid du Colombier 	Ctlr *ctlr;
585*3de6a9c0SDavid du Colombier 
586*3de6a9c0SDavid du Colombier 	if (up == nil)
587*3de6a9c0SDavid du Colombier 		return;				/* too soon */
588*3de6a9c0SDavid du Colombier 
589*3de6a9c0SDavid du Colombier 	ctlr = uart->regs;
590*3de6a9c0SDavid du Colombier 
591*3de6a9c0SDavid du Colombier 	/* omap only: set uart/irda/cir mode to uart */
592*3de6a9c0SDavid du Colombier 	mode = csr8r(ctlr, Mdr);
593*3de6a9c0SDavid du Colombier 	csr8o(ctlr, Mdr, (mode & ~Modemask) | Modeuart);
594*3de6a9c0SDavid du Colombier 
595*3de6a9c0SDavid du Colombier 	ctlr->sticky[Lcr] = Wls8;		/* no parity */
596*3de6a9c0SDavid du Colombier 	csr8w(ctlr, Lcr, 0);
597*3de6a9c0SDavid du Colombier 
598*3de6a9c0SDavid du Colombier 	/*
599*3de6a9c0SDavid du Colombier 	 * Check if there is a FIFO.
600*3de6a9c0SDavid du Colombier 	 * Changing the FIFOena bit in Fcr flushes data
601*3de6a9c0SDavid du Colombier 	 * from both receive and transmit FIFOs; there's
602*3de6a9c0SDavid du Colombier 	 * no easy way to guarantee not losing data on
603*3de6a9c0SDavid du Colombier 	 * the receive side, but it's possible to wait until
604*3de6a9c0SDavid du Colombier 	 * the transmitter is really empty.
605*3de6a9c0SDavid du Colombier 	 * Also, reading the Iir outwith i8250interrupt()
606*3de6a9c0SDavid du Colombier 	 * can be dangerous, but this should only happen
607*3de6a9c0SDavid du Colombier 	 * once, before interrupts are enabled.
608*3de6a9c0SDavid du Colombier 	 */
609*3de6a9c0SDavid du Colombier 	ilock(ctlr);
610*3de6a9c0SDavid du Colombier 	if(!ctlr->checkfifo){
611*3de6a9c0SDavid du Colombier 		/*
612*3de6a9c0SDavid du Colombier 		 * Wait until the transmitter is really empty.
613*3de6a9c0SDavid du Colombier 		 */
614*3de6a9c0SDavid du Colombier 		while(!(csr8r(ctlr, Lsr) & Temt))
615*3de6a9c0SDavid du Colombier 			;
616*3de6a9c0SDavid du Colombier 		csr8w(ctlr, Fcr, FIFOena);
617*3de6a9c0SDavid du Colombier 		if(csr8r(ctlr, Iir) & Ifena)
618*3de6a9c0SDavid du Colombier 			ctlr->hasfifo = 1;
619*3de6a9c0SDavid du Colombier 		csr8w(ctlr, Fcr, 0);
620*3de6a9c0SDavid du Colombier 		ctlr->checkfifo = 1;
621*3de6a9c0SDavid du Colombier 	}
622*3de6a9c0SDavid du Colombier 	iunlock(ctlr);
623*3de6a9c0SDavid du Colombier 
624*3de6a9c0SDavid du Colombier 	/*
625*3de6a9c0SDavid du Colombier 	 * Enable interrupts and turn on DTR and RTS.
626*3de6a9c0SDavid du Colombier 	 * Be careful if this is called to set up a polled serial line
627*3de6a9c0SDavid du Colombier 	 * early on not to try to enable interrupts as interrupt-
628*3de6a9c0SDavid du Colombier 	 * -enabling mechanisms might not be set up yet.
629*3de6a9c0SDavid du Colombier 	 */
630*3de6a9c0SDavid du Colombier 	if(ie){
631*3de6a9c0SDavid du Colombier 		if(ctlr->iena == 0 && !ctlr->poll){
632*3de6a9c0SDavid du Colombier 			irqenable(ctlr->irq, i8250interrupt, uart, uart->name);
633*3de6a9c0SDavid du Colombier 			ctlr->iena = 1;
634*3de6a9c0SDavid du Colombier 		}
635*3de6a9c0SDavid du Colombier 		ctlr->sticky[Ier] = Erda;
636*3de6a9c0SDavid du Colombier //		ctlr->sticky[Mcr] |= Ie;		/* not on omap */
637*3de6a9c0SDavid du Colombier 		ctlr->sticky[Mcr] = 0;
638*3de6a9c0SDavid du Colombier 	}
639*3de6a9c0SDavid du Colombier 	else{
640*3de6a9c0SDavid du Colombier 		ctlr->sticky[Ier] = 0;
641*3de6a9c0SDavid du Colombier 		ctlr->sticky[Mcr] = 0;
642*3de6a9c0SDavid du Colombier 	}
643*3de6a9c0SDavid du Colombier 	csr8w(ctlr, Ier, 0);
644*3de6a9c0SDavid du Colombier 	csr8w(ctlr, Mcr, 0);
645*3de6a9c0SDavid du Colombier 
646*3de6a9c0SDavid du Colombier 	(*uart->phys->dtr)(uart, 1);
647*3de6a9c0SDavid du Colombier 	(*uart->phys->rts)(uart, 1);
648*3de6a9c0SDavid du Colombier 
649*3de6a9c0SDavid du Colombier 	/*
650*3de6a9c0SDavid du Colombier 	 * During startup, the i8259 interrupt controller is reset.
651*3de6a9c0SDavid du Colombier 	 * This may result in a lost interrupt from the i8250 uart.
652*3de6a9c0SDavid du Colombier 	 * The i8250 thinks the interrupt is still outstanding and does not
653*3de6a9c0SDavid du Colombier 	 * generate any further interrupts. The workaround is to call the
654*3de6a9c0SDavid du Colombier 	 * interrupt handler to clear any pending interrupt events.
655*3de6a9c0SDavid du Colombier 	 * Note: this must be done after setting Ier.
656*3de6a9c0SDavid du Colombier 	 */
657*3de6a9c0SDavid du Colombier 	if(ie)
658*3de6a9c0SDavid du Colombier 		i8250interrupt(nil, uart);
659*3de6a9c0SDavid du Colombier }
660*3de6a9c0SDavid du Colombier 
661*3de6a9c0SDavid du Colombier static Uart*
i8250pnp(void)662*3de6a9c0SDavid du Colombier i8250pnp(void)
663*3de6a9c0SDavid du Colombier {
664*3de6a9c0SDavid du Colombier 	return i8250uart;
665*3de6a9c0SDavid du Colombier }
666*3de6a9c0SDavid du Colombier 
667*3de6a9c0SDavid du Colombier static int
i8250getc(Uart * uart)668*3de6a9c0SDavid du Colombier i8250getc(Uart* uart)
669*3de6a9c0SDavid du Colombier {
670*3de6a9c0SDavid du Colombier 	Ctlr *ctlr;
671*3de6a9c0SDavid du Colombier 
672*3de6a9c0SDavid du Colombier 	ctlr = uart->regs;
673*3de6a9c0SDavid du Colombier 	while(!(csr8r(ctlr, Lsr) & Dr))
674*3de6a9c0SDavid du Colombier 		delay(1);
675*3de6a9c0SDavid du Colombier 	return csr8r(ctlr, Rbr);
676*3de6a9c0SDavid du Colombier }
677*3de6a9c0SDavid du Colombier 
678*3de6a9c0SDavid du Colombier static void
i8250putc(Uart * uart,int c)679*3de6a9c0SDavid du Colombier i8250putc(Uart* uart, int c)
680*3de6a9c0SDavid du Colombier {
681*3de6a9c0SDavid du Colombier 	int i;
682*3de6a9c0SDavid du Colombier 	Ctlr *ctlr;
683*3de6a9c0SDavid du Colombier 
684*3de6a9c0SDavid du Colombier 	if (!normalprint) {		/* too early; use brute force */
685*3de6a9c0SDavid du Colombier 		int s = splhi();
686*3de6a9c0SDavid du Colombier 
687*3de6a9c0SDavid du Colombier 		while (!(((ulong *)PHYSCONS)[Lsr] & Thre))
688*3de6a9c0SDavid du Colombier 			;
689*3de6a9c0SDavid du Colombier 		((ulong *)PHYSCONS)[Thr] = c;
690*3de6a9c0SDavid du Colombier 		coherence();
691*3de6a9c0SDavid du Colombier 		splx(s);
692*3de6a9c0SDavid du Colombier 		return;
693*3de6a9c0SDavid du Colombier 	}
694*3de6a9c0SDavid du Colombier 
695*3de6a9c0SDavid du Colombier 	ctlr = uart->regs;
696*3de6a9c0SDavid du Colombier 	for(i = 0; !(csr8r(ctlr, Lsr) & Thre) && i < 128; i++)
697*3de6a9c0SDavid du Colombier 		delay(1);
698*3de6a9c0SDavid du Colombier 	csr8o(ctlr, Thr, (uchar)c);
699*3de6a9c0SDavid du Colombier 	for(i = 0; !(csr8r(ctlr, Lsr) & Thre) && i < 128; i++)
700*3de6a9c0SDavid du Colombier 		delay(1);
701*3de6a9c0SDavid du Colombier }
702*3de6a9c0SDavid du Colombier 
703*3de6a9c0SDavid du Colombier void
serialputc(int c)704*3de6a9c0SDavid du Colombier serialputc(int c)
705*3de6a9c0SDavid du Colombier {
706*3de6a9c0SDavid du Colombier 	i8250putc(&i8250uart[CONSOLE], c);
707*3de6a9c0SDavid du Colombier }
708*3de6a9c0SDavid du Colombier 
709*3de6a9c0SDavid du Colombier void
serialputs(char * s,int n)710*3de6a9c0SDavid du Colombier serialputs(char* s, int n)
711*3de6a9c0SDavid du Colombier {
712*3de6a9c0SDavid du Colombier 	_uartputs(s, n);
713*3de6a9c0SDavid du Colombier }
714*3de6a9c0SDavid du Colombier 
715*3de6a9c0SDavid du Colombier #ifdef notdef
716*3de6a9c0SDavid du Colombier static void
i8250poll(Uart * uart)717*3de6a9c0SDavid du Colombier i8250poll(Uart* uart)
718*3de6a9c0SDavid du Colombier {
719*3de6a9c0SDavid du Colombier 	Ctlr *ctlr;
720*3de6a9c0SDavid du Colombier 
721*3de6a9c0SDavid du Colombier 	/*
722*3de6a9c0SDavid du Colombier 	 * If PhysUart has a non-nil .poll member, this
723*3de6a9c0SDavid du Colombier 	 * routine will be called from the uartclock timer.
724*3de6a9c0SDavid du Colombier 	 * If the Ctlr .poll member is non-zero, when the
725*3de6a9c0SDavid du Colombier 	 * Uart is enabled interrupts will not be enabled
726*3de6a9c0SDavid du Colombier 	 * and the result is polled input and output.
727*3de6a9c0SDavid du Colombier 	 * Not very useful here, but ports to new hardware
728*3de6a9c0SDavid du Colombier 	 * or simulators can use this to get serial I/O
729*3de6a9c0SDavid du Colombier 	 * without setting up the interrupt mechanism.
730*3de6a9c0SDavid du Colombier 	 */
731*3de6a9c0SDavid du Colombier 	ctlr = uart->regs;
732*3de6a9c0SDavid du Colombier 	if(ctlr->iena || !ctlr->poll)
733*3de6a9c0SDavid du Colombier 		return;
734*3de6a9c0SDavid du Colombier 	i8250interrupt(nil, uart);
735*3de6a9c0SDavid du Colombier }
736*3de6a9c0SDavid du Colombier #endif
737*3de6a9c0SDavid du Colombier 
738*3de6a9c0SDavid du Colombier PhysUart i8250physuart = {
739*3de6a9c0SDavid du Colombier 	.name		= "i8250",
740*3de6a9c0SDavid du Colombier 	.pnp		= i8250pnp,
741*3de6a9c0SDavid du Colombier 	.enable		= i8250enable,
742*3de6a9c0SDavid du Colombier 	.disable	= i8250disable,
743*3de6a9c0SDavid du Colombier 	.kick		= i8250kick,
744*3de6a9c0SDavid du Colombier 	.dobreak	= i8250break,
745*3de6a9c0SDavid du Colombier 	.baud		= i8250baud,
746*3de6a9c0SDavid du Colombier 	.bits		= i8250bits,
747*3de6a9c0SDavid du Colombier 	.stop		= i8250stop,
748*3de6a9c0SDavid du Colombier 	.parity		= i8250parity,
749*3de6a9c0SDavid du Colombier 	.modemctl	= i8250modemctl,
750*3de6a9c0SDavid du Colombier 	.rts		= i8250rts,
751*3de6a9c0SDavid du Colombier 	.dtr		= i8250dtr,
752*3de6a9c0SDavid du Colombier 	.status		= i8250status,
753*3de6a9c0SDavid du Colombier 	.fifo		= i8250fifo,
754*3de6a9c0SDavid du Colombier 	.getc		= i8250getc,
755*3de6a9c0SDavid du Colombier 	.putc		= i8250putc,
756*3de6a9c0SDavid du Colombier //	.poll		= i8250poll,		/* only in 9k, not 9 */
757*3de6a9c0SDavid du Colombier };
758*3de6a9c0SDavid du Colombier 
759*3de6a9c0SDavid du Colombier static void
i8250dumpregs(Ctlr * ctlr)760*3de6a9c0SDavid du Colombier i8250dumpregs(Ctlr* ctlr)
761*3de6a9c0SDavid du Colombier {
762*3de6a9c0SDavid du Colombier 	int dlm, dll;
763*3de6a9c0SDavid du Colombier 	int _uartprint(char*, ...);
764*3de6a9c0SDavid du Colombier 
765*3de6a9c0SDavid du Colombier 	csr8w(ctlr, Lcr, Dlab);
766*3de6a9c0SDavid du Colombier 	dlm = csr8r(ctlr, Dlm);
767*3de6a9c0SDavid du Colombier 	dll = csr8r(ctlr, Dll);
768*3de6a9c0SDavid du Colombier 	csr8w(ctlr, Lcr, 0);
769*3de6a9c0SDavid du Colombier 
770*3de6a9c0SDavid du Colombier 	_uartprint("dlm %#ux dll %#ux\n", dlm, dll);
771*3de6a9c0SDavid du Colombier }
772*3de6a9c0SDavid du Colombier 
773*3de6a9c0SDavid du Colombier Uart*	uartenable(Uart *p);
774*3de6a9c0SDavid du Colombier 
775*3de6a9c0SDavid du Colombier /* must call this from a process's context */
776*3de6a9c0SDavid du Colombier int
i8250console(void)777*3de6a9c0SDavid du Colombier i8250console(void)
778*3de6a9c0SDavid du Colombier {
779*3de6a9c0SDavid du Colombier 	Uart *uart = &i8250uart[CONSOLE];
780*3de6a9c0SDavid du Colombier 
781*3de6a9c0SDavid du Colombier 	if (up == nil)
782*3de6a9c0SDavid du Colombier 		return -1;			/* too early */
783*3de6a9c0SDavid du Colombier 
784*3de6a9c0SDavid du Colombier 	if(uartenable(uart) != nil /* && uart->console */){
785*3de6a9c0SDavid du Colombier 		// iprint("i8250console: enabling console uart\n");
786*3de6a9c0SDavid du Colombier 		kbdq = uart->iq;
787*3de6a9c0SDavid du Colombier 		serialoq = uart->oq;
788*3de6a9c0SDavid du Colombier 		uart->putc = kbdcr2nl;
789*3de6a9c0SDavid du Colombier 		uart->opens++;
790*3de6a9c0SDavid du Colombier 		consuart = uart;
791*3de6a9c0SDavid du Colombier 	}
792*3de6a9c0SDavid du Colombier 	uartctl(uart, "b115200 l8 pn r1 s1 i1");
793*3de6a9c0SDavid du Colombier 	return 0;
794*3de6a9c0SDavid du Colombier }
795*3de6a9c0SDavid du Colombier 
796*3de6a9c0SDavid du Colombier void
_uartputs(char * s,int n)797*3de6a9c0SDavid du Colombier _uartputs(char* s, int n)
798*3de6a9c0SDavid du Colombier {
799*3de6a9c0SDavid du Colombier 	char *e;
800*3de6a9c0SDavid du Colombier 
801*3de6a9c0SDavid du Colombier 	for(e = s+n; s < e; s++){
802*3de6a9c0SDavid du Colombier 		if(*s == '\n')
803*3de6a9c0SDavid du Colombier 			i8250putc(&i8250uart[CONSOLE], '\r');
804*3de6a9c0SDavid du Colombier 		i8250putc(&i8250uart[CONSOLE], *s);
805*3de6a9c0SDavid du Colombier 	}
806*3de6a9c0SDavid du Colombier }
807*3de6a9c0SDavid du Colombier 
808*3de6a9c0SDavid du Colombier int
_uartprint(char * fmt,...)809*3de6a9c0SDavid du Colombier _uartprint(char* fmt, ...)
810*3de6a9c0SDavid du Colombier {
811*3de6a9c0SDavid du Colombier 	int n;
812*3de6a9c0SDavid du Colombier 	va_list arg;
813*3de6a9c0SDavid du Colombier 	char buf[PRINTSIZE];
814*3de6a9c0SDavid du Colombier 
815*3de6a9c0SDavid du Colombier 	va_start(arg, fmt);
816*3de6a9c0SDavid du Colombier 	n = vseprint(buf, buf+sizeof(buf), fmt, arg) - buf;
817*3de6a9c0SDavid du Colombier 	va_end(arg);
818*3de6a9c0SDavid du Colombier 	_uartputs(buf, n);
819*3de6a9c0SDavid du Colombier 
820*3de6a9c0SDavid du Colombier 	return n;
821*3de6a9c0SDavid du Colombier }
822