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