The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/mtx/uarti8250.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.