1098ca2bdSWarner Losh /*- 2718cf2ccSPedro F. Giffuni * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3718cf2ccSPedro F. Giffuni * 427d5dc18SMarcel Moolenaar * Copyright (c) 2003 Marcel Moolenaar 527d5dc18SMarcel Moolenaar * All rights reserved. 627d5dc18SMarcel Moolenaar * 727d5dc18SMarcel Moolenaar * Redistribution and use in source and binary forms, with or without 827d5dc18SMarcel Moolenaar * modification, are permitted provided that the following conditions 927d5dc18SMarcel Moolenaar * are met: 1027d5dc18SMarcel Moolenaar * 1127d5dc18SMarcel Moolenaar * 1. Redistributions of source code must retain the above copyright 1227d5dc18SMarcel Moolenaar * notice, this list of conditions and the following disclaimer. 1327d5dc18SMarcel Moolenaar * 2. Redistributions in binary form must reproduce the above copyright 1427d5dc18SMarcel Moolenaar * notice, this list of conditions and the following disclaimer in the 1527d5dc18SMarcel Moolenaar * documentation and/or other materials provided with the distribution. 1627d5dc18SMarcel Moolenaar * 1727d5dc18SMarcel Moolenaar * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1827d5dc18SMarcel Moolenaar * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1927d5dc18SMarcel Moolenaar * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2027d5dc18SMarcel Moolenaar * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2127d5dc18SMarcel Moolenaar * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2227d5dc18SMarcel Moolenaar * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2327d5dc18SMarcel Moolenaar * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2427d5dc18SMarcel Moolenaar * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2527d5dc18SMarcel Moolenaar * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2627d5dc18SMarcel Moolenaar * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2727d5dc18SMarcel Moolenaar */ 2827d5dc18SMarcel Moolenaar 2927d5dc18SMarcel Moolenaar #include <sys/cdefs.h> 3027d5dc18SMarcel Moolenaar __FBSDID("$FreeBSD$"); 3127d5dc18SMarcel Moolenaar 3227d5dc18SMarcel Moolenaar #include <sys/param.h> 3327d5dc18SMarcel Moolenaar #include <sys/systm.h> 3427d5dc18SMarcel Moolenaar #include <sys/bus.h> 3527d5dc18SMarcel Moolenaar #include <sys/conf.h> 3627d5dc18SMarcel Moolenaar #include <sys/cons.h> 3727d5dc18SMarcel Moolenaar #include <sys/fcntl.h> 3827d5dc18SMarcel Moolenaar #include <sys/interrupt.h> 3927d5dc18SMarcel Moolenaar #include <sys/kernel.h> 4027d5dc18SMarcel Moolenaar #include <sys/malloc.h> 4127d5dc18SMarcel Moolenaar #include <sys/reboot.h> 4227d5dc18SMarcel Moolenaar #include <machine/bus.h> 4327d5dc18SMarcel Moolenaar #include <sys/rman.h> 4427d5dc18SMarcel Moolenaar #include <sys/tty.h> 4527d5dc18SMarcel Moolenaar #include <machine/resource.h> 4627d5dc18SMarcel Moolenaar #include <machine/stdarg.h> 4727d5dc18SMarcel Moolenaar 4827d5dc18SMarcel Moolenaar #include <dev/uart/uart.h> 4927d5dc18SMarcel Moolenaar #include <dev/uart/uart_bus.h> 5027d5dc18SMarcel Moolenaar #include <dev/uart/uart_cpu.h> 5127d5dc18SMarcel Moolenaar 5227d5dc18SMarcel Moolenaar #include "uart_if.h" 5327d5dc18SMarcel Moolenaar 5427d5dc18SMarcel Moolenaar static cn_probe_t uart_cnprobe; 5527d5dc18SMarcel Moolenaar static cn_init_t uart_cninit; 56*ec6faf94SAndriy Gapon static cn_init_t uart_cnresume; 5727d5dc18SMarcel Moolenaar static cn_term_t uart_cnterm; 5827d5dc18SMarcel Moolenaar static cn_getc_t uart_cngetc; 5927d5dc18SMarcel Moolenaar static cn_putc_t uart_cnputc; 609976156fSAndriy Gapon static cn_grab_t uart_cngrab; 619976156fSAndriy Gapon static cn_ungrab_t uart_cnungrab; 6227d5dc18SMarcel Moolenaar 6357169ceaSMarius Strobl static tsw_open_t uart_tty_open; 6457169ceaSMarius Strobl static tsw_close_t uart_tty_close; 6557169ceaSMarius Strobl static tsw_outwakeup_t uart_tty_outwakeup; 6657169ceaSMarius Strobl static tsw_inwakeup_t uart_tty_inwakeup; 6757169ceaSMarius Strobl static tsw_ioctl_t uart_tty_ioctl; 6857169ceaSMarius Strobl static tsw_param_t uart_tty_param; 6957169ceaSMarius Strobl static tsw_modem_t uart_tty_modem; 7057169ceaSMarius Strobl static tsw_free_t uart_tty_free; 7157169ceaSMarius Strobl static tsw_busy_t uart_tty_busy; 7257169ceaSMarius Strobl 73*ec6faf94SAndriy Gapon CONSOLE_DRIVER( 74*ec6faf94SAndriy Gapon uart, 75*ec6faf94SAndriy Gapon .cn_resume = uart_cnresume, 76*ec6faf94SAndriy Gapon ); 7727d5dc18SMarcel Moolenaar 7827d5dc18SMarcel Moolenaar static struct uart_devinfo uart_console; 7927d5dc18SMarcel Moolenaar 8027d5dc18SMarcel Moolenaar static void 8127d5dc18SMarcel Moolenaar uart_cnprobe(struct consdev *cp) 8227d5dc18SMarcel Moolenaar { 8327d5dc18SMarcel Moolenaar 8427d5dc18SMarcel Moolenaar cp->cn_pri = CN_DEAD; 8527d5dc18SMarcel Moolenaar 8627d5dc18SMarcel Moolenaar KASSERT(uart_console.cookie == NULL, ("foo")); 8727d5dc18SMarcel Moolenaar 8827d5dc18SMarcel Moolenaar if (uart_cpu_getdev(UART_DEV_CONSOLE, &uart_console)) 8927d5dc18SMarcel Moolenaar return; 9027d5dc18SMarcel Moolenaar 9127d5dc18SMarcel Moolenaar if (uart_probe(&uart_console)) 9227d5dc18SMarcel Moolenaar return; 9327d5dc18SMarcel Moolenaar 949f0974f9SMarcel Moolenaar strlcpy(cp->cn_name, uart_driver_name, sizeof(cp->cn_name)); 9527d5dc18SMarcel Moolenaar cp->cn_pri = (boothowto & RB_SERIAL) ? CN_REMOTE : CN_NORMAL; 9627d5dc18SMarcel Moolenaar cp->cn_arg = &uart_console; 9727d5dc18SMarcel Moolenaar } 9827d5dc18SMarcel Moolenaar 9927d5dc18SMarcel Moolenaar static void 10027d5dc18SMarcel Moolenaar uart_cninit(struct consdev *cp) 10127d5dc18SMarcel Moolenaar { 10227d5dc18SMarcel Moolenaar struct uart_devinfo *di; 10327d5dc18SMarcel Moolenaar 10427d5dc18SMarcel Moolenaar /* 10527d5dc18SMarcel Moolenaar * Yedi trick: we need to be able to define cn_dev before we go 10627d5dc18SMarcel Moolenaar * single- or multi-user. The problem is that we don't know at 10727d5dc18SMarcel Moolenaar * this time what the device will be. Hence, we need to link from 10827d5dc18SMarcel Moolenaar * the uart_devinfo to the consdev that corresponds to it so that 10927d5dc18SMarcel Moolenaar * we can define cn_dev in uart_bus_attach() when we find the 11027d5dc18SMarcel Moolenaar * device during bus enumeration. That's when we'll know what the 11127d5dc18SMarcel Moolenaar * the unit number will be. 11227d5dc18SMarcel Moolenaar */ 11327d5dc18SMarcel Moolenaar di = cp->cn_arg; 11427d5dc18SMarcel Moolenaar KASSERT(di->cookie == NULL, ("foo")); 11527d5dc18SMarcel Moolenaar di->cookie = cp; 11627d5dc18SMarcel Moolenaar di->type = UART_DEV_CONSOLE; 11727d5dc18SMarcel Moolenaar uart_add_sysdev(di); 11827d5dc18SMarcel Moolenaar uart_init(di); 11927d5dc18SMarcel Moolenaar } 12027d5dc18SMarcel Moolenaar 12127d5dc18SMarcel Moolenaar static void 122*ec6faf94SAndriy Gapon uart_cnresume(struct consdev *cp) 123*ec6faf94SAndriy Gapon { 124*ec6faf94SAndriy Gapon 125*ec6faf94SAndriy Gapon uart_init(cp->cn_arg); 126*ec6faf94SAndriy Gapon } 127*ec6faf94SAndriy Gapon 128*ec6faf94SAndriy Gapon static void 12927d5dc18SMarcel Moolenaar uart_cnterm(struct consdev *cp) 13027d5dc18SMarcel Moolenaar { 13127d5dc18SMarcel Moolenaar 13227d5dc18SMarcel Moolenaar uart_term(cp->cn_arg); 13327d5dc18SMarcel Moolenaar } 13427d5dc18SMarcel Moolenaar 13527d5dc18SMarcel Moolenaar static void 1369976156fSAndriy Gapon uart_cngrab(struct consdev *cp) 1379976156fSAndriy Gapon { 138f83ed22cSWarner Losh 139f83ed22cSWarner Losh uart_grab(cp->cn_arg); 1409976156fSAndriy Gapon } 1419976156fSAndriy Gapon 1429976156fSAndriy Gapon static void 1439976156fSAndriy Gapon uart_cnungrab(struct consdev *cp) 1449976156fSAndriy Gapon { 145f83ed22cSWarner Losh 146f83ed22cSWarner Losh uart_ungrab(cp->cn_arg); 1479976156fSAndriy Gapon } 1489976156fSAndriy Gapon 1499976156fSAndriy Gapon static void 15027d5dc18SMarcel Moolenaar uart_cnputc(struct consdev *cp, int c) 15127d5dc18SMarcel Moolenaar { 15227d5dc18SMarcel Moolenaar 15327d5dc18SMarcel Moolenaar uart_putc(cp->cn_arg, c); 15427d5dc18SMarcel Moolenaar } 15527d5dc18SMarcel Moolenaar 15627d5dc18SMarcel Moolenaar static int 15727d5dc18SMarcel Moolenaar uart_cngetc(struct consdev *cp) 15827d5dc18SMarcel Moolenaar { 15927d5dc18SMarcel Moolenaar 1607672c959SPoul-Henning Kamp return (uart_poll(cp->cn_arg)); 16127d5dc18SMarcel Moolenaar } 16227d5dc18SMarcel Moolenaar 16379a8d927SPoul-Henning Kamp static int 164bc093719SEd Schouten uart_tty_open(struct tty *tp) 16579a8d927SPoul-Henning Kamp { 16679a8d927SPoul-Henning Kamp struct uart_softc *sc; 16779a8d927SPoul-Henning Kamp 168bc093719SEd Schouten sc = tty_softc(tp); 169793bcd17SMarcel Moolenaar 170793bcd17SMarcel Moolenaar if (sc == NULL || sc->sc_leaving) 171793bcd17SMarcel Moolenaar return (ENXIO); 172793bcd17SMarcel Moolenaar 17379a8d927SPoul-Henning Kamp sc->sc_opened = 1; 17479a8d927SPoul-Henning Kamp return (0); 17579a8d927SPoul-Henning Kamp } 17679a8d927SPoul-Henning Kamp 17779a8d927SPoul-Henning Kamp static void 17879a8d927SPoul-Henning Kamp uart_tty_close(struct tty *tp) 17979a8d927SPoul-Henning Kamp { 18079a8d927SPoul-Henning Kamp struct uart_softc *sc; 18179a8d927SPoul-Henning Kamp 182bc093719SEd Schouten sc = tty_softc(tp); 183fbbec42fSPoul-Henning Kamp if (sc == NULL || sc->sc_leaving || !sc->sc_opened) 18479a8d927SPoul-Henning Kamp return; 18579a8d927SPoul-Henning Kamp 18679a8d927SPoul-Henning Kamp if (sc->sc_hwiflow) 18779a8d927SPoul-Henning Kamp UART_IOCTL(sc, UART_IOCTL_IFLOW, 0); 18879a8d927SPoul-Henning Kamp if (sc->sc_hwoflow) 18979a8d927SPoul-Henning Kamp UART_IOCTL(sc, UART_IOCTL_OFLOW, 0); 19079a8d927SPoul-Henning Kamp if (sc->sc_sysdev == NULL) 19179a8d927SPoul-Henning Kamp UART_SETSIG(sc, SER_DDTR | SER_DRTS); 19279a8d927SPoul-Henning Kamp 19379a8d927SPoul-Henning Kamp wakeup(sc); 19479a8d927SPoul-Henning Kamp sc->sc_opened = 0; 19579a8d927SPoul-Henning Kamp } 19679a8d927SPoul-Henning Kamp 19727d5dc18SMarcel Moolenaar static void 198bc093719SEd Schouten uart_tty_outwakeup(struct tty *tp) 19927d5dc18SMarcel Moolenaar { 20027d5dc18SMarcel Moolenaar struct uart_softc *sc; 20127d5dc18SMarcel Moolenaar 202bc093719SEd Schouten sc = tty_softc(tp); 20327d5dc18SMarcel Moolenaar if (sc == NULL || sc->sc_leaving) 20427d5dc18SMarcel Moolenaar return; 20527d5dc18SMarcel Moolenaar 206bc093719SEd Schouten if (sc->sc_txbusy) 20727d5dc18SMarcel Moolenaar return; 20827d5dc18SMarcel Moolenaar 209f1fb9647SMarcel Moolenaar /* 210f1fb9647SMarcel Moolenaar * Respect RTS/CTS (output) flow control if enabled and not already 211f1fb9647SMarcel Moolenaar * handled by hardware. 212f1fb9647SMarcel Moolenaar */ 213f1fb9647SMarcel Moolenaar if ((tp->t_termios.c_cflag & CCTS_OFLOW) && !sc->sc_hwoflow && 214f1fb9647SMarcel Moolenaar !(sc->sc_hwsig & SER_CTS)) 215f1fb9647SMarcel Moolenaar return; 216f1fb9647SMarcel Moolenaar 217bc093719SEd Schouten sc->sc_txdatasz = ttydisc_getc(tp, sc->sc_txbuf, sc->sc_txfifosz); 218bc093719SEd Schouten if (sc->sc_txdatasz != 0) 219bc093719SEd Schouten UART_TRANSMIT(sc); 22027d5dc18SMarcel Moolenaar } 22127d5dc18SMarcel Moolenaar 2220acb3c4aSMarcel Moolenaar static void 2230acb3c4aSMarcel Moolenaar uart_tty_inwakeup(struct tty *tp) 2240acb3c4aSMarcel Moolenaar { 2250acb3c4aSMarcel Moolenaar struct uart_softc *sc; 2260acb3c4aSMarcel Moolenaar 2270acb3c4aSMarcel Moolenaar sc = tty_softc(tp); 2280acb3c4aSMarcel Moolenaar if (sc == NULL || sc->sc_leaving) 2290acb3c4aSMarcel Moolenaar return; 2300acb3c4aSMarcel Moolenaar 2310acb3c4aSMarcel Moolenaar if (sc->sc_isquelch) { 2320acb3c4aSMarcel Moolenaar if ((tp->t_termios.c_cflag & CRTS_IFLOW) && !sc->sc_hwiflow) 2330acb3c4aSMarcel Moolenaar UART_SETSIG(sc, SER_DRTS|SER_RTS); 2340acb3c4aSMarcel Moolenaar sc->sc_isquelch = 0; 2350acb3c4aSMarcel Moolenaar uart_sched_softih(sc, SER_INT_RXREADY); 2360acb3c4aSMarcel Moolenaar } 2370acb3c4aSMarcel Moolenaar } 2380acb3c4aSMarcel Moolenaar 239bc093719SEd Schouten static int 24057169ceaSMarius Strobl uart_tty_ioctl(struct tty *tp, u_long cmd, caddr_t data, 24157169ceaSMarius Strobl struct thread *td __unused) 242bc093719SEd Schouten { 243bc093719SEd Schouten struct uart_softc *sc; 244bc093719SEd Schouten 245bc093719SEd Schouten sc = tty_softc(tp); 246bc093719SEd Schouten 247bc093719SEd Schouten switch (cmd) { 248bc093719SEd Schouten case TIOCSBRK: 249bc093719SEd Schouten UART_IOCTL(sc, UART_IOCTL_BREAK, 1); 250bc093719SEd Schouten return (0); 251bc093719SEd Schouten case TIOCCBRK: 252bc093719SEd Schouten UART_IOCTL(sc, UART_IOCTL_BREAK, 0); 253bc093719SEd Schouten return (0); 254bc093719SEd Schouten default: 255bc093719SEd Schouten return pps_ioctl(cmd, data, &sc->sc_pps); 256bc093719SEd Schouten } 25727d5dc18SMarcel Moolenaar } 25827d5dc18SMarcel Moolenaar 25927d5dc18SMarcel Moolenaar static int 26027d5dc18SMarcel Moolenaar uart_tty_param(struct tty *tp, struct termios *t) 26127d5dc18SMarcel Moolenaar { 26227d5dc18SMarcel Moolenaar struct uart_softc *sc; 26327d5dc18SMarcel Moolenaar int databits, parity, stopbits; 26427d5dc18SMarcel Moolenaar 265bc093719SEd Schouten sc = tty_softc(tp); 26627d5dc18SMarcel Moolenaar if (sc == NULL || sc->sc_leaving) 26727d5dc18SMarcel Moolenaar return (ENODEV); 26827d5dc18SMarcel Moolenaar if (t->c_ispeed != t->c_ospeed && t->c_ospeed != 0) 26927d5dc18SMarcel Moolenaar return (EINVAL); 27027d5dc18SMarcel Moolenaar if (t->c_ospeed == 0) { 27128710806SPoul-Henning Kamp UART_SETSIG(sc, SER_DDTR | SER_DRTS); 27227d5dc18SMarcel Moolenaar return (0); 27327d5dc18SMarcel Moolenaar } 27427d5dc18SMarcel Moolenaar switch (t->c_cflag & CSIZE) { 27527d5dc18SMarcel Moolenaar case CS5: databits = 5; break; 27627d5dc18SMarcel Moolenaar case CS6: databits = 6; break; 27727d5dc18SMarcel Moolenaar case CS7: databits = 7; break; 27827d5dc18SMarcel Moolenaar default: databits = 8; break; 27927d5dc18SMarcel Moolenaar } 28027d5dc18SMarcel Moolenaar stopbits = (t->c_cflag & CSTOPB) ? 2 : 1; 28127d5dc18SMarcel Moolenaar if (t->c_cflag & PARENB) 28257169ceaSMarius Strobl parity = (t->c_cflag & PARODD) ? UART_PARITY_ODD : 28357169ceaSMarius Strobl UART_PARITY_EVEN; 28427d5dc18SMarcel Moolenaar else 28527d5dc18SMarcel Moolenaar parity = UART_PARITY_NONE; 286b662bdc2SMarcel Moolenaar if (UART_PARAM(sc, t->c_ospeed, databits, stopbits, parity) != 0) 287b662bdc2SMarcel Moolenaar return (EINVAL); 28828710806SPoul-Henning Kamp UART_SETSIG(sc, SER_DDTR | SER_DTR); 28927d5dc18SMarcel Moolenaar /* Set input flow control state. */ 29027d5dc18SMarcel Moolenaar if (!sc->sc_hwiflow) { 2910acb3c4aSMarcel Moolenaar if ((t->c_cflag & CRTS_IFLOW) && sc->sc_isquelch) 29228710806SPoul-Henning Kamp UART_SETSIG(sc, SER_DRTS); 2930acb3c4aSMarcel Moolenaar else 29428710806SPoul-Henning Kamp UART_SETSIG(sc, SER_DRTS | SER_RTS); 29527d5dc18SMarcel Moolenaar } else 29627d5dc18SMarcel Moolenaar UART_IOCTL(sc, UART_IOCTL_IFLOW, (t->c_cflag & CRTS_IFLOW)); 29727d5dc18SMarcel Moolenaar /* Set output flow control state. */ 29827d5dc18SMarcel Moolenaar if (sc->sc_hwoflow) 29927d5dc18SMarcel Moolenaar UART_IOCTL(sc, UART_IOCTL_OFLOW, (t->c_cflag & CCTS_OFLOW)); 300bc093719SEd Schouten 30127d5dc18SMarcel Moolenaar return (0); 30227d5dc18SMarcel Moolenaar } 30327d5dc18SMarcel Moolenaar 30496df2b0bSPoul-Henning Kamp static int 30596df2b0bSPoul-Henning Kamp uart_tty_modem(struct tty *tp, int biton, int bitoff) 30696df2b0bSPoul-Henning Kamp { 30796df2b0bSPoul-Henning Kamp struct uart_softc *sc; 30896df2b0bSPoul-Henning Kamp 309bc093719SEd Schouten sc = tty_softc(tp); 31096df2b0bSPoul-Henning Kamp if (biton != 0 || bitoff != 0) 31196df2b0bSPoul-Henning Kamp UART_SETSIG(sc, SER_DELTA(bitoff | biton) | biton); 31296df2b0bSPoul-Henning Kamp return (sc->sc_hwsig); 31396df2b0bSPoul-Henning Kamp } 31496df2b0bSPoul-Henning Kamp 31527d5dc18SMarcel Moolenaar void 31627d5dc18SMarcel Moolenaar uart_tty_intr(void *arg) 31727d5dc18SMarcel Moolenaar { 31827d5dc18SMarcel Moolenaar struct uart_softc *sc = arg; 31927d5dc18SMarcel Moolenaar struct tty *tp; 320bc093719SEd Schouten int c, err = 0, pend, sig, xc; 32127d5dc18SMarcel Moolenaar 32227d5dc18SMarcel Moolenaar if (sc->sc_leaving) 32327d5dc18SMarcel Moolenaar return; 32427d5dc18SMarcel Moolenaar 32527d5dc18SMarcel Moolenaar pend = atomic_readandclear_32(&sc->sc_ttypend); 3262d511805SMarcel Moolenaar if (!(pend & SER_INT_MASK)) 32727d5dc18SMarcel Moolenaar return; 32827d5dc18SMarcel Moolenaar 32927d5dc18SMarcel Moolenaar tp = sc->sc_u.u_tty.tp; 330bc093719SEd Schouten tty_lock(tp); 33127d5dc18SMarcel Moolenaar 3322d511805SMarcel Moolenaar if (pend & SER_INT_RXREADY) { 3330acb3c4aSMarcel Moolenaar while (!uart_rx_empty(sc) && !sc->sc_isquelch) { 3340acb3c4aSMarcel Moolenaar xc = uart_rx_peek(sc); 33527d5dc18SMarcel Moolenaar c = xc & 0xff; 33627d5dc18SMarcel Moolenaar if (xc & UART_STAT_FRAMERR) 337bc093719SEd Schouten err |= TRE_FRAMING; 338dd5b096fSMarcel Moolenaar if (xc & UART_STAT_OVERRUN) 339bc093719SEd Schouten err |= TRE_OVERRUN; 34027d5dc18SMarcel Moolenaar if (xc & UART_STAT_PARERR) 341bc093719SEd Schouten err |= TRE_PARITY; 3420acb3c4aSMarcel Moolenaar if (ttydisc_rint(tp, c, err) != 0) { 3430acb3c4aSMarcel Moolenaar sc->sc_isquelch = 1; 3440acb3c4aSMarcel Moolenaar if ((tp->t_termios.c_cflag & CRTS_IFLOW) && 3450acb3c4aSMarcel Moolenaar !sc->sc_hwiflow) 3460acb3c4aSMarcel Moolenaar UART_SETSIG(sc, SER_DRTS); 3470acb3c4aSMarcel Moolenaar } else 3480acb3c4aSMarcel Moolenaar uart_rx_next(sc); 34927d5dc18SMarcel Moolenaar } 35027d5dc18SMarcel Moolenaar } 35127d5dc18SMarcel Moolenaar 352bc093719SEd Schouten if (pend & SER_INT_BREAK) 353bc093719SEd Schouten ttydisc_rint(tp, 0, TRE_BREAK); 35427d5dc18SMarcel Moolenaar 3552d511805SMarcel Moolenaar if (pend & SER_INT_SIGCHG) { 3562d511805SMarcel Moolenaar sig = pend & SER_INT_SIGMASK; 35728710806SPoul-Henning Kamp if (sig & SER_DDCD) 358bc093719SEd Schouten ttydisc_modem(tp, sig & SER_DCD); 359f1fb9647SMarcel Moolenaar if (sig & SER_DCTS) 360bc093719SEd Schouten uart_tty_outwakeup(tp); 36127d5dc18SMarcel Moolenaar } 36227d5dc18SMarcel Moolenaar 363bc093719SEd Schouten if (pend & SER_INT_TXIDLE) 364bc093719SEd Schouten uart_tty_outwakeup(tp); 365bc093719SEd Schouten ttydisc_rint_done(tp); 366bc093719SEd Schouten tty_unlock(tp); 36727d5dc18SMarcel Moolenaar } 368bc093719SEd Schouten 3699b866e4eSEd Schouten static void 37057169ceaSMarius Strobl uart_tty_free(void *arg __unused) 3719b866e4eSEd Schouten { 3729b866e4eSEd Schouten 3739b866e4eSEd Schouten /* 3749b866e4eSEd Schouten * XXX: uart(4) could reuse the device unit number before it is 3759b866e4eSEd Schouten * being freed by the TTY layer. We should use this hook to free 3769b866e4eSEd Schouten * the device unit number, but unfortunately newbus does not 3779b866e4eSEd Schouten * seem to support such a construct. 3789b866e4eSEd Schouten */ 3799b866e4eSEd Schouten } 3809b866e4eSEd Schouten 3819750d9e5SMarius Strobl static bool 3829750d9e5SMarius Strobl uart_tty_busy(struct tty *tp) 3839750d9e5SMarius Strobl { 3849750d9e5SMarius Strobl struct uart_softc *sc; 3859750d9e5SMarius Strobl 3869750d9e5SMarius Strobl sc = tty_softc(tp); 3879750d9e5SMarius Strobl if (sc == NULL || sc->sc_leaving) 3889750d9e5SMarius Strobl return (FALSE); 3899750d9e5SMarius Strobl 3909750d9e5SMarius Strobl return (sc->sc_txbusy); 3919750d9e5SMarius Strobl } 3929750d9e5SMarius Strobl 393bc093719SEd Schouten static struct ttydevsw uart_tty_class = { 394bc093719SEd Schouten .tsw_flags = TF_INITLOCK|TF_CALLOUT, 395bc093719SEd Schouten .tsw_open = uart_tty_open, 396bc093719SEd Schouten .tsw_close = uart_tty_close, 397bc093719SEd Schouten .tsw_outwakeup = uart_tty_outwakeup, 3980acb3c4aSMarcel Moolenaar .tsw_inwakeup = uart_tty_inwakeup, 399bc093719SEd Schouten .tsw_ioctl = uart_tty_ioctl, 400bc093719SEd Schouten .tsw_param = uart_tty_param, 401bc093719SEd Schouten .tsw_modem = uart_tty_modem, 4029b866e4eSEd Schouten .tsw_free = uart_tty_free, 4039750d9e5SMarius Strobl .tsw_busy = uart_tty_busy, 404bc093719SEd Schouten }; 40527d5dc18SMarcel Moolenaar 40627d5dc18SMarcel Moolenaar int 40727d5dc18SMarcel Moolenaar uart_tty_attach(struct uart_softc *sc) 40827d5dc18SMarcel Moolenaar { 40927d5dc18SMarcel Moolenaar struct tty *tp; 41079a8d927SPoul-Henning Kamp int unit; 41127d5dc18SMarcel Moolenaar 412c5e30cc0SEd Schouten sc->sc_u.u_tty.tp = tp = tty_alloc(&uart_tty_class, sc); 41327d5dc18SMarcel Moolenaar 41479a8d927SPoul-Henning Kamp unit = device_get_unit(sc->sc_dev); 41527d5dc18SMarcel Moolenaar 41627d5dc18SMarcel Moolenaar if (sc->sc_sysdev != NULL && sc->sc_sysdev->type == UART_DEV_CONSOLE) { 41712d984b6SMarcel Moolenaar sprintf(((struct consdev *)sc->sc_sysdev->cookie)->cn_name, 41879a8d927SPoul-Henning Kamp "ttyu%r", unit); 419f725b213SMarcel Moolenaar tty_init_console(tp, sc->sc_sysdev->baudrate); 42027d5dc18SMarcel Moolenaar } 42127d5dc18SMarcel Moolenaar 422e0f66ef8SJohn Baldwin swi_add(&tty_intr_event, uart_driver_name, uart_tty_intr, sc, SWI_TTY, 42327d5dc18SMarcel Moolenaar INTR_TYPE_TTY, &sc->sc_softih); 42427d5dc18SMarcel Moolenaar 425bc093719SEd Schouten tty_makedev(tp, NULL, "u%r", unit); 42679a8d927SPoul-Henning Kamp 42727d5dc18SMarcel Moolenaar return (0); 42827d5dc18SMarcel Moolenaar } 42927d5dc18SMarcel Moolenaar 4307d376cbcSAlexander Kabaev int 4317d376cbcSAlexander Kabaev uart_tty_detach(struct uart_softc *sc) 43227d5dc18SMarcel Moolenaar { 43379a8d927SPoul-Henning Kamp struct tty *tp; 43427d5dc18SMarcel Moolenaar 43579a8d927SPoul-Henning Kamp tp = sc->sc_u.u_tty.tp; 436bc093719SEd Schouten 437bc093719SEd Schouten tty_lock(tp); 438284b6708SJohn Baldwin swi_remove(sc->sc_softih); 439bc093719SEd Schouten tty_rel_gone(tp); 44027d5dc18SMarcel Moolenaar 44127d5dc18SMarcel Moolenaar return (0); 44227d5dc18SMarcel Moolenaar } 443b59236ceSIan Lepore 444b59236ceSIan Lepore struct mtx * 445b59236ceSIan Lepore uart_tty_getlock(struct uart_softc *sc) 446b59236ceSIan Lepore { 447b59236ceSIan Lepore 448b59236ceSIan Lepore if (sc->sc_u.u_tty.tp != NULL) 449b59236ceSIan Lepore return (tty_getlock(sc->sc_u.u_tty.tp)); 450b59236ceSIan Lepore else 451b59236ceSIan Lepore return (NULL); 452b59236ceSIan Lepore } 453