]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/uarti8250.c
remove non standard COM3 (eia2) serial port from i8250 uart.
[plan9front.git] / sys / src / 9 / pc / 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         Ifena           = 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     hasfifo;
118         int     checkfifo;
119         int     fena;
120 } Ctlr;
121
122 extern PhysUart i8250physuart;
123
124 static Ctlr i8250ctlr[2] = {
125 {       .io     = Uart0,
126         .irq    = Uart0IRQ,
127         .tbdf   = BUSUNKNOWN, },
128
129 {       .io     = Uart1,
130         .irq    = Uart1IRQ,
131         .tbdf   = BUSUNKNOWN, },
132 };
133
134 static Uart i8250uart[2] = {
135 {       .regs   = &i8250ctlr[0],
136         .name   = "COM1",
137         .freq   = UartFREQ,
138         .phys   = &i8250physuart,
139         .special= 0,
140         .next   = &i8250uart[1], },
141
142 {       .regs   = &i8250ctlr[1],
143         .name   = "COM2",
144         .freq   = UartFREQ,
145         .phys   = &i8250physuart,
146         .special= 0,
147         .next   = nil, },
148 };
149
150 #define csr8r(c, r)     inb((c)->io+(r))
151 #define csr8w(c, r, v)  outb((c)->io+(r), (c)->sticky[(r)]|(v))
152
153 static long
154 i8250status(Uart* uart, void* buf, long n, long offset)
155 {
156         char *p;
157         Ctlr *ctlr;
158         uchar ier, lcr, mcr, msr;
159
160         ctlr = uart->regs;
161         p = smalloc(READSTR);
162         mcr = ctlr->sticky[Mcr];
163         msr = csr8r(ctlr, Msr);
164         ier = ctlr->sticky[Ier];
165         lcr = ctlr->sticky[Lcr];
166         snprint(p, READSTR,
167                 "b%d c%d d%d e%d l%d m%d p%c r%d s%d i%d\n"
168                 "dev(%d) type(%d) framing(%d) overruns(%d) "
169                 "berr(%d) serr(%d)%s%s%s%s\n",
170
171                 uart->baud,
172                 uart->hup_dcd, 
173                 (msr & Dsr) != 0,
174                 uart->hup_dsr,
175                 (lcr & WlsMASK) + 5,
176                 (ier & Ems) != 0, 
177                 (lcr & Pen) ? ((lcr & Eps) ? 'e': 'o'): 'n',
178                 (mcr & Rts) != 0,
179                 (lcr & Stb) ? 2: 1,
180                 ctlr->fena,
181
182                 uart->dev,
183                 uart->type,
184                 uart->ferr,
185                 uart->oerr,
186                 uart->berr,
187                 uart->serr,
188                 (msr & Cts) ? " cts": "",
189                 (msr & Dsr) ? " dsr": "",
190                 (msr & Dcd) ? " dcd": "",
191                 (msr & Ri) ? " ring": ""
192         );
193         n = readstr(offset, buf, n, p);
194         free(p);
195
196         return n;
197 }
198
199 static void
200 i8250fifo(Uart* uart, int level)
201 {
202         Ctlr *ctlr;
203
204         ctlr = uart->regs;
205         if(ctlr->hasfifo == 0)
206                 return;
207
208         /*
209          * Changing the FIFOena bit in Fcr flushes data
210          * from both receive and transmit FIFOs; there's
211          * no easy way to guarantee not losing data on
212          * the receive side, but it's possible to wait until
213          * the transmitter is really empty.
214          */
215         ilock(ctlr);
216         while(!(csr8r(ctlr, Lsr) & Temt))
217                 ;
218
219         /*
220          * Set the trigger level, default is the max.
221          * value.
222          * Some UARTs require FIFOena to be set before
223          * other bits can take effect, so set it twice.
224          */
225         ctlr->fena = level;
226         switch(level){
227         case 0:
228                 break;
229         case 1:
230                 level = FIFO1|FIFOena;
231                 break;
232         case 4:
233                 level = FIFO4|FIFOena;
234                 break;
235         case 8:
236                 level = FIFO8|FIFOena;
237                 break;
238         default:
239                 level = FIFO14|FIFOena;
240                 break;
241         }
242         csr8w(ctlr, Fcr, level);
243         csr8w(ctlr, Fcr, level);
244         iunlock(ctlr);
245 }
246
247 static void
248 i8250dtr(Uart* uart, int on)
249 {
250         Ctlr *ctlr;
251
252         /*
253          * Toggle DTR.
254          */
255         ctlr = uart->regs;
256         if(on)
257                 ctlr->sticky[Mcr] |= Dtr;
258         else
259                 ctlr->sticky[Mcr] &= ~Dtr;
260         csr8w(ctlr, Mcr, 0);
261 }
262
263 static void
264 i8250rts(Uart* uart, int on)
265 {
266         Ctlr *ctlr;
267
268         /*
269          * Toggle RTS.
270          */
271         ctlr = uart->regs;
272         if(on)
273                 ctlr->sticky[Mcr] |= Rts;
274         else
275                 ctlr->sticky[Mcr] &= ~Rts;
276         csr8w(ctlr, Mcr, 0);
277 }
278
279 static void
280 i8250modemctl(Uart* uart, int on)
281 {
282         Ctlr *ctlr;
283
284         ctlr = uart->regs;
285         ilock(&uart->tlock);
286         if(on){
287                 ctlr->sticky[Ier] |= Ems;
288                 csr8w(ctlr, Ier, ctlr->sticky[Ier]);
289                 uart->modem = 1;
290                 uart->cts = csr8r(ctlr, Msr) & Cts;
291         }
292         else{
293                 ctlr->sticky[Ier] &= ~Ems;
294                 csr8w(ctlr, Ier, ctlr->sticky[Ier]);
295                 uart->modem = 0;
296                 uart->cts = 1;
297         }
298         iunlock(&uart->tlock);
299
300         /* modem needs fifo */
301         (*uart->phys->fifo)(uart, on);
302 }
303
304 static int
305 i8250parity(Uart* uart, int parity)
306 {
307         int lcr;
308         Ctlr *ctlr;
309
310         ctlr = uart->regs;
311         lcr = ctlr->sticky[Lcr] & ~(Eps|Pen);
312
313         switch(parity){
314         case 'e':
315                 lcr |= Eps|Pen;
316                 break;
317         case 'o':
318                 lcr |= Pen;
319                 break;
320         case 'n':
321                 break;
322         default:
323                 return -1;
324         }
325         ctlr->sticky[Lcr] = lcr;
326         csr8w(ctlr, Lcr, 0);
327
328         uart->parity = parity;
329
330         return 0;
331 }
332
333 static int
334 i8250stop(Uart* uart, int stop)
335 {
336         int lcr;
337         Ctlr *ctlr;
338
339         ctlr = uart->regs;
340         lcr = ctlr->sticky[Lcr] & ~Stb;
341
342         switch(stop){
343         case 1:
344                 break;
345         case 2:
346                 lcr |= Stb;
347                 break;
348         default:
349                 return -1;
350         }
351         ctlr->sticky[Lcr] = lcr;
352         csr8w(ctlr, Lcr, 0);
353
354         uart->stop = stop;
355
356         return 0;
357 }
358
359 static int
360 i8250bits(Uart* uart, int bits)
361 {
362         int lcr;
363         Ctlr *ctlr;
364
365         ctlr = uart->regs;
366         lcr = ctlr->sticky[Lcr] & ~WlsMASK;
367
368         switch(bits){
369         case 5:
370                 lcr |= Wls5;
371                 break;
372         case 6:
373                 lcr |= Wls6;
374                 break;
375         case 7:
376                 lcr |= Wls7;
377                 break;
378         case 8:
379                 lcr |= Wls8;
380                 break;
381         default:
382                 return -1;
383         }
384         ctlr->sticky[Lcr] = lcr;
385         csr8w(ctlr, Lcr, 0);
386
387         uart->bits = bits;
388
389         return 0;
390 }
391
392 static int
393 i8250baud(Uart* uart, int baud)
394 {
395         ulong bgc;
396         Ctlr *ctlr;
397
398         /*
399          * Set the Baud rate by calculating and setting the Baud rate
400          * Generator Constant. This will work with fairly non-standard
401          * Baud rates.
402          */
403         if(uart->freq == 0 || baud <= 0)
404                 return -1;
405         bgc = (uart->freq+8*baud-1)/(16*baud);
406
407         ctlr = uart->regs;
408         csr8w(ctlr, Lcr, Dlab);
409         outb(ctlr->io+Dlm, bgc>>8);
410         outb(ctlr->io+Dll, bgc);
411         csr8w(ctlr, Lcr, 0);
412
413         uart->baud = baud;
414
415         return 0;
416 }
417
418 static void
419 i8250break(Uart* uart, int ms)
420 {
421         Ctlr *ctlr;
422
423         /*
424          * Send a break.
425          */
426         if(ms <= 0)
427                 ms = 200;
428
429         ctlr = uart->regs;
430         csr8w(ctlr, Lcr, Brk);
431         tsleep(&up->sleep, return0, 0, ms);
432         csr8w(ctlr, Lcr, 0);
433 }
434
435 static void
436 i8250kick(Uart* uart)
437 {
438         int i;
439         Ctlr *ctlr;
440
441         if(uart->cts == 0 || uart->blocked)
442                 return;
443
444         /*
445          *  128 here is an arbitrary limit to make sure
446          *  we don't stay in this loop too long.  If the
447          *  chip's output queue is longer than 128, too
448          *  bad -- presotto
449          */
450         ctlr = uart->regs;
451         for(i = 0; i < 128; i++){
452                 if(!(csr8r(ctlr, Lsr) & Thre))
453                         break;
454                 if(uart->op >= uart->oe && uartstageoutput(uart) == 0)
455                         break;
456                 outb(ctlr->io+Thr, *(uart->op++));
457         }
458 }
459
460 static void
461 i8250interrupt(Ureg*, void* arg)
462 {
463         Ctlr *ctlr;
464         Uart *uart;
465         int iir, lsr, old, r;
466
467         uart = arg;
468
469         ctlr = uart->regs;
470         for(iir = csr8r(ctlr, Iir); !(iir & Ip); iir = csr8r(ctlr, Iir)){
471                 switch(iir & IirMASK){
472                 case Ims:               /* Ms interrupt */
473                         r = csr8r(ctlr, Msr);
474                         if(r & Dcts){
475                                 ilock(&uart->tlock);
476                                 old = uart->cts;
477                                 uart->cts = r & Cts;
478                                 if(old == 0 && uart->cts)
479                                         uart->ctsbackoff = 2;
480                                 iunlock(&uart->tlock);
481                         }
482                         if(r & Ddsr){
483                                 old = r & Dsr;
484                                 if(uart->hup_dsr && uart->dsr && !old)
485                                         uart->dohup = 1;
486                                 uart->dsr = old;
487                         }
488                         if(r & Ddcd){
489                                 old = r & Dcd;
490                                 if(uart->hup_dcd && uart->dcd && !old)
491                                         uart->dohup = 1;
492                                 uart->dcd = old;
493                         }
494                         break;
495                 case Ithre:             /* Thr Empty */
496                         uartkick(uart);
497                         break;
498                 case Irda:              /* Received Data Available */
499                 case Irls:              /* Receiver Line Status */
500                 case Ictoi:             /* Character Time-out Indication */
501                         /*
502                          * Consume any received data.
503                          * If the received byte came in with a break,
504                          * parity or framing error, throw it away;
505                          * overrun is an indication that something has
506                          * already been tossed.
507                          */
508                         while((lsr = csr8r(ctlr, Lsr)) & Dr){
509                                 if(lsr & (FIFOerr|Oe))
510                                         uart->oerr++;
511                                 if(lsr & Pe)
512                                         uart->perr++;
513                                 if(lsr & Fe)
514                                         uart->ferr++;
515                                 r = csr8r(ctlr, Rbr);
516                                 if(!(lsr & (Bi|Fe|Pe)))
517                                         uartrecv(uart, r);
518                         }
519                         break;
520
521                 default:
522                         iprint("weird uart interrupt 0x%2.2uX\n", iir);
523                         break;
524                 }
525         }
526 }
527
528 static void
529 i8250disable(Uart* uart)
530 {
531         Ctlr *ctlr;
532
533         /*
534          * Turn off DTR and RTS, disable interrupts and fifos.
535          */
536         (*uart->phys->dtr)(uart, 0);
537         (*uart->phys->rts)(uart, 0);
538         (*uart->phys->fifo)(uart, 0);
539
540         ctlr = uart->regs;
541         ctlr->sticky[Ier] = 0;
542         csr8w(ctlr, Ier, ctlr->sticky[Ier]);
543
544         if(ctlr->iena != 0){
545                 if(intrdisable(ctlr->irq, i8250interrupt, uart, ctlr->tbdf, uart->name) == 0)
546                         ctlr->iena = 0;
547         }
548 }
549
550 static void
551 i8250enable(Uart* uart, int ie)
552 {
553         Ctlr *ctlr;
554
555         ctlr = uart->regs;
556
557         /*
558          * Check if there is a FIFO.
559          * Changing the FIFOena bit in Fcr flushes data
560          * from both receive and transmit FIFOs; there's
561          * no easy way to guarantee not losing data on
562          * the receive side, but it's possible to wait until
563          * the transmitter is really empty.
564          * Also, reading the Iir outwith i8250interrupt()
565          * can be dangerous, but this should only happen
566          * once before interrupts are enabled.
567          */
568         ilock(ctlr);
569         if(!ctlr->checkfifo){
570                 /*
571                  * Wait until the transmitter is really empty.
572                  */
573                 while(!(csr8r(ctlr, Lsr) & Temt))
574                         ;
575                 csr8w(ctlr, Fcr, FIFOena);
576                 if(csr8r(ctlr, Iir) & Ifena)
577                         ctlr->hasfifo = 1;
578                 csr8w(ctlr, Fcr, 0);
579                 ctlr->checkfifo = 1;
580         }
581         iunlock(ctlr);
582
583         /*
584          * Enable interrupts and turn on DTR and RTS.
585          * Be careful if this is called to set up a polled serial line
586          * early on not to try to enable interrupts as interrupt-
587          * -enabling mechanisms might not be set up yet.
588          */
589         if(ie){
590                 if(ctlr->iena == 0){
591                         intrenable(ctlr->irq, i8250interrupt, uart, ctlr->tbdf, uart->name);
592                         ctlr->iena = 1;
593                 }
594                 ctlr->sticky[Ier] = Ethre|Erda;
595                 ctlr->sticky[Mcr] |= Ie;
596         }
597         else{
598                 ctlr->sticky[Ier] = 0;
599                 ctlr->sticky[Mcr] = 0;
600         }
601         csr8w(ctlr, Ier, ctlr->sticky[Ier]);
602         csr8w(ctlr, Mcr, ctlr->sticky[Mcr]);
603
604         (*uart->phys->dtr)(uart, 1);
605         (*uart->phys->rts)(uart, 1);
606
607         /*
608          * During startup, the i8259 interrupt controller is reset.
609          * This may result in a lost interrupt from the i8250 uart.
610          * The i8250 thinks the interrupt is still outstanding and does not
611          * generate any further interrupts. The workaround is to call the
612          * interrupt handler to clear any pending interrupt events.
613          * Note: this must be done after setting Ier.
614          */
615         if(ie)
616                 i8250interrupt(nil, uart);
617 }
618
619 void*
620 i8250alloc(int io, int irq, int tbdf)
621 {
622         Ctlr *ctlr;
623
624         if((ctlr = malloc(sizeof(Ctlr))) != nil){
625                 ctlr->io = io;
626                 ctlr->irq = irq;
627                 ctlr->tbdf = tbdf;
628         }
629
630         return ctlr;
631 }
632
633 static Uart*
634 i8250pnp(void)
635 {
636         return i8250uart;
637 }
638
639 static int
640 i8250getc(Uart *uart)
641 {
642         Ctlr *ctlr;
643
644         ctlr = uart->regs;
645         while(!(csr8r(ctlr, Lsr)&Dr))
646                 delay(1);
647         return csr8r(ctlr, Rbr);
648 }
649
650 static void
651 i8250putc(Uart *uart, int c)
652 {
653         int i;
654         Ctlr *ctlr;
655
656         ctlr = uart->regs;
657         for(i = 0; !(csr8r(ctlr, Lsr)&Thre) && i < 128; i++)
658                 delay(1);
659         outb(ctlr->io+Thr, c);
660         for(i = 0; !(csr8r(ctlr, Lsr)&Thre) && i < 128; i++)
661                 delay(1);
662 }
663
664 PhysUart i8250physuart = {
665         .name           = "i8250",
666         .pnp            = i8250pnp,
667         .enable         = i8250enable,
668         .disable        = i8250disable,
669         .kick           = i8250kick,
670         .dobreak        = i8250break,
671         .baud           = i8250baud,
672         .bits           = i8250bits,
673         .stop           = i8250stop,
674         .parity         = i8250parity,
675         .modemctl       = i8250modemctl,
676         .rts            = i8250rts,
677         .dtr            = i8250dtr,
678         .status         = i8250status,
679         .fifo           = i8250fifo,
680         .getc           = i8250getc,
681         .putc           = i8250putc,
682 };
683
684 void
685 i8250console(void)
686 {
687         Uart *uart;
688         int n;
689         char *cmd, *p;
690
691         if((p = getconf("console")) == nil)
692                 return;
693         n = strtoul(p, &cmd, 0);
694         if(p == cmd || n < 0 || n >= nelem(i8250uart))
695                 return;
696         uart = &i8250uart[n];
697
698         (*uart->phys->enable)(uart, 0);
699         uartctl(uart, "b9600 l8 pn s1");
700         if(*cmd != '\0')
701                 uartctl(uart, cmd);
702
703         consuart = uart;
704         uart->console = 1;
705 }