|
|
1.1 root 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: Uart uart[1];
76:
77: #define UartFREQ 1843200
78:
79: #define uartwrreg(u,r,v) outb((u)->port + r, (u)->sticky[r] | (v))
80: #define uartrdreg(u,r) inb((u)->port + r)
81:
82: /*
83: * set the baud rate by calculating and setting the baudrate
84: * generator constant. This will work with fairly non-standard
85: * baud rates.
86: */
87: static void
88: uartsetbaud(Uart *up, int rate)
89: {
90: ulong brconst;
91:
92: brconst = (UartFREQ+8*rate-1)/(16*rate);
93:
94: uartwrreg(up, Format, Dra);
95: outb(up->port+Dmsb, (brconst>>8) & 0xff);
96: outb(up->port+Dlsb, brconst & 0xff);
97: uartwrreg(up, Format, 0);
98: }
99:
100: /*
101: * toggle DTR
102: */
103: static void
104: uartdtr(Uart *up, int n)
105: {
106: if(n)
107: up->sticky[Mctl] |= Dtr;
108: else
109: up->sticky[Mctl] &= ~Dtr;
110: uartwrreg(up, Mctl, 0);
111: }
112:
113: /*
114: * toggle RTS
115: */
116: static void
117: uartrts(Uart *up, int n)
118: {
119: if(n)
120: up->sticky[Mctl] |= Rts;
121: else
122: up->sticky[Mctl] &= ~Rts;
123: uartwrreg(up, Mctl, 0);
124: }
125:
126: static void
127: uartintr(Ureg*, void *arg)
128: {
129: Uart *up;
130: int ch;
131: int s, l, loops;
132:
133: up = arg;
134: for(loops = 0; loops < 1024; loops++){
135: s = uartrdreg(up, Istat);
136: switch(s){
137: case 6: /* receiver line status */
138: l = uartrdreg(up, Lstat);
139: if(l & Ferror)
140: up->frame++;
141: if(l & Oerror)
142: up->overrun++;
143: break;
144:
145: case 4: /* received data available */
146: case 12:
147: ch = inb(up->port+Data);
148: if(up->rx)
149: (*up->rx)(ch);
150: break;
151:
152: case 2: /* transmitter empty */
153: ch = -1;
154: if(up->tx)
155: ch = (*up->tx)();
156: if(ch != -1)
157: outb(up->port+Data, ch);
158: else
159: up->txbusy = 0;
160: break;
161:
162: case 0: /* modem status */
163: uartrdreg(up, Mstat);
164: break;
165:
166: default:
167: if(s&1)
168: return;
169: print("weird modem interrupt #%2.2ux\n", s);
170: break;
171: }
172: }
173: panic("uartintr: 0x%2.2ux\n", uartrdreg(up, Istat));
174: }
175:
176: /*
177: * turn on a port's interrupts. set DTR and RTS
178: */
179: static void
180: uartenable(Uart *up)
181: {
182: /*
183: * turn on interrupts
184: */
185: up->sticky[Iena] = 0;
186: if(up->tx)
187: up->sticky[Iena] |= Ixmt;
188: if(up->rx)
189: up->sticky[Iena] |= Ircv|Irstat;
190: uartwrreg(up, Iena, 0);
191:
192: /*
193: * turn on DTR and RTS
194: */
195: uartdtr(up, 1);
196: uartrts(up, 1);
197: }
198:
199: void
200: uartspecial(int port, void (*rx)(int), int (*tx)(void), int baud)
201: {
202: Uart *up = &uart[0];
203:
204: if(up->port)
205: return;
206:
207: switch(port){
208:
209: case 0:
210: up->port = 0x3F8;
211: setvec(Uart0vec, uartintr, up);
212: break;
213:
214: case 1:
215: up->port = 0x2F8;
216: setvec(Uart1vec, uartintr, up);
217: break;
218:
219: default:
220: return;
221: }
222:
223: /*
224: * set rate to 9600 baud.
225: * 8 bits/character.
226: * 1 stop bit.
227: * interrupts enabled.
228: */
229: uartsetbaud(up, 9600);
230: up->sticky[Format] = Bits8;
231: uartwrreg(up, Format, 0);
232: up->sticky[Mctl] |= Inton;
233: uartwrreg(up, Mctl, 0x0);
234:
235: up->rx = rx;
236: up->tx = tx;
237: uartenable(up);
238: if(baud)
239: uartsetbaud(up, baud);
240: }
241:
242: static void
243: uartputc(int c)
244: {
245: Uart *up = &uart[0];
246: int i;
247:
248: for(i = 0; i < 100; i++){
249: if(uartrdreg(up, Lstat) & Outready)
250: break;
251: delay(1);
252: }
253: outb(up->port+Data, c);
254: }
255:
256: void
257: uartputs(IOQ *q, char *s, int n)
258: {
259: Uart *up = &uart[0];
260: int c, x;
261:
262: while(n--){
263: if(*s == '\n')
264: q->putc(q, '\r');
265: q->putc(q, *s++);
266: }
267: x = splhi();
268: if(up->txbusy == 0 && (c = q->getc(q)) != -1){
269: uartputc(c & 0xFF);
270: up->txbusy = 1;
271: }
272: splx(x);
273: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.