1*9a747e4fSDavid du Colombier #include "u.h"
2*9a747e4fSDavid du Colombier #include "../port/lib.h"
3*9a747e4fSDavid du Colombier #include "mem.h"
4*9a747e4fSDavid du Colombier #include "dat.h"
5*9a747e4fSDavid du Colombier #include "fns.h"
6*9a747e4fSDavid du Colombier #include "io.h"
7*9a747e4fSDavid du Colombier #include "../port/error.h"
8*9a747e4fSDavid du Colombier
9*9a747e4fSDavid du Colombier /*
10*9a747e4fSDavid du Colombier * 8250 UART and compatibles.
11*9a747e4fSDavid du Colombier */
12*9a747e4fSDavid du Colombier enum {
13*9a747e4fSDavid du Colombier Uart0 = 0x3F8, /* COM1 */
14*9a747e4fSDavid du Colombier Uart0IRQ = 4,
15*9a747e4fSDavid du Colombier Uart1 = 0x2F8, /* COM2 */
16*9a747e4fSDavid du Colombier Uart1IRQ = 3,
17*9a747e4fSDavid du Colombier
18*9a747e4fSDavid du Colombier UartFREQ = 1843200,
19*9a747e4fSDavid du Colombier };
20*9a747e4fSDavid du Colombier
21*9a747e4fSDavid du Colombier enum { /* I/O ports */
22*9a747e4fSDavid du Colombier Rbr = 0, /* Receiver Buffer (RO) */
23*9a747e4fSDavid du Colombier Thr = 0, /* Transmitter Holding (WO) */
24*9a747e4fSDavid du Colombier Ier = 1, /* Interrupt Enable */
25*9a747e4fSDavid du Colombier Iir = 2, /* Interrupt Identification (RO) */
26*9a747e4fSDavid du Colombier Fcr = 2, /* FIFO Control (WO) */
27*9a747e4fSDavid du Colombier Lcr = 3, /* Line Control */
28*9a747e4fSDavid du Colombier Mcr = 4, /* Modem Control */
29*9a747e4fSDavid du Colombier Lsr = 5, /* Line Status */
30*9a747e4fSDavid du Colombier Msr = 6, /* Modem Status */
31*9a747e4fSDavid du Colombier Scr = 7, /* Scratch Pad */
32*9a747e4fSDavid du Colombier Dll = 0, /* Divisor Latch LSB */
33*9a747e4fSDavid du Colombier Dlm = 1, /* Divisor Latch MSB */
34*9a747e4fSDavid du Colombier };
35*9a747e4fSDavid du Colombier
36*9a747e4fSDavid du Colombier enum { /* Ier */
37*9a747e4fSDavid du Colombier Erda = 0x01, /* Enable Received Data Available */
38*9a747e4fSDavid du Colombier Ethre = 0x02, /* Enable Thr Empty */
39*9a747e4fSDavid du Colombier Erls = 0x04, /* Enable Receiver Line Status */
40*9a747e4fSDavid du Colombier Ems = 0x08, /* Enable Modem Status */
41*9a747e4fSDavid du Colombier };
42*9a747e4fSDavid du Colombier
43*9a747e4fSDavid du Colombier enum { /* Iir */
44*9a747e4fSDavid du Colombier Ims = 0x00, /* Ms interrupt */
45*9a747e4fSDavid du Colombier Ip = 0x01, /* Interrupt Pending (not) */
46*9a747e4fSDavid du Colombier Ithre = 0x02, /* Thr Empty */
47*9a747e4fSDavid du Colombier Irda = 0x04, /* Received Data Available */
48*9a747e4fSDavid du Colombier Irls = 0x06, /* Receiver Line Status */
49*9a747e4fSDavid du Colombier Ictoi = 0x0C, /* Character Time-out Indication */
50*9a747e4fSDavid du Colombier IirMASK = 0x3F,
51*9a747e4fSDavid du Colombier Ife = 0xC0, /* FIFOs enabled */
52*9a747e4fSDavid du Colombier };
53*9a747e4fSDavid du Colombier
54*9a747e4fSDavid du Colombier enum { /* Fcr */
55*9a747e4fSDavid du Colombier FIFOena = 0x01, /* FIFO enable */
56*9a747e4fSDavid du Colombier FIFOrclr = 0x02, /* clear Rx FIFO */
57*9a747e4fSDavid du Colombier FIFOtclr = 0x04, /* clear Tx FIFO */
58*9a747e4fSDavid du Colombier FIFO1 = 0x00, /* Rx FIFO trigger level 1 byte */
59*9a747e4fSDavid du Colombier FIFO4 = 0x40, /* 4 bytes */
60*9a747e4fSDavid du Colombier FIFO8 = 0x80, /* 8 bytes */
61*9a747e4fSDavid du Colombier FIFO14 = 0xC0, /* 14 bytes */
62*9a747e4fSDavid du Colombier };
63*9a747e4fSDavid du Colombier
64*9a747e4fSDavid du Colombier enum { /* Lcr */
65*9a747e4fSDavid du Colombier Wls5 = 0x00, /* Word Length Select 5 bits/byte */
66*9a747e4fSDavid du Colombier Wls6 = 0x01, /* 6 bits/byte */
67*9a747e4fSDavid du Colombier Wls7 = 0x02, /* 7 bits/byte */
68*9a747e4fSDavid du Colombier Wls8 = 0x03, /* 8 bits/byte */
69*9a747e4fSDavid du Colombier WlsMASK = 0x03,
70*9a747e4fSDavid du Colombier Stb = 0x04, /* 2 stop bits */
71*9a747e4fSDavid du Colombier Pen = 0x08, /* Parity Enable */
72*9a747e4fSDavid du Colombier Eps = 0x10, /* Even Parity Select */
73*9a747e4fSDavid du Colombier Stp = 0x20, /* Stick Parity */
74*9a747e4fSDavid du Colombier Brk = 0x40, /* Break */
75*9a747e4fSDavid du Colombier Dlab = 0x80, /* Divisor Latch Access Bit */
76*9a747e4fSDavid du Colombier };
77*9a747e4fSDavid du Colombier
78*9a747e4fSDavid du Colombier enum { /* Mcr */
79*9a747e4fSDavid du Colombier Dtr = 0x01, /* Data Terminal Ready */
80*9a747e4fSDavid du Colombier Rts = 0x02, /* Ready To Send */
81*9a747e4fSDavid du Colombier Out1 = 0x04, /* no longer in use */
82*9a747e4fSDavid du Colombier Ie = 0x08, /* IRQ Enable */
83*9a747e4fSDavid du Colombier Dm = 0x10, /* Diagnostic Mode loopback */
84*9a747e4fSDavid du Colombier };
85*9a747e4fSDavid du Colombier
86*9a747e4fSDavid du Colombier enum { /* Lsr */
87*9a747e4fSDavid du Colombier Dr = 0x01, /* Data Ready */
88*9a747e4fSDavid du Colombier Oe = 0x02, /* Overrun Error */
89*9a747e4fSDavid du Colombier Pe = 0x04, /* Parity Error */
90*9a747e4fSDavid du Colombier Fe = 0x08, /* Framing Error */
91*9a747e4fSDavid du Colombier Bi = 0x10, /* Break Interrupt */
92*9a747e4fSDavid du Colombier Thre = 0x20, /* Thr Empty */
93*9a747e4fSDavid du Colombier Temt = 0x40, /* Tramsmitter Empty */
94*9a747e4fSDavid du Colombier FIFOerr = 0x80, /* error in receiver FIFO */
95*9a747e4fSDavid du Colombier };
96*9a747e4fSDavid du Colombier
97*9a747e4fSDavid du Colombier enum { /* Msr */
98*9a747e4fSDavid du Colombier Dcts = 0x01, /* Delta Cts */
99*9a747e4fSDavid du Colombier Ddsr = 0x02, /* Delta Dsr */
100*9a747e4fSDavid du Colombier Teri = 0x04, /* Trailing Edge of Ri */
101*9a747e4fSDavid du Colombier Ddcd = 0x08, /* Delta Dcd */
102*9a747e4fSDavid du Colombier Cts = 0x10, /* Clear To Send */
103*9a747e4fSDavid du Colombier Dsr = 0x20, /* Data Set Ready */
104*9a747e4fSDavid du Colombier Ri = 0x40, /* Ring Indicator */
105*9a747e4fSDavid du Colombier Dcd = 0x80, /* Data Set Ready */
106*9a747e4fSDavid du Colombier };
107*9a747e4fSDavid du Colombier
108*9a747e4fSDavid du Colombier typedef struct Ctlr {
109*9a747e4fSDavid du Colombier int io;
110*9a747e4fSDavid du Colombier int irq;
111*9a747e4fSDavid du Colombier int tbdf;
112*9a747e4fSDavid du Colombier int iena;
113*9a747e4fSDavid du Colombier
114*9a747e4fSDavid du Colombier uchar sticky[8];
115*9a747e4fSDavid du Colombier
116*9a747e4fSDavid du Colombier Lock;
117*9a747e4fSDavid du Colombier int fifo;
118*9a747e4fSDavid du Colombier int fena;
119*9a747e4fSDavid du Colombier } Ctlr;
120*9a747e4fSDavid du Colombier
121*9a747e4fSDavid du Colombier extern PhysUart i8250physuart;
122*9a747e4fSDavid du Colombier
123*9a747e4fSDavid du Colombier static Ctlr i8250ctlr[2] = {
124*9a747e4fSDavid du Colombier { .io = Uart0,
125*9a747e4fSDavid du Colombier .irq = Uart0IRQ,
126*9a747e4fSDavid du Colombier .tbdf = BUSUNKNOWN, },
127*9a747e4fSDavid du Colombier
128*9a747e4fSDavid du Colombier { .io = Uart1,
129*9a747e4fSDavid du Colombier .irq = Uart1IRQ,
130*9a747e4fSDavid du Colombier .tbdf = BUSUNKNOWN, },
131*9a747e4fSDavid du Colombier };
132*9a747e4fSDavid du Colombier
133*9a747e4fSDavid du Colombier static Uart i8250uart[2] = {
134*9a747e4fSDavid du Colombier { .regs = &i8250ctlr[0],
135*9a747e4fSDavid du Colombier .name = "COM1",
136*9a747e4fSDavid du Colombier .freq = UartFREQ,
137*9a747e4fSDavid du Colombier .phys = &i8250physuart,
138*9a747e4fSDavid du Colombier .special=0,
139*9a747e4fSDavid du Colombier .next = &i8250uart[1], },
140*9a747e4fSDavid du Colombier
141*9a747e4fSDavid du Colombier { .regs = &i8250ctlr[1],
142*9a747e4fSDavid du Colombier .name = "COM2",
143*9a747e4fSDavid du Colombier .freq = UartFREQ,
144*9a747e4fSDavid du Colombier .phys = &i8250physuart,
145*9a747e4fSDavid du Colombier .special=0,
146*9a747e4fSDavid du Colombier .next = nil, },
147*9a747e4fSDavid du Colombier };
148*9a747e4fSDavid du Colombier
149*9a747e4fSDavid du Colombier #define csr8r(c, r) inb((c)->io+(r))
150*9a747e4fSDavid du Colombier #define csr8w(c, r, v) outb((c)->io+(r), (c)->sticky[(r)]|(v))
151*9a747e4fSDavid du Colombier
152*9a747e4fSDavid du Colombier static long
i8250status(Uart * uart,void * buf,long n,long offset)153*9a747e4fSDavid du Colombier i8250status(Uart* uart, void* buf, long n, long offset)
154*9a747e4fSDavid du Colombier {
155*9a747e4fSDavid du Colombier char *p;
156*9a747e4fSDavid du Colombier Ctlr *ctlr;
157*9a747e4fSDavid du Colombier uchar ier, lcr, mcr, msr;
158*9a747e4fSDavid du Colombier
159*9a747e4fSDavid du Colombier ctlr = uart->regs;
160*9a747e4fSDavid du Colombier p = malloc(READSTR);
161*9a747e4fSDavid du Colombier mcr = ctlr->sticky[Mcr];
162*9a747e4fSDavid du Colombier msr = csr8r(ctlr, Msr);
163*9a747e4fSDavid du Colombier ier = ctlr->sticky[Ier];
164*9a747e4fSDavid du Colombier lcr = ctlr->sticky[Lcr];
165*9a747e4fSDavid du Colombier snprint(p, READSTR,
166*9a747e4fSDavid du Colombier "b%d c%d d%d e%d l%d m%d p%c r%d s%d i%d\n"
167*9a747e4fSDavid du Colombier "dev(%d) type(%d) framing(%d) overruns(%d)%s%s%s%s\n",
168*9a747e4fSDavid du Colombier
169*9a747e4fSDavid du Colombier uart->baud,
170*9a747e4fSDavid du Colombier uart->hup_dcd,
171*9a747e4fSDavid du Colombier (msr & Dsr) != 0,
172*9a747e4fSDavid du Colombier uart->hup_dsr,
173*9a747e4fSDavid du Colombier (lcr & WlsMASK) + 5,
174*9a747e4fSDavid du Colombier (ier & Ems) != 0,
175*9a747e4fSDavid du Colombier (lcr & Pen) ? ((lcr & Eps) ? 'e': 'o'): 'n',
176*9a747e4fSDavid du Colombier (mcr & Rts) != 0,
177*9a747e4fSDavid du Colombier (lcr & Stb) ? 2: 1,
178*9a747e4fSDavid du Colombier ctlr->fena,
179*9a747e4fSDavid du Colombier
180*9a747e4fSDavid du Colombier uart->dev,
181*9a747e4fSDavid du Colombier uart->type,
182*9a747e4fSDavid du Colombier uart->ferr,
183*9a747e4fSDavid du Colombier uart->oerr,
184*9a747e4fSDavid du Colombier (msr & Cts) ? " cts": "",
185*9a747e4fSDavid du Colombier (msr & Dsr) ? " dsr": "",
186*9a747e4fSDavid du Colombier (msr & Dcd) ? " dcd": "",
187*9a747e4fSDavid du Colombier (msr & Ri) ? " ring": ""
188*9a747e4fSDavid du Colombier );
189*9a747e4fSDavid du Colombier n = readstr(offset, buf, n, p);
190*9a747e4fSDavid du Colombier free(p);
191*9a747e4fSDavid du Colombier
192*9a747e4fSDavid du Colombier return n;
193*9a747e4fSDavid du Colombier }
194*9a747e4fSDavid du Colombier
195*9a747e4fSDavid du Colombier static void
i8250fifo(Uart * uart,int on)196*9a747e4fSDavid du Colombier i8250fifo(Uart* uart, int on)
197*9a747e4fSDavid du Colombier {
198*9a747e4fSDavid du Colombier int i;
199*9a747e4fSDavid du Colombier Ctlr *ctlr;
200*9a747e4fSDavid du Colombier
201*9a747e4fSDavid du Colombier /*
202*9a747e4fSDavid du Colombier * Toggle FIFOs:
203*9a747e4fSDavid du Colombier * if none, do nothing;
204*9a747e4fSDavid du Colombier * reset the Rx and Tx FIFOs;
205*9a747e4fSDavid du Colombier * empty the Rx buffer and clear any interrupt conditions;
206*9a747e4fSDavid du Colombier * if enabling, try to turn them on.
207*9a747e4fSDavid du Colombier */
208*9a747e4fSDavid du Colombier ctlr = uart->regs;
209*9a747e4fSDavid du Colombier
210*9a747e4fSDavid du Colombier ilock(ctlr);
211*9a747e4fSDavid du Colombier if(!ctlr->fifo){
212*9a747e4fSDavid du Colombier csr8w(ctlr, Fcr, FIFOtclr|FIFOrclr);
213*9a747e4fSDavid du Colombier for(i = 0; i < 16; i++){
214*9a747e4fSDavid du Colombier csr8r(ctlr, Iir);
215*9a747e4fSDavid du Colombier csr8r(ctlr, Rbr);
216*9a747e4fSDavid du Colombier }
217*9a747e4fSDavid du Colombier
218*9a747e4fSDavid du Colombier ctlr->fena = 0;
219*9a747e4fSDavid du Colombier if(on){
220*9a747e4fSDavid du Colombier csr8w(ctlr, Fcr, FIFO4|FIFOena);
221*9a747e4fSDavid du Colombier if(!(csr8r(ctlr, Iir) & Ife))
222*9a747e4fSDavid du Colombier ctlr->fifo = 1;
223*9a747e4fSDavid du Colombier ctlr->fena = 1;
224*9a747e4fSDavid du Colombier }
225*9a747e4fSDavid du Colombier }
226*9a747e4fSDavid du Colombier iunlock(ctlr);
227*9a747e4fSDavid du Colombier }
228*9a747e4fSDavid du Colombier
229*9a747e4fSDavid du Colombier static void
i8250dtr(Uart * uart,int on)230*9a747e4fSDavid du Colombier i8250dtr(Uart* uart, int on)
231*9a747e4fSDavid du Colombier {
232*9a747e4fSDavid du Colombier Ctlr *ctlr;
233*9a747e4fSDavid du Colombier
234*9a747e4fSDavid du Colombier /*
235*9a747e4fSDavid du Colombier * Toggle DTR.
236*9a747e4fSDavid du Colombier */
237*9a747e4fSDavid du Colombier ctlr = uart->regs;
238*9a747e4fSDavid du Colombier if(on)
239*9a747e4fSDavid du Colombier ctlr->sticky[Mcr] |= Dtr;
240*9a747e4fSDavid du Colombier else
241*9a747e4fSDavid du Colombier ctlr->sticky[Mcr] &= ~Dtr;
242*9a747e4fSDavid du Colombier csr8w(ctlr, Mcr, 0);
243*9a747e4fSDavid du Colombier }
244*9a747e4fSDavid du Colombier
245*9a747e4fSDavid du Colombier static void
i8250rts(Uart * uart,int on)246*9a747e4fSDavid du Colombier i8250rts(Uart* uart, int on)
247*9a747e4fSDavid du Colombier {
248*9a747e4fSDavid du Colombier Ctlr *ctlr;
249*9a747e4fSDavid du Colombier
250*9a747e4fSDavid du Colombier /*
251*9a747e4fSDavid du Colombier * Toggle RTS.
252*9a747e4fSDavid du Colombier */
253*9a747e4fSDavid du Colombier ctlr = uart->regs;
254*9a747e4fSDavid du Colombier if(on)
255*9a747e4fSDavid du Colombier ctlr->sticky[Mcr] |= Rts;
256*9a747e4fSDavid du Colombier else
257*9a747e4fSDavid du Colombier ctlr->sticky[Mcr] &= ~Rts;
258*9a747e4fSDavid du Colombier csr8w(ctlr, Mcr, 0);
259*9a747e4fSDavid du Colombier }
260*9a747e4fSDavid du Colombier
261*9a747e4fSDavid du Colombier static void
i8250modemctl(Uart * uart,int on)262*9a747e4fSDavid du Colombier i8250modemctl(Uart* uart, int on)
263*9a747e4fSDavid du Colombier {
264*9a747e4fSDavid du Colombier Ctlr *ctlr;
265*9a747e4fSDavid du Colombier
266*9a747e4fSDavid du Colombier ctlr = uart->regs;
267*9a747e4fSDavid du Colombier ilock(&uart->tlock);
268*9a747e4fSDavid du Colombier if(on){
269*9a747e4fSDavid du Colombier ctlr->sticky[Ier] |= Ems;
270*9a747e4fSDavid du Colombier csr8w(ctlr, Ier, 0);
271*9a747e4fSDavid du Colombier uart->modem = 1;
272*9a747e4fSDavid du Colombier uart->cts = csr8r(ctlr, Msr) & Cts;
273*9a747e4fSDavid du Colombier }
274*9a747e4fSDavid du Colombier else{
275*9a747e4fSDavid du Colombier ctlr->sticky[Ier] &= ~Ems;
276*9a747e4fSDavid du Colombier csr8w(ctlr, Ier, 0);
277*9a747e4fSDavid du Colombier uart->modem = 0;
278*9a747e4fSDavid du Colombier uart->cts = 1;
279*9a747e4fSDavid du Colombier }
280*9a747e4fSDavid du Colombier iunlock(&uart->tlock);
281*9a747e4fSDavid du Colombier
282*9a747e4fSDavid du Colombier /* modem needs fifo */
283*9a747e4fSDavid du Colombier (*uart->phys->fifo)(uart, on);
284*9a747e4fSDavid du Colombier }
285*9a747e4fSDavid du Colombier
286*9a747e4fSDavid du Colombier static int
i8250parity(Uart * uart,int parity)287*9a747e4fSDavid du Colombier i8250parity(Uart* uart, int parity)
288*9a747e4fSDavid du Colombier {
289*9a747e4fSDavid du Colombier int lcr;
290*9a747e4fSDavid du Colombier Ctlr *ctlr;
291*9a747e4fSDavid du Colombier
292*9a747e4fSDavid du Colombier ctlr = uart->regs;
293*9a747e4fSDavid du Colombier lcr = ctlr->sticky[Lcr] & ~(Eps|Pen);
294*9a747e4fSDavid du Colombier
295*9a747e4fSDavid du Colombier switch(parity){
296*9a747e4fSDavid du Colombier case 'e':
297*9a747e4fSDavid du Colombier lcr |= Eps|Pen;
298*9a747e4fSDavid du Colombier break;
299*9a747e4fSDavid du Colombier case 'o':
300*9a747e4fSDavid du Colombier lcr |= Pen;
301*9a747e4fSDavid du Colombier break;
302*9a747e4fSDavid du Colombier case 'n':
303*9a747e4fSDavid du Colombier default:
304*9a747e4fSDavid du Colombier break;
305*9a747e4fSDavid du Colombier }
306*9a747e4fSDavid du Colombier ctlr->sticky[Lcr] = lcr;
307*9a747e4fSDavid du Colombier csr8w(ctlr, Lcr, 0);
308*9a747e4fSDavid du Colombier
309*9a747e4fSDavid du Colombier uart->parity = parity;
310*9a747e4fSDavid du Colombier
311*9a747e4fSDavid du Colombier return 0;
312*9a747e4fSDavid du Colombier }
313*9a747e4fSDavid du Colombier
314*9a747e4fSDavid du Colombier static int
i8250stop(Uart * uart,int stop)315*9a747e4fSDavid du Colombier i8250stop(Uart* uart, int stop)
316*9a747e4fSDavid du Colombier {
317*9a747e4fSDavid du Colombier int lcr;
318*9a747e4fSDavid du Colombier Ctlr *ctlr;
319*9a747e4fSDavid du Colombier
320*9a747e4fSDavid du Colombier ctlr = uart->regs;
321*9a747e4fSDavid du Colombier lcr = ctlr->sticky[Lcr] & ~Stb;
322*9a747e4fSDavid du Colombier
323*9a747e4fSDavid du Colombier switch(stop){
324*9a747e4fSDavid du Colombier case 1:
325*9a747e4fSDavid du Colombier break;
326*9a747e4fSDavid du Colombier case 2:
327*9a747e4fSDavid du Colombier lcr |= Stb;
328*9a747e4fSDavid du Colombier break;
329*9a747e4fSDavid du Colombier default:
330*9a747e4fSDavid du Colombier return -1;
331*9a747e4fSDavid du Colombier }
332*9a747e4fSDavid du Colombier ctlr->sticky[Lcr] = lcr;
333*9a747e4fSDavid du Colombier csr8w(ctlr, Lcr, 0);
334*9a747e4fSDavid du Colombier
335*9a747e4fSDavid du Colombier uart->stop = stop;
336*9a747e4fSDavid du Colombier
337*9a747e4fSDavid du Colombier return 0;
338*9a747e4fSDavid du Colombier }
339*9a747e4fSDavid du Colombier
340*9a747e4fSDavid du Colombier static int
i8250bits(Uart * uart,int bits)341*9a747e4fSDavid du Colombier i8250bits(Uart* uart, int bits)
342*9a747e4fSDavid du Colombier {
343*9a747e4fSDavid du Colombier int lcr;
344*9a747e4fSDavid du Colombier Ctlr *ctlr;
345*9a747e4fSDavid du Colombier
346*9a747e4fSDavid du Colombier ctlr = uart->regs;
347*9a747e4fSDavid du Colombier lcr = ctlr->sticky[Lcr] & ~WlsMASK;
348*9a747e4fSDavid du Colombier
349*9a747e4fSDavid du Colombier switch(bits){
350*9a747e4fSDavid du Colombier case 5:
351*9a747e4fSDavid du Colombier lcr |= Wls5;
352*9a747e4fSDavid du Colombier break;
353*9a747e4fSDavid du Colombier case 6:
354*9a747e4fSDavid du Colombier lcr |= Wls6;
355*9a747e4fSDavid du Colombier break;
356*9a747e4fSDavid du Colombier case 7:
357*9a747e4fSDavid du Colombier lcr |= Wls7;
358*9a747e4fSDavid du Colombier break;
359*9a747e4fSDavid du Colombier case 8:
360*9a747e4fSDavid du Colombier lcr |= Wls8;
361*9a747e4fSDavid du Colombier break;
362*9a747e4fSDavid du Colombier default:
363*9a747e4fSDavid du Colombier return -1;
364*9a747e4fSDavid du Colombier }
365*9a747e4fSDavid du Colombier ctlr->sticky[Lcr] = lcr;
366*9a747e4fSDavid du Colombier csr8w(ctlr, Lcr, 0);
367*9a747e4fSDavid du Colombier
368*9a747e4fSDavid du Colombier uart->bits = bits;
369*9a747e4fSDavid du Colombier
370*9a747e4fSDavid du Colombier return 0;
371*9a747e4fSDavid du Colombier }
372*9a747e4fSDavid du Colombier
373*9a747e4fSDavid du Colombier static int
i8250baud(Uart * uart,int baud)374*9a747e4fSDavid du Colombier i8250baud(Uart* uart, int baud)
375*9a747e4fSDavid du Colombier {
376*9a747e4fSDavid du Colombier ulong bgc;
377*9a747e4fSDavid du Colombier Ctlr *ctlr;
378*9a747e4fSDavid du Colombier
379*9a747e4fSDavid du Colombier /*
380*9a747e4fSDavid du Colombier * Set the Baud rate by calculating and setting the Baud rate
381*9a747e4fSDavid du Colombier * Generator Constant. This will work with fairly non-standard
382*9a747e4fSDavid du Colombier * Baud rates.
383*9a747e4fSDavid du Colombier */
384*9a747e4fSDavid du Colombier if(uart->freq == 0 || baud <= 0)
385*9a747e4fSDavid du Colombier return -1;
386*9a747e4fSDavid du Colombier bgc = (uart->freq+8*baud-1)/(16*baud);
387*9a747e4fSDavid du Colombier
388*9a747e4fSDavid du Colombier ctlr = uart->regs;
389*9a747e4fSDavid du Colombier csr8w(ctlr, Lcr, Dlab);
390*9a747e4fSDavid du Colombier outb(ctlr->io+Dlm, bgc>>8);
391*9a747e4fSDavid du Colombier outb(ctlr->io+Dll, bgc);
392*9a747e4fSDavid du Colombier csr8w(ctlr, Lcr, 0);
393*9a747e4fSDavid du Colombier
394*9a747e4fSDavid du Colombier uart->baud = baud;
395*9a747e4fSDavid du Colombier
396*9a747e4fSDavid du Colombier return 0;
397*9a747e4fSDavid du Colombier }
398*9a747e4fSDavid du Colombier
399*9a747e4fSDavid du Colombier static void
i8250break(Uart * uart,int ms)400*9a747e4fSDavid du Colombier i8250break(Uart* uart, int ms)
401*9a747e4fSDavid du Colombier {
402*9a747e4fSDavid du Colombier Ctlr *ctlr;
403*9a747e4fSDavid du Colombier
404*9a747e4fSDavid du Colombier /*
405*9a747e4fSDavid du Colombier * Send a break.
406*9a747e4fSDavid du Colombier */
407*9a747e4fSDavid du Colombier if(ms == 0)
408*9a747e4fSDavid du Colombier ms = 200;
409*9a747e4fSDavid du Colombier
410*9a747e4fSDavid du Colombier ctlr = uart->regs;
411*9a747e4fSDavid du Colombier csr8w(ctlr, Lcr, Brk);
412*9a747e4fSDavid du Colombier tsleep(&up->sleep, return0, 0, ms);
413*9a747e4fSDavid du Colombier csr8w(ctlr, Lcr, 0);
414*9a747e4fSDavid du Colombier }
415*9a747e4fSDavid du Colombier
416*9a747e4fSDavid du Colombier static void
i8250kick(Uart * uart)417*9a747e4fSDavid du Colombier i8250kick(Uart* uart)
418*9a747e4fSDavid du Colombier {
419*9a747e4fSDavid du Colombier int i;
420*9a747e4fSDavid du Colombier Ctlr *ctlr;
421*9a747e4fSDavid du Colombier
422*9a747e4fSDavid du Colombier if(uart->cts == 0 || uart->blocked)
423*9a747e4fSDavid du Colombier return;
424*9a747e4fSDavid du Colombier
425*9a747e4fSDavid du Colombier /*
426*9a747e4fSDavid du Colombier * 128 here is an arbitrary limit to make sure
427*9a747e4fSDavid du Colombier * we don't stay in this loop too long. If the
428*9a747e4fSDavid du Colombier * chip's output queue is longer than 128, too
429*9a747e4fSDavid du Colombier * bad -- presotto
430*9a747e4fSDavid du Colombier */
431*9a747e4fSDavid du Colombier ctlr = uart->regs;
432*9a747e4fSDavid du Colombier for(i = 0; i < 128; i++){
433*9a747e4fSDavid du Colombier if(!(csr8r(ctlr, Lsr) & Thre))
434*9a747e4fSDavid du Colombier break;
435*9a747e4fSDavid du Colombier if(uart->op >= uart->oe && uartstageoutput(uart) == 0)
436*9a747e4fSDavid du Colombier break;
437*9a747e4fSDavid du Colombier outb(ctlr->io+Thr, *(uart->op++));
438*9a747e4fSDavid du Colombier }
439*9a747e4fSDavid du Colombier }
440*9a747e4fSDavid du Colombier
441*9a747e4fSDavid du Colombier static void
i8250interrupt(Ureg *,void * arg)442*9a747e4fSDavid du Colombier i8250interrupt(Ureg*, void* arg)
443*9a747e4fSDavid du Colombier {
444*9a747e4fSDavid du Colombier Ctlr *ctlr;
445*9a747e4fSDavid du Colombier Uart *uart;
446*9a747e4fSDavid du Colombier int iir, lsr, old, r;
447*9a747e4fSDavid du Colombier
448*9a747e4fSDavid du Colombier uart = arg;
449*9a747e4fSDavid du Colombier
450*9a747e4fSDavid du Colombier ctlr = uart->regs;
451*9a747e4fSDavid du Colombier for(iir = csr8r(ctlr, Iir); !(iir & Ip); iir = csr8r(ctlr, Iir)){
452*9a747e4fSDavid du Colombier switch(iir & IirMASK){
453*9a747e4fSDavid du Colombier case Ims: /* Ms interrupt */
454*9a747e4fSDavid du Colombier r = csr8r(ctlr, Msr);
455*9a747e4fSDavid du Colombier if(r & Dcts){
456*9a747e4fSDavid du Colombier ilock(&uart->tlock);
457*9a747e4fSDavid du Colombier old = uart->cts;
458*9a747e4fSDavid du Colombier uart->cts = r & Cts;
459*9a747e4fSDavid du Colombier if(old == 0 && uart->cts)
460*9a747e4fSDavid du Colombier uart->ctsbackoff = 2;
461*9a747e4fSDavid du Colombier iunlock(&uart->tlock);
462*9a747e4fSDavid du Colombier }
463*9a747e4fSDavid du Colombier if(r & Ddsr){
464*9a747e4fSDavid du Colombier old = r & Dsr;
465*9a747e4fSDavid du Colombier if(uart->hup_dsr && uart->dsr && !old)
466*9a747e4fSDavid du Colombier uart->dohup = 1;
467*9a747e4fSDavid du Colombier uart->dsr = old;
468*9a747e4fSDavid du Colombier }
469*9a747e4fSDavid du Colombier if(r & Ddcd){
470*9a747e4fSDavid du Colombier old = r & Dcd;
471*9a747e4fSDavid du Colombier if(uart->hup_dcd && uart->dcd && !old)
472*9a747e4fSDavid du Colombier uart->dohup = 1;
473*9a747e4fSDavid du Colombier uart->dcd = old;
474*9a747e4fSDavid du Colombier }
475*9a747e4fSDavid du Colombier break;
476*9a747e4fSDavid du Colombier case Ithre: /* Thr Empty */
477*9a747e4fSDavid du Colombier uartkick(uart);
478*9a747e4fSDavid du Colombier break;
479*9a747e4fSDavid du Colombier case Irda: /* Received Data Available */
480*9a747e4fSDavid du Colombier case Ictoi: /* Character Time-out Indication */
481*9a747e4fSDavid du Colombier /*
482*9a747e4fSDavid du Colombier * Consume any received data.
483*9a747e4fSDavid du Colombier * If the received byte came in with a break,
484*9a747e4fSDavid du Colombier * parity or framing error, throw it away;
485*9a747e4fSDavid du Colombier * overrun is an indication that something has
486*9a747e4fSDavid du Colombier * already been tossed.
487*9a747e4fSDavid du Colombier */
488*9a747e4fSDavid du Colombier while((lsr = csr8r(ctlr, Lsr)) & Dr){
489*9a747e4fSDavid du Colombier if(lsr & Oe)
490*9a747e4fSDavid du Colombier uart->oerr++;
491*9a747e4fSDavid du Colombier if(lsr & Pe)
492*9a747e4fSDavid du Colombier uart->perr++;
493*9a747e4fSDavid du Colombier if(lsr & Fe)
494*9a747e4fSDavid du Colombier uart->ferr++;
495*9a747e4fSDavid du Colombier r = csr8r(ctlr, Rbr);
496*9a747e4fSDavid du Colombier if(!(lsr & (Bi|Fe|Pe)))
497*9a747e4fSDavid du Colombier uartrecv(uart, r);
498*9a747e4fSDavid du Colombier }
499*9a747e4fSDavid du Colombier break;
500*9a747e4fSDavid du Colombier default:
501*9a747e4fSDavid du Colombier iprint("weird uart interrupt 0x%2.2uX\n", iir);
502*9a747e4fSDavid du Colombier break;
503*9a747e4fSDavid du Colombier }
504*9a747e4fSDavid du Colombier }
505*9a747e4fSDavid du Colombier }
506*9a747e4fSDavid du Colombier
507*9a747e4fSDavid du Colombier static void
i8250disable(Uart * uart)508*9a747e4fSDavid du Colombier i8250disable(Uart* uart)
509*9a747e4fSDavid du Colombier {
510*9a747e4fSDavid du Colombier Ctlr *ctlr;
511*9a747e4fSDavid du Colombier
512*9a747e4fSDavid du Colombier /*
513*9a747e4fSDavid du Colombier * Turn off DTR and RTS, disable interrupts and fifos.
514*9a747e4fSDavid du Colombier */
515*9a747e4fSDavid du Colombier (*uart->phys->dtr)(uart, 0);
516*9a747e4fSDavid du Colombier (*uart->phys->rts)(uart, 0);
517*9a747e4fSDavid du Colombier (*uart->phys->fifo)(uart, 0);
518*9a747e4fSDavid du Colombier
519*9a747e4fSDavid du Colombier ctlr = uart->regs;
520*9a747e4fSDavid du Colombier ctlr->sticky[Ier] = 0;
521*9a747e4fSDavid du Colombier csr8w(ctlr, Ier, 0);
522*9a747e4fSDavid du Colombier }
523*9a747e4fSDavid du Colombier
524*9a747e4fSDavid du Colombier static void
i8250enable(Uart * uart,int ie)525*9a747e4fSDavid du Colombier i8250enable(Uart* uart, int ie)
526*9a747e4fSDavid du Colombier {
527*9a747e4fSDavid du Colombier Ctlr *ctlr;
528*9a747e4fSDavid du Colombier
529*9a747e4fSDavid du Colombier /*
530*9a747e4fSDavid du Colombier * Enable interrupts and turn on DTR and RTS.
531*9a747e4fSDavid du Colombier * Be careful if this is called to set up a polled serial line
532*9a747e4fSDavid du Colombier * early on not to try to enable interrupts as interrupt-
533*9a747e4fSDavid du Colombier * -enabling mechanisms might not be set up yet.
534*9a747e4fSDavid du Colombier */
535*9a747e4fSDavid du Colombier ctlr = uart->regs;
536*9a747e4fSDavid du Colombier if(ie){
537*9a747e4fSDavid du Colombier if(ctlr->iena == 0){
538*9a747e4fSDavid du Colombier intrenable(ctlr->irq, i8250interrupt, uart, ctlr->tbdf, uart->name);
539*9a747e4fSDavid du Colombier ctlr->iena = 1;
540*9a747e4fSDavid du Colombier }
541*9a747e4fSDavid du Colombier ctlr->sticky[Ier] = Ethre|Erda;
542*9a747e4fSDavid du Colombier ctlr->sticky[Mcr] |= Ie;
543*9a747e4fSDavid du Colombier }
544*9a747e4fSDavid du Colombier else{
545*9a747e4fSDavid du Colombier ctlr->sticky[Ier] = 0;
546*9a747e4fSDavid du Colombier ctlr->sticky[Mcr] = 0;
547*9a747e4fSDavid du Colombier }
548*9a747e4fSDavid du Colombier csr8w(ctlr, Ier, ctlr->sticky[Ier]);
549*9a747e4fSDavid du Colombier csr8w(ctlr, Mcr, ctlr->sticky[Mcr]);
550*9a747e4fSDavid du Colombier
551*9a747e4fSDavid du Colombier (*uart->phys->dtr)(uart, 1);
552*9a747e4fSDavid du Colombier (*uart->phys->rts)(uart, 1);
553*9a747e4fSDavid du Colombier }
554*9a747e4fSDavid du Colombier
555*9a747e4fSDavid du Colombier static Uart*
i8250pnp(void)556*9a747e4fSDavid du Colombier i8250pnp(void)
557*9a747e4fSDavid du Colombier {
558*9a747e4fSDavid du Colombier return i8250uart;
559*9a747e4fSDavid du Colombier }
560*9a747e4fSDavid du Colombier
561*9a747e4fSDavid du Colombier static int
i8250getc(Uart * uart)562*9a747e4fSDavid du Colombier i8250getc(Uart *uart)
563*9a747e4fSDavid du Colombier {
564*9a747e4fSDavid du Colombier Ctlr *ctlr;
565*9a747e4fSDavid du Colombier
566*9a747e4fSDavid du Colombier ctlr = uart->regs;
567*9a747e4fSDavid du Colombier while(!(csr8r(ctlr, Lsr)&Dr))
568*9a747e4fSDavid du Colombier delay(1);
569*9a747e4fSDavid du Colombier return csr8r(ctlr, Rbr);
570*9a747e4fSDavid du Colombier }
571*9a747e4fSDavid du Colombier
572*9a747e4fSDavid du Colombier static void
i8250putc(Uart * uart,int c)573*9a747e4fSDavid du Colombier i8250putc(Uart *uart, int c)
574*9a747e4fSDavid du Colombier {
575*9a747e4fSDavid du Colombier int i;
576*9a747e4fSDavid du Colombier Ctlr *ctlr;
577*9a747e4fSDavid du Colombier
578*9a747e4fSDavid du Colombier ctlr = uart->regs;
579*9a747e4fSDavid du Colombier for(i = 0; !(csr8r(ctlr, Lsr)&Thre) && i < 128; i++)
580*9a747e4fSDavid du Colombier delay(1);
581*9a747e4fSDavid du Colombier outb(ctlr->io+Thr, c);
582*9a747e4fSDavid du Colombier for(i = 0; !(csr8r(ctlr, Lsr)&Thre) && i < 128; i++)
583*9a747e4fSDavid du Colombier delay(1);
584*9a747e4fSDavid du Colombier }
585*9a747e4fSDavid du Colombier
586*9a747e4fSDavid du Colombier PhysUart i8250physuart = {
587*9a747e4fSDavid du Colombier .name = "i8250",
588*9a747e4fSDavid du Colombier .pnp = i8250pnp,
589*9a747e4fSDavid du Colombier .enable = i8250enable,
590*9a747e4fSDavid du Colombier .disable = i8250disable,
591*9a747e4fSDavid du Colombier .kick = i8250kick,
592*9a747e4fSDavid du Colombier .dobreak = i8250break,
593*9a747e4fSDavid du Colombier .baud = i8250baud,
594*9a747e4fSDavid du Colombier .bits = i8250bits,
595*9a747e4fSDavid du Colombier .stop = i8250stop,
596*9a747e4fSDavid du Colombier .parity = i8250parity,
597*9a747e4fSDavid du Colombier .modemctl = i8250modemctl,
598*9a747e4fSDavid du Colombier .rts = i8250rts,
599*9a747e4fSDavid du Colombier .dtr = i8250dtr,
600*9a747e4fSDavid du Colombier .status = i8250status,
601*9a747e4fSDavid du Colombier .fifo = i8250fifo,
602*9a747e4fSDavid du Colombier .getc = i8250getc,
603*9a747e4fSDavid du Colombier .putc = i8250putc,
604*9a747e4fSDavid du Colombier };
605*9a747e4fSDavid du Colombier
606*9a747e4fSDavid du Colombier void
i8250console(void)607*9a747e4fSDavid du Colombier i8250console(void)
608*9a747e4fSDavid du Colombier {
609*9a747e4fSDavid du Colombier Uart *uart;
610*9a747e4fSDavid du Colombier int n;
611*9a747e4fSDavid du Colombier char *cmd, *p;
612*9a747e4fSDavid du Colombier
613*9a747e4fSDavid du Colombier if((p = getconf("console")) == nil)
614*9a747e4fSDavid du Colombier return;
615*9a747e4fSDavid du Colombier n = strtoul(p, &cmd, 0);
616*9a747e4fSDavid du Colombier if(p == cmd)
617*9a747e4fSDavid du Colombier return;
618*9a747e4fSDavid du Colombier switch(n){
619*9a747e4fSDavid du Colombier default:
620*9a747e4fSDavid du Colombier return;
621*9a747e4fSDavid du Colombier case 0:
622*9a747e4fSDavid du Colombier uart = &i8250uart[0];
623*9a747e4fSDavid du Colombier break;
624*9a747e4fSDavid du Colombier case 1:
625*9a747e4fSDavid du Colombier uart = &i8250uart[1];
626*9a747e4fSDavid du Colombier break;
627*9a747e4fSDavid du Colombier }
628*9a747e4fSDavid du Colombier
629*9a747e4fSDavid du Colombier uartctl(uart, "b9600 l8 pn s1");
630*9a747e4fSDavid du Colombier if(*cmd != '\0')
631*9a747e4fSDavid du Colombier uartctl(uart, cmd);
632*9a747e4fSDavid du Colombier (*uart->phys->enable)(uart, 0);
633*9a747e4fSDavid du Colombier
634*9a747e4fSDavid du Colombier consuart = uart;
635*9a747e4fSDavid du Colombier uart->console = 1;
636*9a747e4fSDavid du Colombier }
637