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