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: releng/8.4/sys/dev/uart/uart_tty.c 218000 2011-01-28 00:22:03Z marcel $");
   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 static cn_probe_t uart_cnprobe;
   54 static cn_init_t uart_cninit;
   55 static cn_term_t uart_cnterm;
   56 static cn_getc_t uart_cngetc;
   57 static cn_putc_t uart_cnputc;
   58 
   59 CONSOLE_DRIVER(uart);
   60 
   61 static struct uart_devinfo uart_console;
   62 
   63 static void
   64 uart_cnprobe(struct consdev *cp)
   65 {
   66 
   67         cp->cn_pri = CN_DEAD;
   68 
   69         KASSERT(uart_console.cookie == NULL, ("foo"));
   70 
   71         if (uart_cpu_getdev(UART_DEV_CONSOLE, &uart_console))
   72                 return;
   73 
   74         if (uart_probe(&uart_console))
   75                 return;
   76 
   77         strlcpy(cp->cn_name, uart_driver_name, sizeof(cp->cn_name));
   78         cp->cn_pri = (boothowto & RB_SERIAL) ? CN_REMOTE : CN_NORMAL;
   79         cp->cn_arg = &uart_console;
   80 }
   81 
   82 static void
   83 uart_cninit(struct consdev *cp)
   84 {
   85         struct uart_devinfo *di;
   86 
   87         /*
   88          * Yedi trick: we need to be able to define cn_dev before we go
   89          * single- or multi-user. The problem is that we don't know at
   90          * this time what the device will be. Hence, we need to link from
   91          * the uart_devinfo to the consdev that corresponds to it so that
   92          * we can define cn_dev in uart_bus_attach() when we find the
   93          * device during bus enumeration. That's when we'll know what the
   94          * the unit number will be.
   95          */
   96         di = cp->cn_arg;
   97         KASSERT(di->cookie == NULL, ("foo"));
   98         di->cookie = cp;
   99         di->type = UART_DEV_CONSOLE;
  100         uart_add_sysdev(di);
  101         uart_init(di);
  102 }
  103 
  104 static void
  105 uart_cnterm(struct consdev *cp)
  106 {
  107 
  108         uart_term(cp->cn_arg);
  109 }
  110 
  111 static void
  112 uart_cnputc(struct consdev *cp, int c)
  113 {
  114 
  115         uart_putc(cp->cn_arg, c);
  116 }
  117 
  118 static int
  119 uart_cngetc(struct consdev *cp)
  120 {
  121 
  122         return (uart_poll(cp->cn_arg));
  123 }
  124 
  125 static int
  126 uart_tty_open(struct tty *tp)
  127 {
  128         struct uart_softc *sc;
  129 
  130         sc = tty_softc(tp);
  131 
  132         if (sc == NULL || sc->sc_leaving)
  133                 return (ENXIO);
  134 
  135         sc->sc_opened = 1;
  136         return (0);
  137 }
  138 
  139 static void
  140 uart_tty_close(struct tty *tp)
  141 {
  142         struct uart_softc *sc;
  143 
  144         sc = tty_softc(tp);
  145         if (sc == NULL || sc->sc_leaving || !sc->sc_opened) 
  146                 return;
  147 
  148         if (sc->sc_hwiflow)
  149                 UART_IOCTL(sc, UART_IOCTL_IFLOW, 0);
  150         if (sc->sc_hwoflow)
  151                 UART_IOCTL(sc, UART_IOCTL_OFLOW, 0);
  152         if (sc->sc_sysdev == NULL)
  153                 UART_SETSIG(sc, SER_DDTR | SER_DRTS);
  154 
  155         wakeup(sc);
  156         sc->sc_opened = 0;
  157         return;
  158 }
  159 
  160 static void
  161 uart_tty_outwakeup(struct tty *tp)
  162 {
  163         struct uart_softc *sc;
  164 
  165         sc = tty_softc(tp);
  166         if (sc == NULL || sc->sc_leaving)
  167                 return;
  168 
  169         if (sc->sc_txbusy)
  170                 return;
  171 
  172         /*
  173          * Respect RTS/CTS (output) flow control if enabled and not already
  174          * handled by hardware.
  175          */
  176         if ((tp->t_termios.c_cflag & CCTS_OFLOW) && !sc->sc_hwoflow &&
  177             !(sc->sc_hwsig & SER_CTS))
  178                 return;
  179 
  180         sc->sc_txdatasz = ttydisc_getc(tp, sc->sc_txbuf, sc->sc_txfifosz);
  181         if (sc->sc_txdatasz != 0)
  182                 UART_TRANSMIT(sc);
  183 }
  184 
  185 static void
  186 uart_tty_inwakeup(struct tty *tp)
  187 {
  188         struct uart_softc *sc;
  189 
  190         sc = tty_softc(tp);
  191         if (sc == NULL || sc->sc_leaving)
  192                 return;
  193 
  194         if (sc->sc_isquelch) {
  195                 if ((tp->t_termios.c_cflag & CRTS_IFLOW) && !sc->sc_hwiflow)
  196                         UART_SETSIG(sc, SER_DRTS|SER_RTS);
  197                 sc->sc_isquelch = 0;
  198                 uart_sched_softih(sc, SER_INT_RXREADY);
  199         }
  200 }
  201 
  202 static int
  203 uart_tty_ioctl(struct tty *tp, u_long cmd, caddr_t data, struct thread *td)
  204 {
  205         struct uart_softc *sc;
  206 
  207         sc = tty_softc(tp);
  208 
  209         switch (cmd) {
  210         case TIOCSBRK:
  211                 UART_IOCTL(sc, UART_IOCTL_BREAK, 1);
  212                 return (0);
  213         case TIOCCBRK:
  214                 UART_IOCTL(sc, UART_IOCTL_BREAK, 0);
  215                 return (0);
  216         default:
  217                 return pps_ioctl(cmd, data, &sc->sc_pps);
  218         }
  219 }
  220 
  221 static int
  222 uart_tty_param(struct tty *tp, struct termios *t)
  223 {
  224         struct uart_softc *sc;
  225         int databits, parity, stopbits;
  226 
  227         sc = tty_softc(tp);
  228         if (sc == NULL || sc->sc_leaving)
  229                 return (ENODEV);
  230         if (t->c_ispeed != t->c_ospeed && t->c_ospeed != 0)
  231                 return (EINVAL);
  232         /* Fixate certain parameters for system devices. */
  233         if (sc->sc_sysdev != NULL) {
  234                 t->c_ispeed = t->c_ospeed = sc->sc_sysdev->baudrate;
  235                 t->c_cflag |= CLOCAL;
  236                 t->c_cflag &= ~HUPCL;
  237         }
  238         if (t->c_ospeed == 0) {
  239                 UART_SETSIG(sc, SER_DDTR | SER_DRTS);
  240                 return (0);
  241         }
  242         switch (t->c_cflag & CSIZE) {
  243         case CS5:       databits = 5; break;
  244         case CS6:       databits = 6; break;
  245         case CS7:       databits = 7; break;
  246         default:        databits = 8; break;
  247         }
  248         stopbits = (t->c_cflag & CSTOPB) ? 2 : 1;
  249         if (t->c_cflag & PARENB)
  250                 parity = (t->c_cflag & PARODD) ? UART_PARITY_ODD
  251                     : UART_PARITY_EVEN;
  252         else
  253                 parity = UART_PARITY_NONE;
  254         if (UART_PARAM(sc, t->c_ospeed, databits, stopbits, parity) != 0)
  255                 return (EINVAL);
  256         UART_SETSIG(sc, SER_DDTR | SER_DTR);
  257         /* Set input flow control state. */
  258         if (!sc->sc_hwiflow) {
  259                 if ((t->c_cflag & CRTS_IFLOW) && sc->sc_isquelch)
  260                         UART_SETSIG(sc, SER_DRTS);
  261                 else
  262                         UART_SETSIG(sc, SER_DRTS | SER_RTS);
  263         } else
  264                 UART_IOCTL(sc, UART_IOCTL_IFLOW, (t->c_cflag & CRTS_IFLOW));
  265         /* Set output flow control state. */
  266         if (sc->sc_hwoflow)
  267                 UART_IOCTL(sc, UART_IOCTL_OFLOW, (t->c_cflag & CCTS_OFLOW));
  268 
  269         return (0);
  270 }
  271 
  272 static int
  273 uart_tty_modem(struct tty *tp, int biton, int bitoff)
  274 {
  275         struct uart_softc *sc;
  276 
  277         sc = tty_softc(tp);
  278         if (biton != 0 || bitoff != 0)
  279                 UART_SETSIG(sc, SER_DELTA(bitoff|biton) | biton);
  280         return (sc->sc_hwsig);
  281 }
  282 
  283 void
  284 uart_tty_intr(void *arg)
  285 {
  286         struct uart_softc *sc = arg;
  287         struct tty *tp;
  288         int c, err = 0, pend, sig, xc;
  289 
  290         if (sc->sc_leaving)
  291                 return;
  292 
  293         pend = atomic_readandclear_32(&sc->sc_ttypend);
  294         if (!(pend & SER_INT_MASK))
  295                 return;
  296 
  297         tp = sc->sc_u.u_tty.tp;
  298         tty_lock(tp);
  299 
  300         if (pend & SER_INT_RXREADY) {
  301                 while (!uart_rx_empty(sc) && !sc->sc_isquelch) {
  302                         xc = uart_rx_peek(sc);
  303                         c = xc & 0xff;
  304                         if (xc & UART_STAT_FRAMERR)
  305                                 err |= TRE_FRAMING;
  306                         if (xc & UART_STAT_OVERRUN)
  307                                 err |= TRE_OVERRUN;
  308                         if (xc & UART_STAT_PARERR)
  309                                 err |= TRE_PARITY;
  310                         if (ttydisc_rint(tp, c, err) != 0) {
  311                                 sc->sc_isquelch = 1;
  312                                 if ((tp->t_termios.c_cflag & CRTS_IFLOW) &&
  313                                     !sc->sc_hwiflow)
  314                                         UART_SETSIG(sc, SER_DRTS);
  315                         } else
  316                                 uart_rx_next(sc);
  317                 }
  318         }
  319 
  320         if (pend & SER_INT_BREAK)
  321                 ttydisc_rint(tp, 0, TRE_BREAK);
  322 
  323         if (pend & SER_INT_SIGCHG) {
  324                 sig = pend & SER_INT_SIGMASK;
  325                 if (sig & SER_DDCD)
  326                         ttydisc_modem(tp, sig & SER_DCD);
  327                 if (sig & SER_DCTS)
  328                         uart_tty_outwakeup(tp);
  329         }
  330 
  331         if (pend & SER_INT_TXIDLE)
  332                 uart_tty_outwakeup(tp);
  333         ttydisc_rint_done(tp);
  334         tty_unlock(tp);
  335 }
  336 
  337 static void
  338 uart_tty_free(void *arg)
  339 {
  340 
  341         /*
  342          * XXX: uart(4) could reuse the device unit number before it is
  343          * being freed by the TTY layer. We should use this hook to free
  344          * the device unit number, but unfortunately newbus does not
  345          * seem to support such a construct.
  346          */
  347 }
  348 
  349 static struct ttydevsw uart_tty_class = {
  350         .tsw_flags      = TF_INITLOCK|TF_CALLOUT,
  351         .tsw_open       = uart_tty_open,
  352         .tsw_close      = uart_tty_close,
  353         .tsw_outwakeup  = uart_tty_outwakeup,
  354         .tsw_inwakeup   = uart_tty_inwakeup,
  355         .tsw_ioctl      = uart_tty_ioctl,
  356         .tsw_param      = uart_tty_param,
  357         .tsw_modem      = uart_tty_modem,
  358         .tsw_free       = uart_tty_free,
  359 };
  360 
  361 int
  362 uart_tty_attach(struct uart_softc *sc)
  363 {
  364         struct tty *tp;
  365         int unit;
  366 
  367         sc->sc_u.u_tty.tp = tp = tty_alloc(&uart_tty_class, sc);
  368 
  369         unit = device_get_unit(sc->sc_dev);
  370 
  371         if (sc->sc_sysdev != NULL && sc->sc_sysdev->type == UART_DEV_CONSOLE) {
  372                 sprintf(((struct consdev *)sc->sc_sysdev->cookie)->cn_name,
  373                     "ttyu%r", unit);
  374                 tty_init_console(tp, 0);
  375         }
  376 
  377         swi_add(&tty_intr_event, uart_driver_name, uart_tty_intr, sc, SWI_TTY,
  378             INTR_TYPE_TTY, &sc->sc_softih);
  379 
  380         tty_makedev(tp, NULL, "u%r", unit);
  381 
  382         return (0);
  383 }
  384 
  385 int
  386 uart_tty_detach(struct uart_softc *sc)
  387 {
  388         struct tty *tp;
  389 
  390         tp = sc->sc_u.u_tty.tp;
  391 
  392         tty_lock(tp);
  393         swi_remove(sc->sc_softih);
  394         tty_rel_gone(tp);
  395 
  396         return (0);
  397 }

Cache object: 039c6b73c40db1099031420fe0ac5082


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