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