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