127d5dc18SMarcel Moolenaar /* 227d5dc18SMarcel Moolenaar * Copyright (c) 2003 Marcel Moolenaar 327d5dc18SMarcel Moolenaar * All rights reserved. 427d5dc18SMarcel Moolenaar * 527d5dc18SMarcel Moolenaar * Redistribution and use in source and binary forms, with or without 627d5dc18SMarcel Moolenaar * modification, are permitted provided that the following conditions 727d5dc18SMarcel Moolenaar * are met: 827d5dc18SMarcel Moolenaar * 927d5dc18SMarcel Moolenaar * 1. Redistributions of source code must retain the above copyright 1027d5dc18SMarcel Moolenaar * notice, this list of conditions and the following disclaimer. 1127d5dc18SMarcel Moolenaar * 2. Redistributions in binary form must reproduce the above copyright 1227d5dc18SMarcel Moolenaar * notice, this list of conditions and the following disclaimer in the 1327d5dc18SMarcel Moolenaar * documentation and/or other materials provided with the distribution. 1427d5dc18SMarcel Moolenaar * 1527d5dc18SMarcel Moolenaar * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1627d5dc18SMarcel Moolenaar * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1727d5dc18SMarcel Moolenaar * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1827d5dc18SMarcel Moolenaar * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1927d5dc18SMarcel Moolenaar * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2027d5dc18SMarcel Moolenaar * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2127d5dc18SMarcel Moolenaar * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2227d5dc18SMarcel Moolenaar * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2327d5dc18SMarcel Moolenaar * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2427d5dc18SMarcel Moolenaar * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2527d5dc18SMarcel Moolenaar */ 2627d5dc18SMarcel Moolenaar 2727d5dc18SMarcel Moolenaar #include <sys/cdefs.h> 2827d5dc18SMarcel Moolenaar __FBSDID("$FreeBSD$"); 2927d5dc18SMarcel Moolenaar 3027d5dc18SMarcel Moolenaar #include <sys/param.h> 3127d5dc18SMarcel Moolenaar #include <sys/systm.h> 3227d5dc18SMarcel Moolenaar #include <sys/bus.h> 3327d5dc18SMarcel Moolenaar #include <sys/conf.h> 3427d5dc18SMarcel Moolenaar #include <sys/cons.h> 3527d5dc18SMarcel Moolenaar #include <sys/fcntl.h> 3627d5dc18SMarcel Moolenaar #include <sys/interrupt.h> 3727d5dc18SMarcel Moolenaar #include <sys/kernel.h> 3827d5dc18SMarcel Moolenaar #include <sys/malloc.h> 3927d5dc18SMarcel Moolenaar #include <sys/reboot.h> 4027d5dc18SMarcel Moolenaar #include <machine/bus.h> 4127d5dc18SMarcel Moolenaar #include <sys/rman.h> 4227d5dc18SMarcel Moolenaar #include <sys/termios.h> 4327d5dc18SMarcel Moolenaar #include <sys/tty.h> 4427d5dc18SMarcel Moolenaar #include <machine/resource.h> 4527d5dc18SMarcel Moolenaar #include <machine/stdarg.h> 4627d5dc18SMarcel Moolenaar 4727d5dc18SMarcel Moolenaar #include <dev/uart/uart.h> 4827d5dc18SMarcel Moolenaar #include <dev/uart/uart_bus.h> 4927d5dc18SMarcel Moolenaar #include <dev/uart/uart_cpu.h> 5027d5dc18SMarcel Moolenaar 5127d5dc18SMarcel Moolenaar #include "uart_if.h" 5227d5dc18SMarcel Moolenaar 5327d5dc18SMarcel Moolenaar #define UART_MINOR_CALLOUT 0x10000 5427d5dc18SMarcel Moolenaar 5527d5dc18SMarcel Moolenaar static cn_probe_t uart_cnprobe; 5627d5dc18SMarcel Moolenaar static cn_init_t uart_cninit; 5727d5dc18SMarcel Moolenaar static cn_term_t uart_cnterm; 5827d5dc18SMarcel Moolenaar static cn_getc_t uart_cngetc; 5927d5dc18SMarcel Moolenaar static cn_checkc_t uart_cncheckc; 6027d5dc18SMarcel Moolenaar static cn_putc_t uart_cnputc; 6127d5dc18SMarcel Moolenaar 6227d5dc18SMarcel Moolenaar CONS_DRIVER(uart, uart_cnprobe, uart_cninit, uart_cnterm, uart_cngetc, 6327d5dc18SMarcel Moolenaar uart_cncheckc, uart_cnputc, NULL); 6427d5dc18SMarcel Moolenaar 6527d5dc18SMarcel Moolenaar static d_open_t uart_tty_open; 6627d5dc18SMarcel Moolenaar static d_close_t uart_tty_close; 6727d5dc18SMarcel Moolenaar static d_ioctl_t uart_tty_ioctl; 6827d5dc18SMarcel Moolenaar 6927d5dc18SMarcel Moolenaar static struct cdevsw uart_cdevsw = { 7027d5dc18SMarcel Moolenaar .d_open = uart_tty_open, 7127d5dc18SMarcel Moolenaar .d_close = uart_tty_close, 7227d5dc18SMarcel Moolenaar .d_read = ttyread, 7327d5dc18SMarcel Moolenaar .d_write = ttywrite, 7427d5dc18SMarcel Moolenaar .d_ioctl = uart_tty_ioctl, 7527d5dc18SMarcel Moolenaar .d_poll = ttypoll, 7627d5dc18SMarcel Moolenaar .d_name = uart_driver_name, 7727d5dc18SMarcel Moolenaar .d_flags = D_TTY, 7827d5dc18SMarcel Moolenaar .d_kqfilter = ttykqfilter, 7927d5dc18SMarcel Moolenaar }; 8027d5dc18SMarcel Moolenaar 8127d5dc18SMarcel Moolenaar static struct uart_devinfo uart_console; 8227d5dc18SMarcel Moolenaar 8327d5dc18SMarcel Moolenaar static void 8427d5dc18SMarcel Moolenaar uart_cnprobe(struct consdev *cp) 8527d5dc18SMarcel Moolenaar { 8627d5dc18SMarcel Moolenaar 8727d5dc18SMarcel Moolenaar cp->cn_pri = CN_DEAD; 8827d5dc18SMarcel Moolenaar 8927d5dc18SMarcel Moolenaar KASSERT(uart_console.cookie == NULL, ("foo")); 9027d5dc18SMarcel Moolenaar 9127d5dc18SMarcel Moolenaar if (uart_cpu_getdev(UART_DEV_CONSOLE, &uart_console)) 9227d5dc18SMarcel Moolenaar return; 9327d5dc18SMarcel Moolenaar 9427d5dc18SMarcel Moolenaar if (uart_probe(&uart_console)) 9527d5dc18SMarcel Moolenaar return; 9627d5dc18SMarcel Moolenaar 9727d5dc18SMarcel Moolenaar cp->cn_pri = (boothowto & RB_SERIAL) ? CN_REMOTE : CN_NORMAL; 9827d5dc18SMarcel Moolenaar cp->cn_arg = &uart_console; 9927d5dc18SMarcel Moolenaar } 10027d5dc18SMarcel Moolenaar 10127d5dc18SMarcel Moolenaar static void 10227d5dc18SMarcel Moolenaar uart_cninit(struct consdev *cp) 10327d5dc18SMarcel Moolenaar { 10427d5dc18SMarcel Moolenaar struct uart_devinfo *di; 10527d5dc18SMarcel Moolenaar 10627d5dc18SMarcel Moolenaar /* 10727d5dc18SMarcel Moolenaar * Yedi trick: we need to be able to define cn_dev before we go 10827d5dc18SMarcel Moolenaar * single- or multi-user. The problem is that we don't know at 10927d5dc18SMarcel Moolenaar * this time what the device will be. Hence, we need to link from 11027d5dc18SMarcel Moolenaar * the uart_devinfo to the consdev that corresponds to it so that 11127d5dc18SMarcel Moolenaar * we can define cn_dev in uart_bus_attach() when we find the 11227d5dc18SMarcel Moolenaar * device during bus enumeration. That's when we'll know what the 11327d5dc18SMarcel Moolenaar * the unit number will be. 11427d5dc18SMarcel Moolenaar */ 11527d5dc18SMarcel Moolenaar di = cp->cn_arg; 11627d5dc18SMarcel Moolenaar KASSERT(di->cookie == NULL, ("foo")); 11727d5dc18SMarcel Moolenaar di->cookie = cp; 11827d5dc18SMarcel Moolenaar di->type = UART_DEV_CONSOLE; 11927d5dc18SMarcel Moolenaar uart_add_sysdev(di); 12027d5dc18SMarcel Moolenaar uart_init(di); 12127d5dc18SMarcel Moolenaar } 12227d5dc18SMarcel Moolenaar 12327d5dc18SMarcel Moolenaar static void 12427d5dc18SMarcel Moolenaar uart_cnterm(struct consdev *cp) 12527d5dc18SMarcel Moolenaar { 12627d5dc18SMarcel Moolenaar 12727d5dc18SMarcel Moolenaar uart_term(cp->cn_arg); 12827d5dc18SMarcel Moolenaar } 12927d5dc18SMarcel Moolenaar 13027d5dc18SMarcel Moolenaar static void 13127d5dc18SMarcel Moolenaar uart_cnputc(struct consdev *cp, int c) 13227d5dc18SMarcel Moolenaar { 13327d5dc18SMarcel Moolenaar 13427d5dc18SMarcel Moolenaar uart_putc(cp->cn_arg, c); 13527d5dc18SMarcel Moolenaar } 13627d5dc18SMarcel Moolenaar 13727d5dc18SMarcel Moolenaar static int 13827d5dc18SMarcel Moolenaar uart_cncheckc(struct consdev *cp) 13927d5dc18SMarcel Moolenaar { 14027d5dc18SMarcel Moolenaar 14127d5dc18SMarcel Moolenaar return (uart_poll(cp->cn_arg)); 14227d5dc18SMarcel Moolenaar } 14327d5dc18SMarcel Moolenaar 14427d5dc18SMarcel Moolenaar static int 14527d5dc18SMarcel Moolenaar uart_cngetc(struct consdev *cp) 14627d5dc18SMarcel Moolenaar { 14727d5dc18SMarcel Moolenaar 14827d5dc18SMarcel Moolenaar return (uart_getc(cp->cn_arg)); 14927d5dc18SMarcel Moolenaar } 15027d5dc18SMarcel Moolenaar 15127d5dc18SMarcel Moolenaar static void 15227d5dc18SMarcel Moolenaar uart_tty_oproc(struct tty *tp) 15327d5dc18SMarcel Moolenaar { 15427d5dc18SMarcel Moolenaar struct uart_softc *sc; 15527d5dc18SMarcel Moolenaar 15627d5dc18SMarcel Moolenaar KASSERT(tp->t_dev != NULL, ("foo")); 15727d5dc18SMarcel Moolenaar sc = tp->t_dev->si_drv1; 15827d5dc18SMarcel Moolenaar if (sc == NULL || sc->sc_leaving) 15927d5dc18SMarcel Moolenaar return; 16027d5dc18SMarcel Moolenaar 16127d5dc18SMarcel Moolenaar /* 16227d5dc18SMarcel Moolenaar * Handle input flow control. Note that if we have hardware support, 16327d5dc18SMarcel Moolenaar * we don't do anything here. We continue to receive until our buffer 16427d5dc18SMarcel Moolenaar * is full. At that time we cannot empty the UART itself and it will 16527d5dc18SMarcel Moolenaar * de-assert RTS for us. In that situation we're completely stuffed. 16627d5dc18SMarcel Moolenaar * Without hardware support, we need to toggle RTS ourselves. 16727d5dc18SMarcel Moolenaar */ 16827d5dc18SMarcel Moolenaar if ((tp->t_cflag & CRTS_IFLOW) && !sc->sc_hwiflow) { 16927d5dc18SMarcel Moolenaar if ((tp->t_state & TS_TBLOCK) && 17027d5dc18SMarcel Moolenaar (sc->sc_hwsig & UART_SIG_RTS)) 17127d5dc18SMarcel Moolenaar UART_SETSIG(sc, UART_SIG_DRTS); 17227d5dc18SMarcel Moolenaar else if (!(tp->t_state & TS_TBLOCK) && 17327d5dc18SMarcel Moolenaar !(sc->sc_hwsig & UART_SIG_RTS)) 17427d5dc18SMarcel Moolenaar UART_SETSIG(sc, UART_SIG_DRTS|UART_SIG_RTS); 17527d5dc18SMarcel Moolenaar } 17627d5dc18SMarcel Moolenaar 17727d5dc18SMarcel Moolenaar if (tp->t_state & TS_TTSTOP) 17827d5dc18SMarcel Moolenaar return; 17927d5dc18SMarcel Moolenaar 18027d5dc18SMarcel Moolenaar if ((tp->t_state & TS_BUSY) || sc->sc_txbusy) 18127d5dc18SMarcel Moolenaar return; 18227d5dc18SMarcel Moolenaar 18327d5dc18SMarcel Moolenaar if (tp->t_outq.c_cc == 0) { 18427d5dc18SMarcel Moolenaar ttwwakeup(tp); 18527d5dc18SMarcel Moolenaar return; 18627d5dc18SMarcel Moolenaar } 18727d5dc18SMarcel Moolenaar 18827d5dc18SMarcel Moolenaar sc->sc_txdatasz = q_to_b(&tp->t_outq, sc->sc_txbuf, sc->sc_txfifosz); 18927d5dc18SMarcel Moolenaar tp->t_state |= TS_BUSY; 19027d5dc18SMarcel Moolenaar UART_TRANSMIT(sc); 19127d5dc18SMarcel Moolenaar ttwwakeup(tp); 19227d5dc18SMarcel Moolenaar } 19327d5dc18SMarcel Moolenaar 19427d5dc18SMarcel Moolenaar static int 19527d5dc18SMarcel Moolenaar uart_tty_param(struct tty *tp, struct termios *t) 19627d5dc18SMarcel Moolenaar { 19727d5dc18SMarcel Moolenaar struct uart_softc *sc; 19827d5dc18SMarcel Moolenaar int databits, parity, stopbits; 19927d5dc18SMarcel Moolenaar 20027d5dc18SMarcel Moolenaar KASSERT(tp->t_dev != NULL, ("foo")); 20127d5dc18SMarcel Moolenaar sc = tp->t_dev->si_drv1; 20227d5dc18SMarcel Moolenaar if (sc == NULL || sc->sc_leaving) 20327d5dc18SMarcel Moolenaar return (ENODEV); 20427d5dc18SMarcel Moolenaar if (t->c_ispeed != t->c_ospeed && t->c_ospeed != 0) 20527d5dc18SMarcel Moolenaar return (EINVAL); 20627d5dc18SMarcel Moolenaar /* Fixate certain parameters for system devices. */ 20727d5dc18SMarcel Moolenaar if (sc->sc_sysdev != NULL) { 20827d5dc18SMarcel Moolenaar t->c_ispeed = t->c_ospeed = sc->sc_sysdev->baudrate; 20927d5dc18SMarcel Moolenaar t->c_cflag |= CLOCAL; 21027d5dc18SMarcel Moolenaar t->c_cflag &= ~HUPCL; 21127d5dc18SMarcel Moolenaar } 21227d5dc18SMarcel Moolenaar if (t->c_ospeed == 0) { 21327d5dc18SMarcel Moolenaar UART_SETSIG(sc, UART_SIG_DDTR | UART_SIG_DRTS); 21427d5dc18SMarcel Moolenaar return (0); 21527d5dc18SMarcel Moolenaar } 21627d5dc18SMarcel Moolenaar switch (t->c_cflag & CSIZE) { 21727d5dc18SMarcel Moolenaar case CS5: databits = 5; break; 21827d5dc18SMarcel Moolenaar case CS6: databits = 6; break; 21927d5dc18SMarcel Moolenaar case CS7: databits = 7; break; 22027d5dc18SMarcel Moolenaar default: databits = 8; break; 22127d5dc18SMarcel Moolenaar } 22227d5dc18SMarcel Moolenaar stopbits = (t->c_cflag & CSTOPB) ? 2 : 1; 22327d5dc18SMarcel Moolenaar if (t->c_cflag & PARENB) 22427d5dc18SMarcel Moolenaar parity = (t->c_cflag & PARODD) ? UART_PARITY_ODD 22527d5dc18SMarcel Moolenaar : UART_PARITY_EVEN; 22627d5dc18SMarcel Moolenaar else 22727d5dc18SMarcel Moolenaar parity = UART_PARITY_NONE; 228b662bdc2SMarcel Moolenaar if (UART_PARAM(sc, t->c_ospeed, databits, stopbits, parity) != 0) 229b662bdc2SMarcel Moolenaar return (EINVAL); 23027d5dc18SMarcel Moolenaar UART_SETSIG(sc, UART_SIG_DDTR | UART_SIG_DTR); 23127d5dc18SMarcel Moolenaar /* Set input flow control state. */ 23227d5dc18SMarcel Moolenaar if (!sc->sc_hwiflow) { 23327d5dc18SMarcel Moolenaar if ((t->c_cflag & CRTS_IFLOW) && (tp->t_state & TS_TBLOCK)) 23427d5dc18SMarcel Moolenaar UART_SETSIG(sc, UART_SIG_DRTS); 23527d5dc18SMarcel Moolenaar else 23627d5dc18SMarcel Moolenaar UART_SETSIG(sc, UART_SIG_DRTS | UART_SIG_RTS); 23727d5dc18SMarcel Moolenaar } else 23827d5dc18SMarcel Moolenaar UART_IOCTL(sc, UART_IOCTL_IFLOW, (t->c_cflag & CRTS_IFLOW)); 23927d5dc18SMarcel Moolenaar /* Set output flow control state. */ 24027d5dc18SMarcel Moolenaar if (sc->sc_hwoflow) 24127d5dc18SMarcel Moolenaar UART_IOCTL(sc, UART_IOCTL_OFLOW, (t->c_cflag & CCTS_OFLOW)); 24227d5dc18SMarcel Moolenaar ttsetwater(tp); 24327d5dc18SMarcel Moolenaar return (0); 24427d5dc18SMarcel Moolenaar } 24527d5dc18SMarcel Moolenaar 24627d5dc18SMarcel Moolenaar static void 24727d5dc18SMarcel Moolenaar uart_tty_stop(struct tty *tp, int rw) 24827d5dc18SMarcel Moolenaar { 24927d5dc18SMarcel Moolenaar struct uart_softc *sc; 25027d5dc18SMarcel Moolenaar 25127d5dc18SMarcel Moolenaar KASSERT(tp->t_dev != NULL, ("foo")); 25227d5dc18SMarcel Moolenaar sc = tp->t_dev->si_drv1; 25327d5dc18SMarcel Moolenaar if (sc == NULL || sc->sc_leaving) 25427d5dc18SMarcel Moolenaar return; 25527d5dc18SMarcel Moolenaar if (rw & FWRITE) { 25627d5dc18SMarcel Moolenaar if (sc->sc_txbusy) { 25727d5dc18SMarcel Moolenaar sc->sc_txbusy = 0; 25827d5dc18SMarcel Moolenaar UART_FLUSH(sc, UART_FLUSH_TRANSMITTER); 25927d5dc18SMarcel Moolenaar } 26027d5dc18SMarcel Moolenaar tp->t_state &= ~TS_BUSY; 26127d5dc18SMarcel Moolenaar } 26227d5dc18SMarcel Moolenaar if (rw & FREAD) { 26327d5dc18SMarcel Moolenaar UART_FLUSH(sc, UART_FLUSH_RECEIVER); 26427d5dc18SMarcel Moolenaar sc->sc_rxget = sc->sc_rxput = 0; 26527d5dc18SMarcel Moolenaar } 26627d5dc18SMarcel Moolenaar } 26727d5dc18SMarcel Moolenaar 26827d5dc18SMarcel Moolenaar void 26927d5dc18SMarcel Moolenaar uart_tty_intr(void *arg) 27027d5dc18SMarcel Moolenaar { 27127d5dc18SMarcel Moolenaar struct uart_softc *sc = arg; 27227d5dc18SMarcel Moolenaar struct tty *tp; 27327d5dc18SMarcel Moolenaar int c, pend, sig, xc; 27427d5dc18SMarcel Moolenaar 27527d5dc18SMarcel Moolenaar if (sc->sc_leaving) 27627d5dc18SMarcel Moolenaar return; 27727d5dc18SMarcel Moolenaar 27827d5dc18SMarcel Moolenaar pend = atomic_readandclear_32(&sc->sc_ttypend); 27927d5dc18SMarcel Moolenaar if (!(pend & UART_IPEND_MASK)) 28027d5dc18SMarcel Moolenaar return; 28127d5dc18SMarcel Moolenaar 28227d5dc18SMarcel Moolenaar tp = sc->sc_u.u_tty.tp; 28327d5dc18SMarcel Moolenaar 28427d5dc18SMarcel Moolenaar if (pend & UART_IPEND_RXREADY) { 28527d5dc18SMarcel Moolenaar while (!uart_rx_empty(sc) && !(tp->t_state & TS_TBLOCK)) { 28627d5dc18SMarcel Moolenaar xc = uart_rx_get(sc); 28727d5dc18SMarcel Moolenaar c = xc & 0xff; 28827d5dc18SMarcel Moolenaar if (xc & UART_STAT_FRAMERR) 28927d5dc18SMarcel Moolenaar c |= TTY_FE; 29027d5dc18SMarcel Moolenaar if (xc & UART_STAT_PARERR) 29127d5dc18SMarcel Moolenaar c |= TTY_PE; 29227d5dc18SMarcel Moolenaar (*linesw[tp->t_line].l_rint)(c, tp); 29327d5dc18SMarcel Moolenaar } 29427d5dc18SMarcel Moolenaar } 29527d5dc18SMarcel Moolenaar 29627d5dc18SMarcel Moolenaar if (pend & UART_IPEND_BREAK) { 29727d5dc18SMarcel Moolenaar if (tp != NULL && !(tp->t_iflag & IGNBRK)) 29827d5dc18SMarcel Moolenaar (*linesw[tp->t_line].l_rint)(0, tp); 29927d5dc18SMarcel Moolenaar } 30027d5dc18SMarcel Moolenaar 30127d5dc18SMarcel Moolenaar if (pend & UART_IPEND_SIGCHG) { 30227d5dc18SMarcel Moolenaar sig = pend & UART_IPEND_SIGMASK; 30327d5dc18SMarcel Moolenaar if (sig & UART_SIG_DDCD) 30427d5dc18SMarcel Moolenaar (*linesw[tp->t_line].l_modem)(tp, sig & UART_SIG_DCD); 30527d5dc18SMarcel Moolenaar if ((sig & UART_SIG_DCTS) && (tp->t_cflag & CCTS_OFLOW) && 30627d5dc18SMarcel Moolenaar !sc->sc_hwoflow) { 30727d5dc18SMarcel Moolenaar if (sig & UART_SIG_CTS) { 30827d5dc18SMarcel Moolenaar tp->t_state &= ~TS_TTSTOP; 30927d5dc18SMarcel Moolenaar (*linesw[tp->t_line].l_start)(tp); 31027d5dc18SMarcel Moolenaar } else 31127d5dc18SMarcel Moolenaar tp->t_state |= TS_TTSTOP; 31227d5dc18SMarcel Moolenaar } 31327d5dc18SMarcel Moolenaar } 31427d5dc18SMarcel Moolenaar 31527d5dc18SMarcel Moolenaar if (pend & UART_IPEND_TXIDLE) { 31627d5dc18SMarcel Moolenaar tp->t_state &= ~TS_BUSY; 31727d5dc18SMarcel Moolenaar (*linesw[tp->t_line].l_start)(tp); 31827d5dc18SMarcel Moolenaar } 31927d5dc18SMarcel Moolenaar } 32027d5dc18SMarcel Moolenaar 32127d5dc18SMarcel Moolenaar int 32227d5dc18SMarcel Moolenaar uart_tty_attach(struct uart_softc *sc) 32327d5dc18SMarcel Moolenaar { 32427d5dc18SMarcel Moolenaar struct tty *tp; 32527d5dc18SMarcel Moolenaar 32627d5dc18SMarcel Moolenaar tp = ttymalloc(NULL); 32727d5dc18SMarcel Moolenaar sc->sc_u.u_tty.tp = tp; 32827d5dc18SMarcel Moolenaar 32927d5dc18SMarcel Moolenaar sc->sc_u.u_tty.si[0] = make_dev(&uart_cdevsw, 33027d5dc18SMarcel Moolenaar device_get_unit(sc->sc_dev), UID_ROOT, GID_WHEEL, 0600, "ttyu%r", 33127d5dc18SMarcel Moolenaar device_get_unit(sc->sc_dev)); 33227d5dc18SMarcel Moolenaar sc->sc_u.u_tty.si[0]->si_drv1 = sc; 33327d5dc18SMarcel Moolenaar sc->sc_u.u_tty.si[0]->si_tty = tp; 33427d5dc18SMarcel Moolenaar sc->sc_u.u_tty.si[1] = make_dev(&uart_cdevsw, 33527d5dc18SMarcel Moolenaar device_get_unit(sc->sc_dev) | UART_MINOR_CALLOUT, UID_UUCP, 33627d5dc18SMarcel Moolenaar GID_DIALER, 0660, "uart%r", device_get_unit(sc->sc_dev)); 33727d5dc18SMarcel Moolenaar sc->sc_u.u_tty.si[1]->si_drv1 = sc; 33827d5dc18SMarcel Moolenaar sc->sc_u.u_tty.si[1]->si_tty = tp; 33927d5dc18SMarcel Moolenaar 34027d5dc18SMarcel Moolenaar tp->t_oproc = uart_tty_oproc; 34127d5dc18SMarcel Moolenaar tp->t_param = uart_tty_param; 34227d5dc18SMarcel Moolenaar tp->t_stop = uart_tty_stop; 34327d5dc18SMarcel Moolenaar 34427d5dc18SMarcel Moolenaar if (sc->sc_sysdev != NULL && sc->sc_sysdev->type == UART_DEV_CONSOLE) { 34512d984b6SMarcel Moolenaar sprintf(((struct consdev *)sc->sc_sysdev->cookie)->cn_name, 34612d984b6SMarcel Moolenaar "ttyu%r", device_get_unit(sc->sc_dev)); 34727d5dc18SMarcel Moolenaar } 34827d5dc18SMarcel Moolenaar 34927d5dc18SMarcel Moolenaar swi_add(&tty_ithd, uart_driver_name, uart_tty_intr, sc, SWI_TTY, 35027d5dc18SMarcel Moolenaar INTR_TYPE_TTY, &sc->sc_softih); 35127d5dc18SMarcel Moolenaar 35227d5dc18SMarcel Moolenaar return (0); 35327d5dc18SMarcel Moolenaar } 35427d5dc18SMarcel Moolenaar 35527d5dc18SMarcel Moolenaar int uart_tty_detach(struct uart_softc *sc) 35627d5dc18SMarcel Moolenaar { 35727d5dc18SMarcel Moolenaar 35827d5dc18SMarcel Moolenaar ithread_remove_handler(sc->sc_softih); 35927d5dc18SMarcel Moolenaar destroy_dev(sc->sc_u.u_tty.si[0]); 36027d5dc18SMarcel Moolenaar destroy_dev(sc->sc_u.u_tty.si[1]); 36127d5dc18SMarcel Moolenaar /* ttyfree(sc->sc_u.u_tty.tp); */ 36227d5dc18SMarcel Moolenaar 36327d5dc18SMarcel Moolenaar return (0); 36427d5dc18SMarcel Moolenaar } 36527d5dc18SMarcel Moolenaar 36627d5dc18SMarcel Moolenaar static int 36727d5dc18SMarcel Moolenaar uart_tty_open(dev_t dev, int flags, int mode, struct thread *td) 36827d5dc18SMarcel Moolenaar { 36927d5dc18SMarcel Moolenaar struct uart_softc *sc; 37027d5dc18SMarcel Moolenaar struct tty *tp; 37127d5dc18SMarcel Moolenaar int error; 37227d5dc18SMarcel Moolenaar 37327d5dc18SMarcel Moolenaar sc = dev->si_drv1; 37427d5dc18SMarcel Moolenaar if (sc == NULL || sc->sc_leaving) 37527d5dc18SMarcel Moolenaar return (ENODEV); 37627d5dc18SMarcel Moolenaar 37727d5dc18SMarcel Moolenaar tp = dev->si_tty; 37827d5dc18SMarcel Moolenaar 37927d5dc18SMarcel Moolenaar loop: 38027d5dc18SMarcel Moolenaar if (sc->sc_opened) { 38127d5dc18SMarcel Moolenaar KASSERT(tp->t_state & TS_ISOPEN, ("foo")); 38227d5dc18SMarcel Moolenaar /* 38327d5dc18SMarcel Moolenaar * The device is open, so everything has been initialized. 38427d5dc18SMarcel Moolenaar * Handle conflicts. 38527d5dc18SMarcel Moolenaar */ 38627d5dc18SMarcel Moolenaar if (minor(dev) & UART_MINOR_CALLOUT) { 38727d5dc18SMarcel Moolenaar if (!sc->sc_callout) 38827d5dc18SMarcel Moolenaar return (EBUSY); 38927d5dc18SMarcel Moolenaar } else { 39027d5dc18SMarcel Moolenaar if (sc->sc_callout) { 39127d5dc18SMarcel Moolenaar if (flags & O_NONBLOCK) 39227d5dc18SMarcel Moolenaar return (EBUSY); 39327d5dc18SMarcel Moolenaar error = tsleep(sc, TTIPRI|PCATCH, "uartbi", 0); 39427d5dc18SMarcel Moolenaar if (error) 39527d5dc18SMarcel Moolenaar return (error); 39627d5dc18SMarcel Moolenaar sc = dev->si_drv1; 39727d5dc18SMarcel Moolenaar if (sc == NULL || sc->sc_leaving) 39827d5dc18SMarcel Moolenaar return (ENODEV); 39927d5dc18SMarcel Moolenaar goto loop; 40027d5dc18SMarcel Moolenaar } 40127d5dc18SMarcel Moolenaar } 40227d5dc18SMarcel Moolenaar if (tp->t_state & TS_XCLUDE && suser(td) != 0) 40327d5dc18SMarcel Moolenaar return (EBUSY); 40427d5dc18SMarcel Moolenaar } else { 40527d5dc18SMarcel Moolenaar KASSERT(!(tp->t_state & TS_ISOPEN), ("foo")); 40627d5dc18SMarcel Moolenaar /* 40727d5dc18SMarcel Moolenaar * The device isn't open, so there are no conflicts. 40827d5dc18SMarcel Moolenaar * Initialize it. Initialization is done twice in many 40927d5dc18SMarcel Moolenaar * cases: to preempt sleeping callin opens if we are 41027d5dc18SMarcel Moolenaar * callout, and to complete a callin open after DCD rises. 41127d5dc18SMarcel Moolenaar */ 41227d5dc18SMarcel Moolenaar sc->sc_callout = (minor(dev) & UART_MINOR_CALLOUT) ? 1 : 0; 41327d5dc18SMarcel Moolenaar tp->t_dev = dev; 41427d5dc18SMarcel Moolenaar 41527d5dc18SMarcel Moolenaar tp->t_cflag = TTYDEF_CFLAG; 41627d5dc18SMarcel Moolenaar tp->t_iflag = TTYDEF_IFLAG; 41727d5dc18SMarcel Moolenaar tp->t_lflag = TTYDEF_LFLAG; 41827d5dc18SMarcel Moolenaar tp->t_oflag = TTYDEF_OFLAG; 41927d5dc18SMarcel Moolenaar tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; 42027d5dc18SMarcel Moolenaar ttychars(tp); 42127d5dc18SMarcel Moolenaar error = uart_tty_param(tp, &tp->t_termios); 42227d5dc18SMarcel Moolenaar if (error) 42327d5dc18SMarcel Moolenaar return (error); 42427d5dc18SMarcel Moolenaar /* 42527d5dc18SMarcel Moolenaar * Handle initial DCD. 42627d5dc18SMarcel Moolenaar */ 42727d5dc18SMarcel Moolenaar if ((sc->sc_hwsig & UART_SIG_DCD) || sc->sc_callout) 42827d5dc18SMarcel Moolenaar (*linesw[tp->t_line].l_modem)(tp, 1); 42927d5dc18SMarcel Moolenaar } 43027d5dc18SMarcel Moolenaar /* 43127d5dc18SMarcel Moolenaar * Wait for DCD if necessary. 43227d5dc18SMarcel Moolenaar */ 43327d5dc18SMarcel Moolenaar if (!(tp->t_state & TS_CARR_ON) && !sc->sc_callout && 43427d5dc18SMarcel Moolenaar !(tp->t_cflag & CLOCAL) && !(flags & O_NONBLOCK)) { 43527d5dc18SMarcel Moolenaar error = tsleep(TSA_CARR_ON(tp), TTIPRI|PCATCH, "uartdcd", 0); 43627d5dc18SMarcel Moolenaar if (error) 43727d5dc18SMarcel Moolenaar return (error); 43827d5dc18SMarcel Moolenaar sc = dev->si_drv1; 43927d5dc18SMarcel Moolenaar if (sc == NULL || sc->sc_leaving) 44027d5dc18SMarcel Moolenaar return (ENODEV); 44127d5dc18SMarcel Moolenaar goto loop; 44227d5dc18SMarcel Moolenaar } 44327d5dc18SMarcel Moolenaar error = ttyopen(dev, tp); 44427d5dc18SMarcel Moolenaar if (error) 44527d5dc18SMarcel Moolenaar return (error); 44627d5dc18SMarcel Moolenaar error = (*linesw[tp->t_line].l_open)(dev, tp); 44727d5dc18SMarcel Moolenaar if (error) 44827d5dc18SMarcel Moolenaar return (error); 44927d5dc18SMarcel Moolenaar 45027d5dc18SMarcel Moolenaar KASSERT(tp->t_state & TS_ISOPEN, ("foo")); 45127d5dc18SMarcel Moolenaar sc->sc_opened = 1; 45227d5dc18SMarcel Moolenaar return (0); 45327d5dc18SMarcel Moolenaar } 45427d5dc18SMarcel Moolenaar 45527d5dc18SMarcel Moolenaar static int 45627d5dc18SMarcel Moolenaar uart_tty_close(dev_t dev, int flags, int mode, struct thread *td) 45727d5dc18SMarcel Moolenaar { 45827d5dc18SMarcel Moolenaar struct uart_softc *sc; 45927d5dc18SMarcel Moolenaar struct tty *tp; 46027d5dc18SMarcel Moolenaar 46127d5dc18SMarcel Moolenaar sc = dev->si_drv1; 46227d5dc18SMarcel Moolenaar if (sc == NULL || sc->sc_leaving) 46327d5dc18SMarcel Moolenaar return (ENODEV); 46427d5dc18SMarcel Moolenaar tp = dev->si_tty; 46527d5dc18SMarcel Moolenaar if (!sc->sc_opened) { 46627d5dc18SMarcel Moolenaar KASSERT(!(tp->t_state & TS_ISOPEN), ("foo")); 46727d5dc18SMarcel Moolenaar return (0); 46827d5dc18SMarcel Moolenaar } 46927d5dc18SMarcel Moolenaar KASSERT(tp->t_state & TS_ISOPEN, ("foo")); 47027d5dc18SMarcel Moolenaar 47127d5dc18SMarcel Moolenaar if (sc->sc_hwiflow) 47227d5dc18SMarcel Moolenaar UART_IOCTL(sc, UART_IOCTL_IFLOW, 0); 47327d5dc18SMarcel Moolenaar if (sc->sc_hwoflow) 47427d5dc18SMarcel Moolenaar UART_IOCTL(sc, UART_IOCTL_OFLOW, 0); 47527d5dc18SMarcel Moolenaar if (sc->sc_sysdev == NULL) 47627d5dc18SMarcel Moolenaar UART_SETSIG(sc, UART_SIG_DDTR | UART_SIG_DRTS); 47727d5dc18SMarcel Moolenaar 4788194412bSMarcel Moolenaar /* Disable pulse capturing. */ 4798194412bSMarcel Moolenaar sc->sc_pps.ppsparam.mode = 0; 4808194412bSMarcel Moolenaar 48127d5dc18SMarcel Moolenaar (*linesw[tp->t_line].l_close)(tp, flags); 48227d5dc18SMarcel Moolenaar ttyclose(tp); 48327d5dc18SMarcel Moolenaar wakeup(sc); 48427d5dc18SMarcel Moolenaar wakeup(TSA_CARR_ON(tp)); 48527d5dc18SMarcel Moolenaar KASSERT(!(tp->t_state & TS_ISOPEN), ("foo")); 48627d5dc18SMarcel Moolenaar sc->sc_opened = 0; 48727d5dc18SMarcel Moolenaar return (0); 48827d5dc18SMarcel Moolenaar } 48927d5dc18SMarcel Moolenaar 49027d5dc18SMarcel Moolenaar static int 49127d5dc18SMarcel Moolenaar uart_tty_ioctl(dev_t dev, u_long cmd, caddr_t data, int flags, 49227d5dc18SMarcel Moolenaar struct thread *td) 49327d5dc18SMarcel Moolenaar { 49427d5dc18SMarcel Moolenaar struct uart_softc *sc; 49527d5dc18SMarcel Moolenaar struct tty *tp; 49627d5dc18SMarcel Moolenaar int bits, error, sig; 49727d5dc18SMarcel Moolenaar 49827d5dc18SMarcel Moolenaar sc = dev->si_drv1; 49927d5dc18SMarcel Moolenaar if (sc == NULL || sc->sc_leaving) 50027d5dc18SMarcel Moolenaar return (ENODEV); 50127d5dc18SMarcel Moolenaar 50227d5dc18SMarcel Moolenaar tp = dev->si_tty; 50327d5dc18SMarcel Moolenaar error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flags, td); 50427d5dc18SMarcel Moolenaar if (error != ENOIOCTL) 50527d5dc18SMarcel Moolenaar return (error); 50627d5dc18SMarcel Moolenaar error = ttioctl(tp, cmd, data, flags); 50727d5dc18SMarcel Moolenaar if (error != ENOIOCTL) 50827d5dc18SMarcel Moolenaar return (error); 50927d5dc18SMarcel Moolenaar 5108194412bSMarcel Moolenaar error = 0; 51127d5dc18SMarcel Moolenaar switch (cmd) { 51227d5dc18SMarcel Moolenaar case TIOCSBRK: 51327d5dc18SMarcel Moolenaar UART_IOCTL(sc, UART_IOCTL_BREAK, 1); 51427d5dc18SMarcel Moolenaar break; 51527d5dc18SMarcel Moolenaar case TIOCCBRK: 51627d5dc18SMarcel Moolenaar UART_IOCTL(sc, UART_IOCTL_BREAK, 0); 51727d5dc18SMarcel Moolenaar break; 51827d5dc18SMarcel Moolenaar case TIOCSDTR: 51927d5dc18SMarcel Moolenaar UART_SETSIG(sc, UART_SIG_DDTR | UART_SIG_DTR); 52027d5dc18SMarcel Moolenaar break; 52127d5dc18SMarcel Moolenaar case TIOCCDTR: 52227d5dc18SMarcel Moolenaar UART_SETSIG(sc, UART_SIG_DDTR); 52327d5dc18SMarcel Moolenaar break; 52427d5dc18SMarcel Moolenaar case TIOCMSET: 52527d5dc18SMarcel Moolenaar bits = *(int*)data; 52627d5dc18SMarcel Moolenaar sig = UART_SIG_DDTR | UART_SIG_DRTS; 52727d5dc18SMarcel Moolenaar if (bits & TIOCM_DTR) 52827d5dc18SMarcel Moolenaar sig |= UART_SIG_DTR; 52927d5dc18SMarcel Moolenaar if (bits & TIOCM_RTS) 53027d5dc18SMarcel Moolenaar sig |= UART_SIG_RTS; 53127d5dc18SMarcel Moolenaar UART_SETSIG(sc, sig); 53227d5dc18SMarcel Moolenaar break; 53327d5dc18SMarcel Moolenaar case TIOCMBIS: 53427d5dc18SMarcel Moolenaar bits = *(int*)data; 53527d5dc18SMarcel Moolenaar sig = 0; 53627d5dc18SMarcel Moolenaar if (bits & TIOCM_DTR) 53727d5dc18SMarcel Moolenaar sig |= UART_SIG_DDTR | UART_SIG_DTR; 53827d5dc18SMarcel Moolenaar if (bits & TIOCM_RTS) 53927d5dc18SMarcel Moolenaar sig |= UART_SIG_DRTS | UART_SIG_RTS; 54027d5dc18SMarcel Moolenaar UART_SETSIG(sc, sig); 54127d5dc18SMarcel Moolenaar break; 54227d5dc18SMarcel Moolenaar case TIOCMBIC: 54327d5dc18SMarcel Moolenaar bits = *(int*)data; 54427d5dc18SMarcel Moolenaar sig = 0; 54527d5dc18SMarcel Moolenaar if (bits & TIOCM_DTR) 54627d5dc18SMarcel Moolenaar sig |= UART_SIG_DDTR; 54727d5dc18SMarcel Moolenaar if (bits & TIOCM_RTS) 54827d5dc18SMarcel Moolenaar sig |= UART_SIG_DRTS; 54927d5dc18SMarcel Moolenaar UART_SETSIG(sc, sig); 55027d5dc18SMarcel Moolenaar break; 55127d5dc18SMarcel Moolenaar case TIOCMGET: 55227d5dc18SMarcel Moolenaar sig = sc->sc_hwsig; 55327d5dc18SMarcel Moolenaar bits = TIOCM_LE; 55427d5dc18SMarcel Moolenaar if (sig & UART_SIG_DTR) 55527d5dc18SMarcel Moolenaar bits |= TIOCM_DTR; 55627d5dc18SMarcel Moolenaar if (sig & UART_SIG_RTS) 55727d5dc18SMarcel Moolenaar bits |= TIOCM_RTS; 55827d5dc18SMarcel Moolenaar if (sig & UART_SIG_DSR) 55927d5dc18SMarcel Moolenaar bits |= TIOCM_DSR; 56027d5dc18SMarcel Moolenaar if (sig & UART_SIG_CTS) 56127d5dc18SMarcel Moolenaar bits |= TIOCM_CTS; 56227d5dc18SMarcel Moolenaar if (sig & UART_SIG_DCD) 56327d5dc18SMarcel Moolenaar bits |= TIOCM_CD; 56427d5dc18SMarcel Moolenaar if (sig & (UART_SIG_DRI | UART_SIG_RI)) 56527d5dc18SMarcel Moolenaar bits |= TIOCM_RI; 56627d5dc18SMarcel Moolenaar *(int*)data = bits; 56727d5dc18SMarcel Moolenaar break; 56827d5dc18SMarcel Moolenaar default: 5698194412bSMarcel Moolenaar error = pps_ioctl(cmd, data, &sc->sc_pps); 5708194412bSMarcel Moolenaar if (error == ENODEV) 5718194412bSMarcel Moolenaar error = ENOTTY; 5728194412bSMarcel Moolenaar break; 57327d5dc18SMarcel Moolenaar } 5748194412bSMarcel Moolenaar return (error); 57527d5dc18SMarcel Moolenaar } 576