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