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/dev/uart/uart_tty.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 /*-
    2  * Copyright (c) 2003 Marcel Moolenaar
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  *
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   25  */
   26 
   27 #include <sys/cdefs.h>
   28 __FBSDID("$FreeBSD$");
   29 
   30 #include <sys/param.h>
   31 #include <sys/systm.h>
   32 #include <sys/bus.h>
   33 #include <sys/conf.h>
   34 #include <sys/cons.h>
   35 #include <sys/fcntl.h>
   36 #include <sys/interrupt.h>
   37 #include <sys/kernel.h>
   38 #include <sys/malloc.h>
   39 #include <sys/reboot.h>
   40 #include <machine/bus.h>
   41 #include <sys/rman.h>
   42 #include <sys/termios.h>
   43 #include <sys/tty.h>
   44 #include <machine/resource.h>
   45 #include <machine/stdarg.h>
   46 
   47 #include <dev/uart/uart.h>
   48 #include <dev/uart/uart_bus.h>
   49 #include <dev/uart/uart_cpu.h>
   50 
   51 #include "uart_if.h"
   52 
   53 #define UART_MINOR_CALLOUT      0x10000
   54 
   55 static cn_probe_t uart_cnprobe;
   56 static cn_init_t uart_cninit;
   57 static cn_term_t uart_cnterm;
   58 static cn_getc_t uart_cngetc;
   59 static cn_checkc_t uart_cncheckc;
   60 static cn_putc_t uart_cnputc;
   61 
   62 CONS_DRIVER(uart, uart_cnprobe, uart_cninit, uart_cnterm, uart_cngetc,
   63     uart_cncheckc, uart_cnputc, NULL);
   64 
   65 static d_open_t uart_tty_open;
   66 static d_close_t uart_tty_close;
   67 static d_ioctl_t uart_tty_ioctl;
   68 
   69 static struct cdevsw uart_cdevsw = {
   70         .d_version =    D_VERSION,
   71         .d_open =       uart_tty_open,
   72         .d_close =      uart_tty_close,
   73         .d_ioctl =      uart_tty_ioctl,
   74         .d_name =       uart_driver_name,
   75         .d_flags =      D_TTY | D_NEEDGIANT,
   76 };
   77 
   78 static struct uart_devinfo uart_console;
   79 
   80 static void
   81 uart_cnprobe(struct consdev *cp)
   82 {
   83 
   84         cp->cn_pri = CN_DEAD;
   85 
   86         KASSERT(uart_console.cookie == NULL, ("foo"));
   87 
   88         if (uart_cpu_getdev(UART_DEV_CONSOLE, &uart_console))
   89                 return;
   90 
   91         if (uart_probe(&uart_console))
   92                 return;
   93 
   94         strlcpy(cp->cn_name, uart_driver_name, sizeof(cp->cn_name));
   95         cp->cn_pri = (boothowto & RB_SERIAL) ? CN_REMOTE : CN_NORMAL;
   96         cp->cn_arg = &uart_console;
   97 }
   98 
   99 static void
  100 uart_cninit(struct consdev *cp)
  101 {
  102         struct uart_devinfo *di;
  103 
  104         /*
  105          * Yedi trick: we need to be able to define cn_dev before we go
  106          * single- or multi-user. The problem is that we don't know at
  107          * this time what the device will be. Hence, we need to link from
  108          * the uart_devinfo to the consdev that corresponds to it so that
  109          * we can define cn_dev in uart_bus_attach() when we find the
  110          * device during bus enumeration. That's when we'll know what the
  111          * the unit number will be.
  112          */
  113         di = cp->cn_arg;
  114         KASSERT(di->cookie == NULL, ("foo"));
  115         di->cookie = cp;
  116         di->type = UART_DEV_CONSOLE;
  117         uart_add_sysdev(di);
  118         uart_init(di);
  119 }
  120 
  121 static void
  122 uart_cnterm(struct consdev *cp)
  123 {
  124 
  125         uart_term(cp->cn_arg);
  126 }
  127 
  128 static void
  129 uart_cnputc(struct consdev *cp, int c)
  130 {
  131 
  132         uart_putc(cp->cn_arg, c);
  133 }
  134 
  135 static int
  136 uart_cncheckc(struct consdev *cp)
  137 {
  138 
  139         return (uart_poll(cp->cn_arg));
  140 }
  141 
  142 static int
  143 uart_cngetc(struct consdev *cp)
  144 {
  145 
  146         return (uart_getc(cp->cn_arg));
  147 }
  148 
  149 static void
  150 uart_tty_oproc(struct tty *tp)
  151 {
  152         struct uart_softc *sc;
  153 
  154         KASSERT(tp->t_dev != NULL, ("foo"));
  155         sc = tp->t_dev->si_drv1;
  156         if (sc == NULL || sc->sc_leaving)
  157                 return;
  158 
  159         /*
  160          * Handle input flow control. Note that if we have hardware support,
  161          * we don't do anything here. We continue to receive until our buffer
  162          * is full. At that time we cannot empty the UART itself and it will
  163          * de-assert RTS for us. In that situation we're completely stuffed.
  164          * Without hardware support, we need to toggle RTS ourselves.
  165          */
  166         if ((tp->t_cflag & CRTS_IFLOW) && !sc->sc_hwiflow) {
  167                 if ((tp->t_state & TS_TBLOCK) &&
  168                     (sc->sc_hwsig & SER_RTS))
  169                         UART_SETSIG(sc, SER_DRTS);
  170                 else if (!(tp->t_state & TS_TBLOCK) &&
  171                     !(sc->sc_hwsig & SER_RTS))
  172                         UART_SETSIG(sc, SER_DRTS|SER_RTS);
  173         }
  174 
  175         if (tp->t_state & TS_TTSTOP)
  176                 return;
  177 
  178         if ((tp->t_state & TS_BUSY) || sc->sc_txbusy)
  179                 return;
  180 
  181         if (tp->t_outq.c_cc == 0) {
  182                 ttwwakeup(tp);
  183                 return;
  184         }
  185 
  186         sc->sc_txdatasz = q_to_b(&tp->t_outq, sc->sc_txbuf, sc->sc_txfifosz);
  187         tp->t_state |= TS_BUSY;
  188         UART_TRANSMIT(sc);
  189         ttwwakeup(tp);
  190 }
  191 
  192 static int
  193 uart_tty_param(struct tty *tp, struct termios *t)
  194 {
  195         struct uart_softc *sc;
  196         int databits, parity, stopbits;
  197 
  198         KASSERT(tp->t_dev != NULL, ("foo"));
  199         sc = tp->t_dev->si_drv1;
  200         if (sc == NULL || sc->sc_leaving)
  201                 return (ENODEV);
  202         if (t->c_ispeed != t->c_ospeed && t->c_ospeed != 0)
  203                 return (EINVAL);
  204         /* Fixate certain parameters for system devices. */
  205         if (sc->sc_sysdev != NULL) {
  206                 t->c_ispeed = t->c_ospeed = sc->sc_sysdev->baudrate;
  207                 t->c_cflag |= CLOCAL;
  208                 t->c_cflag &= ~HUPCL;
  209         }
  210         if (t->c_ospeed == 0) {
  211                 UART_SETSIG(sc, SER_DDTR | SER_DRTS);
  212                 return (0);
  213         }
  214         switch (t->c_cflag & CSIZE) {
  215         case CS5:       databits = 5; break;
  216         case CS6:       databits = 6; break;
  217         case CS7:       databits = 7; break;
  218         default:        databits = 8; break;
  219         }
  220         stopbits = (t->c_cflag & CSTOPB) ? 2 : 1;
  221         if (t->c_cflag & PARENB)
  222                 parity = (t->c_cflag & PARODD) ? UART_PARITY_ODD
  223                     : UART_PARITY_EVEN;
  224         else
  225                 parity = UART_PARITY_NONE;
  226         if (UART_PARAM(sc, t->c_ospeed, databits, stopbits, parity) != 0)
  227                 return (EINVAL);
  228         UART_SETSIG(sc, SER_DDTR | SER_DTR);
  229         /* Set input flow control state. */
  230         if (!sc->sc_hwiflow) {
  231                 if ((t->c_cflag & CRTS_IFLOW) && (tp->t_state & TS_TBLOCK))
  232                         UART_SETSIG(sc, SER_DRTS);
  233                 else
  234                         UART_SETSIG(sc, SER_DRTS | SER_RTS);
  235         } else
  236                 UART_IOCTL(sc, UART_IOCTL_IFLOW, (t->c_cflag & CRTS_IFLOW));
  237         /* Set output flow control state. */
  238         if (sc->sc_hwoflow)
  239                 UART_IOCTL(sc, UART_IOCTL_OFLOW, (t->c_cflag & CCTS_OFLOW));
  240         ttsetwater(tp);
  241         return (0);
  242 }
  243 
  244 static int
  245 uart_tty_modem(struct tty *tp, int biton, int bitoff)
  246 {
  247         struct uart_softc *sc;
  248 
  249         sc = tp->t_dev->si_drv1;
  250         if (biton != 0 || bitoff != 0)
  251                 UART_SETSIG(sc, SER_DELTA(bitoff|biton) | biton);
  252         return (sc->sc_hwsig);
  253 }
  254 
  255 static void
  256 uart_tty_break(struct tty *tp, int state)
  257 {
  258         struct uart_softc *sc;
  259 
  260         sc = tp->t_dev->si_drv1;
  261         UART_IOCTL(sc, UART_IOCTL_BREAK, state);
  262 }
  263 
  264 static void
  265 uart_tty_stop(struct tty *tp, int rw)
  266 {
  267         struct uart_softc *sc;
  268 
  269         KASSERT(tp->t_dev != NULL, ("foo"));
  270         sc = tp->t_dev->si_drv1;
  271         if (sc == NULL || sc->sc_leaving)
  272                 return;
  273         if (rw & FWRITE) {
  274                 if (sc->sc_txbusy) {
  275                         sc->sc_txbusy = 0;
  276                         UART_FLUSH(sc, UART_FLUSH_TRANSMITTER);
  277                 }
  278                 tp->t_state &= ~TS_BUSY;
  279         }
  280         if (rw & FREAD) {
  281                 UART_FLUSH(sc, UART_FLUSH_RECEIVER);
  282                 sc->sc_rxget = sc->sc_rxput = 0;
  283         }
  284 }
  285 
  286 void
  287 uart_tty_intr(void *arg)
  288 {
  289         struct uart_softc *sc = arg;
  290         struct tty *tp;
  291         int c, pend, sig, xc;
  292 
  293         if (sc->sc_leaving)
  294                 return;
  295 
  296         pend = atomic_readandclear_32(&sc->sc_ttypend);
  297         if (!(pend & UART_IPEND_MASK))
  298                 return;
  299 
  300         tp = sc->sc_u.u_tty.tp;
  301 
  302         if (pend & UART_IPEND_RXREADY) {
  303                 while (!uart_rx_empty(sc) && !(tp->t_state & TS_TBLOCK)) {
  304                         xc = uart_rx_get(sc);
  305                         c = xc & 0xff;
  306                         if (xc & UART_STAT_FRAMERR)
  307                                 c |= TTY_FE;
  308                         if (xc & UART_STAT_PARERR)
  309                                 c |= TTY_PE;
  310                         ttyld_rint(tp, c);
  311                 }
  312         }
  313 
  314         if (pend & UART_IPEND_BREAK) {
  315                 if (tp != NULL && !(tp->t_iflag & IGNBRK))
  316                         ttyld_rint(tp, 0);
  317         }
  318 
  319         if (pend & UART_IPEND_SIGCHG) {
  320                 sig = pend & UART_IPEND_SIGMASK;
  321                 if (sig & SER_DDCD)
  322                         ttyld_modem(tp, sig & SER_DCD);
  323                 if ((sig & SER_DCTS) && (tp->t_cflag & CCTS_OFLOW) &&
  324                     !sc->sc_hwoflow) {
  325                         if (sig & SER_CTS) {
  326                                 tp->t_state &= ~TS_TTSTOP;
  327                                 ttyld_start(tp);
  328                         } else
  329                                 tp->t_state |= TS_TTSTOP;
  330                 }
  331         }
  332 
  333         if (pend & UART_IPEND_TXIDLE) {
  334                 tp->t_state &= ~TS_BUSY;
  335                 ttyld_start(tp);
  336         }
  337 }
  338 
  339 int
  340 uart_tty_attach(struct uart_softc *sc)
  341 {
  342         struct tty *tp;
  343 
  344         tp = ttymalloc(NULL);
  345         sc->sc_u.u_tty.tp = tp;
  346 
  347         sc->sc_u.u_tty.si[0] = make_dev(&uart_cdevsw,
  348             device_get_unit(sc->sc_dev), UID_ROOT, GID_WHEEL, 0600, "ttyu%r",
  349             device_get_unit(sc->sc_dev));
  350         sc->sc_u.u_tty.si[0]->si_drv1 = sc;
  351         sc->sc_u.u_tty.si[0]->si_tty = tp;
  352         sc->sc_u.u_tty.si[1] = make_dev(&uart_cdevsw,
  353             device_get_unit(sc->sc_dev) | UART_MINOR_CALLOUT, UID_UUCP,
  354             GID_DIALER, 0660, "uart%r", device_get_unit(sc->sc_dev));
  355         sc->sc_u.u_tty.si[1]->si_drv1 = sc;
  356         sc->sc_u.u_tty.si[1]->si_tty = tp;
  357 
  358         tp->t_oproc = uart_tty_oproc;
  359         tp->t_param = uart_tty_param;
  360         tp->t_stop = uart_tty_stop;
  361         tp->t_modem = uart_tty_modem;
  362         tp->t_break = uart_tty_break;
  363 
  364         if (sc->sc_sysdev != NULL && sc->sc_sysdev->type == UART_DEV_CONSOLE) {
  365                 sprintf(((struct consdev *)sc->sc_sysdev->cookie)->cn_name,
  366                     "ttyu%r", device_get_unit(sc->sc_dev));
  367         }
  368 
  369         swi_add(&tty_ithd, uart_driver_name, uart_tty_intr, sc, SWI_TTY,
  370             INTR_TYPE_TTY, &sc->sc_softih);
  371 
  372         return (0);
  373 }
  374 
  375 int uart_tty_detach(struct uart_softc *sc)
  376 {
  377 
  378         ithread_remove_handler(sc->sc_softih);
  379         destroy_dev(sc->sc_u.u_tty.si[0]);
  380         destroy_dev(sc->sc_u.u_tty.si[1]);
  381         /* ttyfree(sc->sc_u.u_tty.tp); */
  382 
  383         return (0);
  384 }
  385 
  386 static int
  387 uart_tty_open(struct cdev *dev, int flags, int mode, struct thread *td)
  388 {
  389         struct uart_softc *sc;
  390         struct tty *tp;
  391         int error;
  392 
  393  loop:
  394         sc = dev->si_drv1;
  395         if (sc == NULL || sc->sc_leaving)
  396                 return (ENODEV);
  397 
  398         tp = dev->si_tty;
  399 
  400         if (sc->sc_opened) {
  401                 KASSERT(tp->t_state & TS_ISOPEN, ("foo"));
  402                 /*
  403                  * The device is open, so everything has been initialized.
  404                  * Handle conflicts.
  405                  */
  406                 if (minor(dev) & UART_MINOR_CALLOUT) {
  407                         if (!sc->sc_callout)
  408                                 return (EBUSY);
  409                 } else {
  410                         if (sc->sc_callout) {
  411                                 if (flags & O_NONBLOCK)
  412                                         return (EBUSY);
  413                                 error = tsleep(sc, TTIPRI|PCATCH, "uartbi", 0);
  414                                 if (error)
  415                                         return (error);
  416                                 goto loop;
  417                         }
  418                 }
  419                 if (tp->t_state & TS_XCLUDE && suser(td) != 0)
  420                         return (EBUSY);
  421         } else {
  422                 KASSERT(!(tp->t_state & TS_ISOPEN), ("foo"));
  423                 /*
  424                  * The device isn't open, so there are no conflicts.
  425                  * Initialize it.  Initialization is done twice in many
  426                  * cases: to preempt sleeping callin opens if we are
  427                  * callout, and to complete a callin open after DCD rises.
  428                  */
  429                 sc->sc_callout = (minor(dev) & UART_MINOR_CALLOUT) ? 1 : 0;
  430                 tp->t_dev = dev;
  431 
  432                 tp->t_cflag = TTYDEF_CFLAG;
  433                 tp->t_iflag = TTYDEF_IFLAG;
  434                 tp->t_lflag = TTYDEF_LFLAG;
  435                 tp->t_oflag = TTYDEF_OFLAG;
  436                 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
  437                 ttychars(tp);
  438                 error = uart_tty_param(tp, &tp->t_termios);
  439                 if (error)
  440                         return (error);
  441                 /*
  442                  * Handle initial DCD.
  443                  */
  444                 if ((sc->sc_hwsig & SER_DCD) || sc->sc_callout)
  445                         ttyld_modem(tp, 1);
  446         }
  447         /*
  448          * Wait for DCD if necessary.
  449          */
  450         if (!(tp->t_state & TS_CARR_ON) && !sc->sc_callout &&
  451             !(tp->t_cflag & CLOCAL) && !(flags & O_NONBLOCK)) {
  452                 error = tsleep(TSA_CARR_ON(tp), TTIPRI|PCATCH, "uartdcd", 0);
  453                 if (error)
  454                         return (error);
  455                 goto loop;
  456         }
  457         error = tty_open(dev, tp);
  458         if (error)
  459                 return (error);
  460         error = ttyld_open(tp, dev);
  461         if (error)
  462                 return (error);
  463 
  464         KASSERT(tp->t_state & TS_ISOPEN, ("foo"));
  465         sc->sc_opened = 1;
  466         return (0);
  467 }
  468 
  469 static int
  470 uart_tty_close(struct cdev *dev, int flags, int mode, struct thread *td)
  471 {
  472         struct uart_softc *sc;
  473         struct tty *tp;
  474 
  475         sc = dev->si_drv1;
  476         if (sc == NULL || sc->sc_leaving)
  477                 return (ENODEV);
  478         tp = dev->si_tty;
  479         if (!sc->sc_opened) {
  480                 KASSERT(!(tp->t_state & TS_ISOPEN), ("foo"));
  481                 return (0);
  482         }
  483         KASSERT(tp->t_state & TS_ISOPEN, ("foo"));
  484 
  485         if (sc->sc_hwiflow)
  486                 UART_IOCTL(sc, UART_IOCTL_IFLOW, 0);
  487         if (sc->sc_hwoflow)
  488                 UART_IOCTL(sc, UART_IOCTL_OFLOW, 0);
  489         if (sc->sc_sysdev == NULL)
  490                 UART_SETSIG(sc, SER_DDTR | SER_DRTS);
  491 
  492         /* Disable pulse capturing. */
  493         sc->sc_pps.ppsparam.mode = 0;
  494 
  495         ttyld_close(tp, flags);
  496         tty_close(tp);
  497         wakeup(sc);
  498         wakeup(TSA_CARR_ON(tp));
  499         KASSERT(!(tp->t_state & TS_ISOPEN), ("foo"));
  500         sc->sc_opened = 0;
  501         return (0);
  502 }
  503 
  504 static int
  505 uart_tty_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags,
  506     struct thread *td)
  507 {
  508         struct uart_softc *sc;
  509         struct tty *tp;
  510         int error;
  511 
  512         sc = dev->si_drv1;
  513         if (sc == NULL || sc->sc_leaving)
  514                 return (ENODEV);
  515 
  516         tp = dev->si_tty;
  517         error = ttyioctl(dev, cmd, data, flags, td);
  518         if (error != ENOTTY)
  519                 return (error);
  520 
  521         error = pps_ioctl(cmd, data, &sc->sc_pps);
  522         if (error == ENODEV)
  523                 error = ENOTTY;
  524         return (error);
  525 }

Cache object: 2bd99da0a61576f8931fcad954325746


[ 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.