1*74a4d8c2SCharles.Forsyth #include "u.h"
2*74a4d8c2SCharles.Forsyth #include "lib.h"
3*74a4d8c2SCharles.Forsyth #include "mem.h"
4*74a4d8c2SCharles.Forsyth #include "dat.h"
5*74a4d8c2SCharles.Forsyth #include "fns.h"
6*74a4d8c2SCharles.Forsyth #include "io.h"
7*74a4d8c2SCharles.Forsyth
8*74a4d8c2SCharles.Forsyth /*
9*74a4d8c2SCharles.Forsyth * INS8250 uart
10*74a4d8c2SCharles.Forsyth */
11*74a4d8c2SCharles.Forsyth enum
12*74a4d8c2SCharles.Forsyth {
13*74a4d8c2SCharles.Forsyth /*
14*74a4d8c2SCharles.Forsyth * register numbers
15*74a4d8c2SCharles.Forsyth */
16*74a4d8c2SCharles.Forsyth Data= 0, /* xmit/rcv buffer */
17*74a4d8c2SCharles.Forsyth Iena= 1, /* interrupt enable */
18*74a4d8c2SCharles.Forsyth Ircv= (1<<0), /* for char rcv'd */
19*74a4d8c2SCharles.Forsyth Ixmt= (1<<1), /* for xmit buffer empty */
20*74a4d8c2SCharles.Forsyth Irstat=(1<<2), /* for change in rcv'er status */
21*74a4d8c2SCharles.Forsyth Imstat=(1<<3), /* for change in modem status */
22*74a4d8c2SCharles.Forsyth Istat= 2, /* interrupt flag (read) */
23*74a4d8c2SCharles.Forsyth Tctl= 2, /* test control (write) */
24*74a4d8c2SCharles.Forsyth Format= 3, /* byte format */
25*74a4d8c2SCharles.Forsyth Bits8= (3<<0), /* 8 bits/byte */
26*74a4d8c2SCharles.Forsyth Stop2= (1<<2), /* 2 stop bits */
27*74a4d8c2SCharles.Forsyth Pena= (1<<3), /* generate parity */
28*74a4d8c2SCharles.Forsyth Peven= (1<<4), /* even parity */
29*74a4d8c2SCharles.Forsyth Pforce=(1<<5), /* force parity */
30*74a4d8c2SCharles.Forsyth Break= (1<<6), /* generate a break */
31*74a4d8c2SCharles.Forsyth Dra= (1<<7), /* address the divisor */
32*74a4d8c2SCharles.Forsyth Mctl= 4, /* modem control */
33*74a4d8c2SCharles.Forsyth Dtr= (1<<0), /* data terminal ready */
34*74a4d8c2SCharles.Forsyth Rts= (1<<1), /* request to send */
35*74a4d8c2SCharles.Forsyth Ri= (1<<2), /* ring */
36*74a4d8c2SCharles.Forsyth Inton= (1<<3), /* turn on interrupts */
37*74a4d8c2SCharles.Forsyth Loop= (1<<4), /* loop back */
38*74a4d8c2SCharles.Forsyth Lstat= 5, /* line status */
39*74a4d8c2SCharles.Forsyth Inready=(1<<0), /* receive buffer full */
40*74a4d8c2SCharles.Forsyth Oerror=(1<<1), /* receiver overrun */
41*74a4d8c2SCharles.Forsyth Perror=(1<<2), /* receiver parity error */
42*74a4d8c2SCharles.Forsyth Ferror=(1<<3), /* rcv framing error */
43*74a4d8c2SCharles.Forsyth Outready=(1<<5), /* output buffer empty */
44*74a4d8c2SCharles.Forsyth Mstat= 6, /* modem status */
45*74a4d8c2SCharles.Forsyth Ctsc= (1<<0), /* clear to send changed */
46*74a4d8c2SCharles.Forsyth Dsrc= (1<<1), /* data set ready changed */
47*74a4d8c2SCharles.Forsyth Rire= (1<<2), /* rising edge of ring indicator */
48*74a4d8c2SCharles.Forsyth Dcdc= (1<<3), /* data carrier detect changed */
49*74a4d8c2SCharles.Forsyth Cts= (1<<4), /* complement of clear to send line */
50*74a4d8c2SCharles.Forsyth Dsr= (1<<5), /* complement of data set ready line */
51*74a4d8c2SCharles.Forsyth Ring= (1<<6), /* complement of ring indicator line */
52*74a4d8c2SCharles.Forsyth Dcd= (1<<7), /* complement of data carrier detect line */
53*74a4d8c2SCharles.Forsyth Scratch=7, /* scratchpad */
54*74a4d8c2SCharles.Forsyth Dlsb= 0, /* divisor lsb */
55*74a4d8c2SCharles.Forsyth Dmsb= 1, /* divisor msb */
56*74a4d8c2SCharles.Forsyth
57*74a4d8c2SCharles.Forsyth Serial= 0,
58*74a4d8c2SCharles.Forsyth Modem= 1,
59*74a4d8c2SCharles.Forsyth };
60*74a4d8c2SCharles.Forsyth
61*74a4d8c2SCharles.Forsyth typedef struct Uart Uart;
62*74a4d8c2SCharles.Forsyth struct Uart
63*74a4d8c2SCharles.Forsyth {
64*74a4d8c2SCharles.Forsyth int port;
65*74a4d8c2SCharles.Forsyth uchar sticky[8]; /* sticky write register values */
66*74a4d8c2SCharles.Forsyth uchar txbusy;
67*74a4d8c2SCharles.Forsyth
68*74a4d8c2SCharles.Forsyth void (*rx)(int); /* routine to take a received character */
69*74a4d8c2SCharles.Forsyth int (*tx)(void); /* routine to get a character to transmit */
70*74a4d8c2SCharles.Forsyth
71*74a4d8c2SCharles.Forsyth ulong frame;
72*74a4d8c2SCharles.Forsyth ulong overrun;
73*74a4d8c2SCharles.Forsyth };
74*74a4d8c2SCharles.Forsyth
75*74a4d8c2SCharles.Forsyth static Uart com[2];
76*74a4d8c2SCharles.Forsyth static Uart* uart;
77*74a4d8c2SCharles.Forsyth
78*74a4d8c2SCharles.Forsyth #define UartFREQ 1843200
79*74a4d8c2SCharles.Forsyth
80*74a4d8c2SCharles.Forsyth #define uartwrreg(u,r,v) outb((u)->port + r, (u)->sticky[r] | (v))
81*74a4d8c2SCharles.Forsyth #define uartrdreg(u,r) inb((u)->port + r)
82*74a4d8c2SCharles.Forsyth
83*74a4d8c2SCharles.Forsyth /*
84*74a4d8c2SCharles.Forsyth * set the baud rate by calculating and setting the baudrate
85*74a4d8c2SCharles.Forsyth * generator constant. This will work with fairly non-standard
86*74a4d8c2SCharles.Forsyth * baud rates.
87*74a4d8c2SCharles.Forsyth */
88*74a4d8c2SCharles.Forsyth static void
uartsetbaud(Uart * up,int rate)89*74a4d8c2SCharles.Forsyth uartsetbaud(Uart *up, int rate)
90*74a4d8c2SCharles.Forsyth {
91*74a4d8c2SCharles.Forsyth ulong brconst;
92*74a4d8c2SCharles.Forsyth
93*74a4d8c2SCharles.Forsyth brconst = (UartFREQ+8*rate-1)/(16*rate);
94*74a4d8c2SCharles.Forsyth
95*74a4d8c2SCharles.Forsyth uartwrreg(up, Format, Dra);
96*74a4d8c2SCharles.Forsyth outb(up->port+Dmsb, (brconst>>8) & 0xff);
97*74a4d8c2SCharles.Forsyth outb(up->port+Dlsb, brconst & 0xff);
98*74a4d8c2SCharles.Forsyth uartwrreg(up, Format, 0);
99*74a4d8c2SCharles.Forsyth }
100*74a4d8c2SCharles.Forsyth
101*74a4d8c2SCharles.Forsyth /*
102*74a4d8c2SCharles.Forsyth * toggle DTR
103*74a4d8c2SCharles.Forsyth */
104*74a4d8c2SCharles.Forsyth static void
uartdtr(Uart * up,int n)105*74a4d8c2SCharles.Forsyth uartdtr(Uart *up, int n)
106*74a4d8c2SCharles.Forsyth {
107*74a4d8c2SCharles.Forsyth if(n)
108*74a4d8c2SCharles.Forsyth up->sticky[Mctl] |= Dtr;
109*74a4d8c2SCharles.Forsyth else
110*74a4d8c2SCharles.Forsyth up->sticky[Mctl] &= ~Dtr;
111*74a4d8c2SCharles.Forsyth uartwrreg(up, Mctl, 0);
112*74a4d8c2SCharles.Forsyth }
113*74a4d8c2SCharles.Forsyth
114*74a4d8c2SCharles.Forsyth /*
115*74a4d8c2SCharles.Forsyth * toggle RTS
116*74a4d8c2SCharles.Forsyth */
117*74a4d8c2SCharles.Forsyth static void
uartrts(Uart * up,int n)118*74a4d8c2SCharles.Forsyth uartrts(Uart *up, int n)
119*74a4d8c2SCharles.Forsyth {
120*74a4d8c2SCharles.Forsyth if(n)
121*74a4d8c2SCharles.Forsyth up->sticky[Mctl] |= Rts;
122*74a4d8c2SCharles.Forsyth else
123*74a4d8c2SCharles.Forsyth up->sticky[Mctl] &= ~Rts;
124*74a4d8c2SCharles.Forsyth uartwrreg(up, Mctl, 0);
125*74a4d8c2SCharles.Forsyth }
126*74a4d8c2SCharles.Forsyth
127*74a4d8c2SCharles.Forsyth static void
uartintr(Ureg *,void * arg)128*74a4d8c2SCharles.Forsyth uartintr(Ureg*, void *arg)
129*74a4d8c2SCharles.Forsyth {
130*74a4d8c2SCharles.Forsyth Uart *up;
131*74a4d8c2SCharles.Forsyth int ch;
132*74a4d8c2SCharles.Forsyth int s, l, loops;
133*74a4d8c2SCharles.Forsyth
134*74a4d8c2SCharles.Forsyth up = arg;
135*74a4d8c2SCharles.Forsyth for(loops = 0; loops < 1024; loops++){
136*74a4d8c2SCharles.Forsyth s = uartrdreg(up, Istat);
137*74a4d8c2SCharles.Forsyth switch(s & 0x3F){
138*74a4d8c2SCharles.Forsyth case 6: /* receiver line status */
139*74a4d8c2SCharles.Forsyth l = uartrdreg(up, Lstat);
140*74a4d8c2SCharles.Forsyth if(l & Ferror)
141*74a4d8c2SCharles.Forsyth up->frame++;
142*74a4d8c2SCharles.Forsyth if(l & Oerror)
143*74a4d8c2SCharles.Forsyth up->overrun++;
144*74a4d8c2SCharles.Forsyth break;
145*74a4d8c2SCharles.Forsyth
146*74a4d8c2SCharles.Forsyth case 4: /* received data available */
147*74a4d8c2SCharles.Forsyth case 12:
148*74a4d8c2SCharles.Forsyth ch = inb(up->port+Data);
149*74a4d8c2SCharles.Forsyth if(up->rx)
150*74a4d8c2SCharles.Forsyth (*up->rx)(ch);
151*74a4d8c2SCharles.Forsyth break;
152*74a4d8c2SCharles.Forsyth
153*74a4d8c2SCharles.Forsyth case 2: /* transmitter empty */
154*74a4d8c2SCharles.Forsyth ch = -1;
155*74a4d8c2SCharles.Forsyth if(up->tx)
156*74a4d8c2SCharles.Forsyth ch = (*up->tx)();
157*74a4d8c2SCharles.Forsyth if(ch != -1)
158*74a4d8c2SCharles.Forsyth outb(up->port+Data, ch);
159*74a4d8c2SCharles.Forsyth else
160*74a4d8c2SCharles.Forsyth up->txbusy = 0;
161*74a4d8c2SCharles.Forsyth break;
162*74a4d8c2SCharles.Forsyth
163*74a4d8c2SCharles.Forsyth case 0: /* modem status */
164*74a4d8c2SCharles.Forsyth uartrdreg(up, Mstat);
165*74a4d8c2SCharles.Forsyth break;
166*74a4d8c2SCharles.Forsyth
167*74a4d8c2SCharles.Forsyth default:
168*74a4d8c2SCharles.Forsyth if(s&1)
169*74a4d8c2SCharles.Forsyth return;
170*74a4d8c2SCharles.Forsyth print("weird modem interrupt #%2.2ux\n", s);
171*74a4d8c2SCharles.Forsyth break;
172*74a4d8c2SCharles.Forsyth }
173*74a4d8c2SCharles.Forsyth }
174*74a4d8c2SCharles.Forsyth panic("uartintr: 0x%2.2ux\n", uartrdreg(up, Istat));
175*74a4d8c2SCharles.Forsyth }
176*74a4d8c2SCharles.Forsyth
177*74a4d8c2SCharles.Forsyth /*
178*74a4d8c2SCharles.Forsyth * turn on a port's interrupts. set DTR and RTS
179*74a4d8c2SCharles.Forsyth */
180*74a4d8c2SCharles.Forsyth static void
uartenable(Uart * up)181*74a4d8c2SCharles.Forsyth uartenable(Uart *up)
182*74a4d8c2SCharles.Forsyth {
183*74a4d8c2SCharles.Forsyth /*
184*74a4d8c2SCharles.Forsyth * turn on interrupts
185*74a4d8c2SCharles.Forsyth */
186*74a4d8c2SCharles.Forsyth up->sticky[Iena] = 0;
187*74a4d8c2SCharles.Forsyth if(up->tx)
188*74a4d8c2SCharles.Forsyth up->sticky[Iena] |= Ixmt;
189*74a4d8c2SCharles.Forsyth if(up->rx)
190*74a4d8c2SCharles.Forsyth up->sticky[Iena] |= Ircv|Irstat;
191*74a4d8c2SCharles.Forsyth uartwrreg(up, Iena, 0);
192*74a4d8c2SCharles.Forsyth
193*74a4d8c2SCharles.Forsyth /*
194*74a4d8c2SCharles.Forsyth * turn on DTR and RTS
195*74a4d8c2SCharles.Forsyth */
196*74a4d8c2SCharles.Forsyth uartdtr(up, 1);
197*74a4d8c2SCharles.Forsyth uartrts(up, 1);
198*74a4d8c2SCharles.Forsyth }
199*74a4d8c2SCharles.Forsyth
200*74a4d8c2SCharles.Forsyth static void
uartdisable(Uart * up)201*74a4d8c2SCharles.Forsyth uartdisable(Uart* up)
202*74a4d8c2SCharles.Forsyth {
203*74a4d8c2SCharles.Forsyth /*
204*74a4d8c2SCharles.Forsyth * Disable interrupts.
205*74a4d8c2SCharles.Forsyth */
206*74a4d8c2SCharles.Forsyth up->sticky[Iena] = 0;
207*74a4d8c2SCharles.Forsyth uartwrreg(up, Iena, 0);
208*74a4d8c2SCharles.Forsyth uartdtr(up, 0);
209*74a4d8c2SCharles.Forsyth uartrts(up, 0);
210*74a4d8c2SCharles.Forsyth }
211*74a4d8c2SCharles.Forsyth
212*74a4d8c2SCharles.Forsyth void
uartspecial(int port,void (* rx)(int),int (* tx)(void),int baud)213*74a4d8c2SCharles.Forsyth uartspecial(int port, void (*rx)(int), int (*tx)(void), int baud)
214*74a4d8c2SCharles.Forsyth {
215*74a4d8c2SCharles.Forsyth Uart *up;
216*74a4d8c2SCharles.Forsyth int vector;
217*74a4d8c2SCharles.Forsyth
218*74a4d8c2SCharles.Forsyth switch(port){
219*74a4d8c2SCharles.Forsyth case 0:
220*74a4d8c2SCharles.Forsyth port = 0x3F8;
221*74a4d8c2SCharles.Forsyth vector = VectorUART0;
222*74a4d8c2SCharles.Forsyth up = &com[0];
223*74a4d8c2SCharles.Forsyth break;
224*74a4d8c2SCharles.Forsyth case 1:
225*74a4d8c2SCharles.Forsyth port = 0x2F8;
226*74a4d8c2SCharles.Forsyth vector = VectorUART1;
227*74a4d8c2SCharles.Forsyth up = &com[1];
228*74a4d8c2SCharles.Forsyth break;
229*74a4d8c2SCharles.Forsyth default:
230*74a4d8c2SCharles.Forsyth return;
231*74a4d8c2SCharles.Forsyth }
232*74a4d8c2SCharles.Forsyth
233*74a4d8c2SCharles.Forsyth if(uart != nil && uart != up)
234*74a4d8c2SCharles.Forsyth uartdisable(uart);
235*74a4d8c2SCharles.Forsyth uart = up;
236*74a4d8c2SCharles.Forsyth
237*74a4d8c2SCharles.Forsyth if(up->port == 0){
238*74a4d8c2SCharles.Forsyth up->port = port;
239*74a4d8c2SCharles.Forsyth setvec(vector, uartintr, up);
240*74a4d8c2SCharles.Forsyth }
241*74a4d8c2SCharles.Forsyth
242*74a4d8c2SCharles.Forsyth /*
243*74a4d8c2SCharles.Forsyth * set rate to 9600 baud.
244*74a4d8c2SCharles.Forsyth * 8 bits/character.
245*74a4d8c2SCharles.Forsyth * 1 stop bit.
246*74a4d8c2SCharles.Forsyth * interrupts enabled.
247*74a4d8c2SCharles.Forsyth */
248*74a4d8c2SCharles.Forsyth uartsetbaud(up, 9600);
249*74a4d8c2SCharles.Forsyth up->sticky[Format] = Bits8;
250*74a4d8c2SCharles.Forsyth uartwrreg(up, Format, 0);
251*74a4d8c2SCharles.Forsyth up->sticky[Mctl] |= Inton;
252*74a4d8c2SCharles.Forsyth uartwrreg(up, Mctl, 0x0);
253*74a4d8c2SCharles.Forsyth
254*74a4d8c2SCharles.Forsyth up->rx = rx;
255*74a4d8c2SCharles.Forsyth up->tx = tx;
256*74a4d8c2SCharles.Forsyth uartenable(up);
257*74a4d8c2SCharles.Forsyth if(baud)
258*74a4d8c2SCharles.Forsyth uartsetbaud(up, baud);
259*74a4d8c2SCharles.Forsyth }
260*74a4d8c2SCharles.Forsyth
261*74a4d8c2SCharles.Forsyth void
uartputc(int c)262*74a4d8c2SCharles.Forsyth uartputc(int c)
263*74a4d8c2SCharles.Forsyth {
264*74a4d8c2SCharles.Forsyth int i;
265*74a4d8c2SCharles.Forsyth Uart *up;
266*74a4d8c2SCharles.Forsyth
267*74a4d8c2SCharles.Forsyth if((up = uart) == nil)
268*74a4d8c2SCharles.Forsyth return;
269*74a4d8c2SCharles.Forsyth for(i = 0; i < 100; i++){
270*74a4d8c2SCharles.Forsyth if(uartrdreg(up, Lstat) & Outready)
271*74a4d8c2SCharles.Forsyth break;
272*74a4d8c2SCharles.Forsyth delay(1);
273*74a4d8c2SCharles.Forsyth }
274*74a4d8c2SCharles.Forsyth outb(up->port+Data, c);
275*74a4d8c2SCharles.Forsyth }
276*74a4d8c2SCharles.Forsyth
277*74a4d8c2SCharles.Forsyth void
uartputs(IOQ * q,char * s,int n)278*74a4d8c2SCharles.Forsyth uartputs(IOQ *q, char *s, int n)
279*74a4d8c2SCharles.Forsyth {
280*74a4d8c2SCharles.Forsyth Uart *up;
281*74a4d8c2SCharles.Forsyth int c, x;
282*74a4d8c2SCharles.Forsyth
283*74a4d8c2SCharles.Forsyth if((up = uart) == nil)
284*74a4d8c2SCharles.Forsyth return;
285*74a4d8c2SCharles.Forsyth while(n--){
286*74a4d8c2SCharles.Forsyth if(*s == '\n')
287*74a4d8c2SCharles.Forsyth q->putc(q, '\r');
288*74a4d8c2SCharles.Forsyth q->putc(q, *s++);
289*74a4d8c2SCharles.Forsyth }
290*74a4d8c2SCharles.Forsyth x = splhi();
291*74a4d8c2SCharles.Forsyth if(up->txbusy == 0 && (c = q->getc(q)) != -1){
292*74a4d8c2SCharles.Forsyth uartputc(c & 0xFF);
293*74a4d8c2SCharles.Forsyth up->txbusy = 1;
294*74a4d8c2SCharles.Forsyth }
295*74a4d8c2SCharles.Forsyth splx(x);
296*74a4d8c2SCharles.Forsyth }
297*74a4d8c2SCharles.Forsyth
298*74a4d8c2SCharles.Forsyth void
uartdrain(void)299*74a4d8c2SCharles.Forsyth uartdrain(void)
300*74a4d8c2SCharles.Forsyth {
301*74a4d8c2SCharles.Forsyth Uart *up;
302*74a4d8c2SCharles.Forsyth int timeo;
303*74a4d8c2SCharles.Forsyth
304*74a4d8c2SCharles.Forsyth if((up = uart) == nil)
305*74a4d8c2SCharles.Forsyth return;
306*74a4d8c2SCharles.Forsyth for(timeo = 0; timeo < 10000 && up->txbusy; timeo++)
307*74a4d8c2SCharles.Forsyth delay(1);
308*74a4d8c2SCharles.Forsyth }
309