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