1bf21cd93STycho Nightingale /*- 24c87aefeSPatrick Mooney * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 34c87aefeSPatrick Mooney * 4bf21cd93STycho Nightingale * Copyright (c) 2012 NetApp, Inc. 5bf21cd93STycho Nightingale * Copyright (c) 2013 Neel Natu <neel@freebsd.org> 6bf21cd93STycho Nightingale * All rights reserved. 7bf21cd93STycho Nightingale * 8bf21cd93STycho Nightingale * Redistribution and use in source and binary forms, with or without 9bf21cd93STycho Nightingale * modification, are permitted provided that the following conditions 10bf21cd93STycho Nightingale * are met: 11bf21cd93STycho Nightingale * 1. Redistributions of source code must retain the above copyright 12bf21cd93STycho Nightingale * notice, this list of conditions and the following disclaimer. 13bf21cd93STycho Nightingale * 2. Redistributions in binary form must reproduce the above copyright 14bf21cd93STycho Nightingale * notice, this list of conditions and the following disclaimer in the 15bf21cd93STycho Nightingale * documentation and/or other materials provided with the distribution. 16bf21cd93STycho Nightingale * 17bf21cd93STycho Nightingale * THIS SOFTWARE IS PROVIDED BY NETAPP, INC ``AS IS'' AND 18bf21cd93STycho Nightingale * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19bf21cd93STycho Nightingale * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20bf21cd93STycho Nightingale * ARE DISCLAIMED. IN NO EVENT SHALL NETAPP, INC OR CONTRIBUTORS BE LIABLE 21bf21cd93STycho Nightingale * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22bf21cd93STycho Nightingale * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23bf21cd93STycho Nightingale * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24bf21cd93STycho Nightingale * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25bf21cd93STycho Nightingale * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26bf21cd93STycho Nightingale * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27bf21cd93STycho Nightingale * SUCH DAMAGE. 28bf21cd93STycho Nightingale * 294c87aefeSPatrick Mooney * $FreeBSD$ 304c87aefeSPatrick Mooney * 31bf21cd93STycho Nightingale */ 32bf21cd93STycho Nightingale /* 33bf21cd93STycho Nightingale * This file and its contents are supplied under the terms of the 34bf21cd93STycho Nightingale * Common Development and Distribution License ("CDDL"), version 1.0. 35bf21cd93STycho Nightingale * You may only use this file in accordance with the terms of version 36bf21cd93STycho Nightingale * 1.0 of the CDDL. 37bf21cd93STycho Nightingale * 38bf21cd93STycho Nightingale * A full copy of the text of the CDDL should have accompanied this 39bf21cd93STycho Nightingale * source. A copy of the CDDL is also available via the Internet at 40bf21cd93STycho Nightingale * http://www.illumos.org/license/CDDL. 41bf21cd93STycho Nightingale * 42bf21cd93STycho Nightingale * Copyright 2015 Pluribus Networks Inc. 434c87aefeSPatrick Mooney * Copyright 2018 Joyent, Inc. 44bf21cd93STycho Nightingale */ 45bf21cd93STycho Nightingale 46bf21cd93STycho Nightingale #include <sys/cdefs.h> 474c87aefeSPatrick Mooney __FBSDID("$FreeBSD$"); 48bf21cd93STycho Nightingale 49bf21cd93STycho Nightingale #include <sys/types.h> 50bf21cd93STycho Nightingale #include <dev/ic/ns16550.h> 514c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM 524c87aefeSPatrick Mooney #include <sys/capsicum.h> 534c87aefeSPatrick Mooney #include <capsicum_helpers.h> 54bf21cd93STycho Nightingale #endif 554c87aefeSPatrick Mooney 56bf21cd93STycho Nightingale #include <stdio.h> 57bf21cd93STycho Nightingale #include <stdlib.h> 58bf21cd93STycho Nightingale #include <assert.h> 594c87aefeSPatrick Mooney #include <err.h> 604c87aefeSPatrick Mooney #include <errno.h> 614c87aefeSPatrick Mooney #include <fcntl.h> 62bf21cd93STycho Nightingale #include <termios.h> 63bf21cd93STycho Nightingale #include <unistd.h> 64bf21cd93STycho Nightingale #include <stdbool.h> 65bf21cd93STycho Nightingale #include <string.h> 66bf21cd93STycho Nightingale #include <pthread.h> 674c87aefeSPatrick Mooney #include <sysexits.h> 68bf21cd93STycho Nightingale #ifndef __FreeBSD__ 694c87aefeSPatrick Mooney #include <sys/socket.h> 70bf21cd93STycho Nightingale #endif 71bf21cd93STycho Nightingale 72bf21cd93STycho Nightingale #include "mevent.h" 73bf21cd93STycho Nightingale #include "uart_emul.h" 74154972afSPatrick Mooney #include "debug.h" 75bf21cd93STycho Nightingale 76bf21cd93STycho Nightingale #define COM1_BASE 0x3F8 77bf21cd93STycho Nightingale #define COM1_IRQ 4 78bf21cd93STycho Nightingale #define COM2_BASE 0x2F8 79bf21cd93STycho Nightingale #define COM2_IRQ 3 802b948146SAndy Fiddaman #define COM3_BASE 0x3E8 812b948146SAndy Fiddaman #define COM3_IRQ 4 822b948146SAndy Fiddaman #define COM4_BASE 0x2E8 832b948146SAndy Fiddaman #define COM4_IRQ 3 84bf21cd93STycho Nightingale 85bf21cd93STycho Nightingale #define DEFAULT_RCLK 1843200 86bf21cd93STycho Nightingale #define DEFAULT_BAUD 9600 87bf21cd93STycho Nightingale 88bf21cd93STycho Nightingale #define FCR_RX_MASK 0xC0 89bf21cd93STycho Nightingale 90bf21cd93STycho Nightingale #define MCR_OUT1 0x04 91bf21cd93STycho Nightingale #define MCR_OUT2 0x08 92bf21cd93STycho Nightingale 93bf21cd93STycho Nightingale #define MSR_DELTA_MASK 0x0f 94bf21cd93STycho Nightingale 95bf21cd93STycho Nightingale #ifndef REG_SCR 96bf21cd93STycho Nightingale #define REG_SCR com_scr 97bf21cd93STycho Nightingale #endif 98bf21cd93STycho Nightingale 99bf21cd93STycho Nightingale #define FIFOSZ 16 100bf21cd93STycho Nightingale 101bf21cd93STycho Nightingale static bool uart_stdio; /* stdio in use for i/o */ 1024c87aefeSPatrick Mooney static struct termios tio_stdio_orig; 103bf21cd93STycho Nightingale 104bf21cd93STycho Nightingale static struct { 105bf21cd93STycho Nightingale int baseaddr; 106bf21cd93STycho Nightingale int irq; 107bf21cd93STycho Nightingale bool inuse; 108bf21cd93STycho Nightingale } uart_lres[] = { 109bf21cd93STycho Nightingale { COM1_BASE, COM1_IRQ, false}, 110bf21cd93STycho Nightingale { COM2_BASE, COM2_IRQ, false}, 1112b948146SAndy Fiddaman { COM3_BASE, COM3_IRQ, false}, 1122b948146SAndy Fiddaman { COM4_BASE, COM4_IRQ, false}, 113bf21cd93STycho Nightingale }; 114bf21cd93STycho Nightingale 115bf21cd93STycho Nightingale #define UART_NLDEVS (sizeof(uart_lres) / sizeof(uart_lres[0])) 116bf21cd93STycho Nightingale 117bf21cd93STycho Nightingale struct fifo { 118bf21cd93STycho Nightingale uint8_t buf[FIFOSZ]; 119bf21cd93STycho Nightingale int rindex; /* index to read from */ 120bf21cd93STycho Nightingale int windex; /* index to write to */ 121bf21cd93STycho Nightingale int num; /* number of characters in the fifo */ 122bf21cd93STycho Nightingale int size; /* size of the fifo */ 123bf21cd93STycho Nightingale }; 124bf21cd93STycho Nightingale 1254c87aefeSPatrick Mooney struct ttyfd { 1264c87aefeSPatrick Mooney bool opened; 1274c87aefeSPatrick Mooney int rfd; /* fd for reading */ 1284c87aefeSPatrick Mooney int wfd; /* fd for writing, may be == rfd */ 1294c87aefeSPatrick Mooney }; 1304c87aefeSPatrick Mooney 131bf21cd93STycho Nightingale struct uart_softc { 132bf21cd93STycho Nightingale pthread_mutex_t mtx; /* protects all softc elements */ 133bf21cd93STycho Nightingale uint8_t data; /* Data register (R/W) */ 134bf21cd93STycho Nightingale uint8_t ier; /* Interrupt enable register (R/W) */ 135bf21cd93STycho Nightingale uint8_t lcr; /* Line control register (R/W) */ 136bf21cd93STycho Nightingale uint8_t mcr; /* Modem control register (R/W) */ 137bf21cd93STycho Nightingale uint8_t lsr; /* Line status register (R/W) */ 138bf21cd93STycho Nightingale uint8_t msr; /* Modem status register (R/W) */ 139bf21cd93STycho Nightingale uint8_t fcr; /* FIFO control register (W) */ 140bf21cd93STycho Nightingale uint8_t scr; /* Scratch register (R/W) */ 141bf21cd93STycho Nightingale 142bf21cd93STycho Nightingale uint8_t dll; /* Baudrate divisor latch LSB */ 143bf21cd93STycho Nightingale uint8_t dlh; /* Baudrate divisor latch MSB */ 144bf21cd93STycho Nightingale 145bf21cd93STycho Nightingale struct fifo rxfifo; 1464c87aefeSPatrick Mooney struct mevent *mev; 147bf21cd93STycho Nightingale 1484c87aefeSPatrick Mooney struct ttyfd tty; 149bf21cd93STycho Nightingale #ifndef __FreeBSD__ 1504c87aefeSPatrick Mooney bool sock; 151bf21cd93STycho Nightingale struct { 152bf21cd93STycho Nightingale int clifd; /* console client unix domain socket */ 153bf21cd93STycho Nightingale int servfd; /* console server unix domain socket */ 1544c87aefeSPatrick Mooney struct mevent *servmev; /* mevent for server socket */ 1554c87aefeSPatrick Mooney } usc_sock; 156bf21cd93STycho Nightingale #endif 157bf21cd93STycho Nightingale 158bf21cd93STycho Nightingale bool thre_int_pending; /* THRE interrupt pending */ 159bf21cd93STycho Nightingale 160bf21cd93STycho Nightingale void *arg; 161bf21cd93STycho Nightingale uart_intr_func_t intr_assert; 162bf21cd93STycho Nightingale uart_intr_func_t intr_deassert; 163bf21cd93STycho Nightingale }; 164bf21cd93STycho Nightingale 165bf21cd93STycho Nightingale static void uart_drain(int fd, enum ev_type ev, void *arg); 166bf21cd93STycho Nightingale 167bf21cd93STycho Nightingale static void 168bf21cd93STycho Nightingale ttyclose(void) 169bf21cd93STycho Nightingale { 170bf21cd93STycho Nightingale 1714c87aefeSPatrick Mooney tcsetattr(STDIN_FILENO, TCSANOW, &tio_stdio_orig); 172bf21cd93STycho Nightingale } 173bf21cd93STycho Nightingale 174bf21cd93STycho Nightingale static void 1754c87aefeSPatrick Mooney ttyopen(struct ttyfd *tf) 176bf21cd93STycho Nightingale { 1774c87aefeSPatrick Mooney struct termios orig, new; 178bf21cd93STycho Nightingale 1794c87aefeSPatrick Mooney tcgetattr(tf->rfd, &orig); 1804c87aefeSPatrick Mooney new = orig; 1814c87aefeSPatrick Mooney cfmakeraw(&new); 1824c87aefeSPatrick Mooney new.c_cflag |= CLOCAL; 1834c87aefeSPatrick Mooney tcsetattr(tf->rfd, TCSANOW, &new); 1844c87aefeSPatrick Mooney if (uart_stdio) { 1854c87aefeSPatrick Mooney tio_stdio_orig = orig; 186bf21cd93STycho Nightingale atexit(ttyclose); 187bf21cd93STycho Nightingale } 188154972afSPatrick Mooney raw_stdio = 1; 189bf21cd93STycho Nightingale } 190bf21cd93STycho Nightingale 191bf21cd93STycho Nightingale static int 1924c87aefeSPatrick Mooney ttyread(struct ttyfd *tf) 193bf21cd93STycho Nightingale { 1944c87aefeSPatrick Mooney unsigned char rb; 195bf21cd93STycho Nightingale 1964c87aefeSPatrick Mooney if (read(tf->rfd, &rb, 1) == 1) 1974c87aefeSPatrick Mooney return (rb); 1984c87aefeSPatrick Mooney else 199bf21cd93STycho Nightingale return (-1); 200bf21cd93STycho Nightingale } 201bf21cd93STycho Nightingale 202bf21cd93STycho Nightingale static void 2034c87aefeSPatrick Mooney ttywrite(struct ttyfd *tf, unsigned char wb) 204bf21cd93STycho Nightingale { 205bf21cd93STycho Nightingale 2064c87aefeSPatrick Mooney (void)write(tf->wfd, &wb, 1); 207bf21cd93STycho Nightingale } 208bf21cd93STycho Nightingale 209bf21cd93STycho Nightingale #ifndef __FreeBSD__ 210bf21cd93STycho Nightingale static void 2114c87aefeSPatrick Mooney sockwrite(struct uart_softc *sc, unsigned char wb) 212bf21cd93STycho Nightingale { 2134c87aefeSPatrick Mooney (void) write(sc->usc_sock.clifd, &wb, 1); 214bf21cd93STycho Nightingale } 215bf21cd93STycho Nightingale #endif 216bf21cd93STycho Nightingale 217bf21cd93STycho Nightingale static void 2184c87aefeSPatrick Mooney rxfifo_reset(struct uart_softc *sc, int size) 219bf21cd93STycho Nightingale { 2204c87aefeSPatrick Mooney char flushbuf[32]; 2214c87aefeSPatrick Mooney struct fifo *fifo; 2224c87aefeSPatrick Mooney ssize_t nread; 2234c87aefeSPatrick Mooney int error; 2244c87aefeSPatrick Mooney 2254c87aefeSPatrick Mooney fifo = &sc->rxfifo; 226bf21cd93STycho Nightingale bzero(fifo, sizeof(struct fifo)); 227bf21cd93STycho Nightingale fifo->size = size; 2284c87aefeSPatrick Mooney 2294c87aefeSPatrick Mooney if (sc->tty.opened) { 2304c87aefeSPatrick Mooney /* 2314c87aefeSPatrick Mooney * Flush any unread input from the tty buffer. 2324c87aefeSPatrick Mooney */ 2334c87aefeSPatrick Mooney while (1) { 2344c87aefeSPatrick Mooney nread = read(sc->tty.rfd, flushbuf, sizeof(flushbuf)); 2354c87aefeSPatrick Mooney if (nread != sizeof(flushbuf)) 2364c87aefeSPatrick Mooney break; 2374c87aefeSPatrick Mooney } 2384c87aefeSPatrick Mooney 2394c87aefeSPatrick Mooney /* 2404c87aefeSPatrick Mooney * Enable mevent to trigger when new characters are available 2414c87aefeSPatrick Mooney * on the tty fd. 2424c87aefeSPatrick Mooney */ 2434c87aefeSPatrick Mooney error = mevent_enable(sc->mev); 2444c87aefeSPatrick Mooney assert(error == 0); 2454c87aefeSPatrick Mooney } 2464c87aefeSPatrick Mooney #ifndef __FreeBSD__ 2474c87aefeSPatrick Mooney if (sc->sock && sc->usc_sock.clifd != -1) { 2484c87aefeSPatrick Mooney /* Flush any unread input from the socket buffer. */ 2494c87aefeSPatrick Mooney do { 2504c87aefeSPatrick Mooney nread = read(sc->usc_sock.clifd, flushbuf, 2514c87aefeSPatrick Mooney sizeof (flushbuf)); 2524c87aefeSPatrick Mooney } while (nread == sizeof (flushbuf)); 2534c87aefeSPatrick Mooney 2544c87aefeSPatrick Mooney /* Enable mevent to trigger when new data available on sock */ 2554c87aefeSPatrick Mooney error = mevent_enable(sc->mev); 2564c87aefeSPatrick Mooney assert(error == 0); 2574c87aefeSPatrick Mooney } 2584c87aefeSPatrick Mooney #endif /* __FreeBSD__ */ 259bf21cd93STycho Nightingale } 260bf21cd93STycho Nightingale 261bf21cd93STycho Nightingale static int 2624c87aefeSPatrick Mooney rxfifo_available(struct uart_softc *sc) 263bf21cd93STycho Nightingale { 2644c87aefeSPatrick Mooney struct fifo *fifo; 2654c87aefeSPatrick Mooney 2664c87aefeSPatrick Mooney fifo = &sc->rxfifo; 2674c87aefeSPatrick Mooney return (fifo->num < fifo->size); 2684c87aefeSPatrick Mooney } 2694c87aefeSPatrick Mooney 2704c87aefeSPatrick Mooney static int 2714c87aefeSPatrick Mooney rxfifo_putchar(struct uart_softc *sc, uint8_t ch) 2724c87aefeSPatrick Mooney { 2734c87aefeSPatrick Mooney struct fifo *fifo; 2744c87aefeSPatrick Mooney int error; 2754c87aefeSPatrick Mooney 2764c87aefeSPatrick Mooney fifo = &sc->rxfifo; 277bf21cd93STycho Nightingale 278bf21cd93STycho Nightingale if (fifo->num < fifo->size) { 279bf21cd93STycho Nightingale fifo->buf[fifo->windex] = ch; 280bf21cd93STycho Nightingale fifo->windex = (fifo->windex + 1) % fifo->size; 281bf21cd93STycho Nightingale fifo->num++; 2824c87aefeSPatrick Mooney if (!rxfifo_available(sc)) { 2834c87aefeSPatrick Mooney if (sc->tty.opened) { 2844c87aefeSPatrick Mooney /* 2854c87aefeSPatrick Mooney * Disable mevent callback if the FIFO is full. 2864c87aefeSPatrick Mooney */ 2874c87aefeSPatrick Mooney error = mevent_disable(sc->mev); 2884c87aefeSPatrick Mooney assert(error == 0); 2894c87aefeSPatrick Mooney } 2904c87aefeSPatrick Mooney #ifndef __FreeBSD__ 2914c87aefeSPatrick Mooney if (sc->sock && sc->usc_sock.clifd != -1) { 2924c87aefeSPatrick Mooney /* 2934c87aefeSPatrick Mooney * Disable mevent callback if the FIFO is full. 2944c87aefeSPatrick Mooney */ 2954c87aefeSPatrick Mooney error = mevent_disable(sc->mev); 2964c87aefeSPatrick Mooney assert(error == 0); 2974c87aefeSPatrick Mooney } 2984c87aefeSPatrick Mooney #endif /* __FreeBSD__ */ 2994c87aefeSPatrick Mooney } 300bf21cd93STycho Nightingale return (0); 301bf21cd93STycho Nightingale } else 302bf21cd93STycho Nightingale return (-1); 303bf21cd93STycho Nightingale } 304bf21cd93STycho Nightingale 305bf21cd93STycho Nightingale static int 3064c87aefeSPatrick Mooney rxfifo_getchar(struct uart_softc *sc) 307bf21cd93STycho Nightingale { 3084c87aefeSPatrick Mooney struct fifo *fifo; 3094c87aefeSPatrick Mooney int c, error, wasfull; 310bf21cd93STycho Nightingale 3114c87aefeSPatrick Mooney wasfull = 0; 3124c87aefeSPatrick Mooney fifo = &sc->rxfifo; 313bf21cd93STycho Nightingale if (fifo->num > 0) { 3144c87aefeSPatrick Mooney if (!rxfifo_available(sc)) 3154c87aefeSPatrick Mooney wasfull = 1; 316bf21cd93STycho Nightingale c = fifo->buf[fifo->rindex]; 317bf21cd93STycho Nightingale fifo->rindex = (fifo->rindex + 1) % fifo->size; 318bf21cd93STycho Nightingale fifo->num--; 3194c87aefeSPatrick Mooney if (wasfull) { 3204c87aefeSPatrick Mooney if (sc->tty.opened) { 3214c87aefeSPatrick Mooney error = mevent_enable(sc->mev); 3224c87aefeSPatrick Mooney assert(error == 0); 3234c87aefeSPatrick Mooney } 3244c87aefeSPatrick Mooney #ifndef __FreeBSD__ 3254c87aefeSPatrick Mooney if (sc->sock && sc->usc_sock.clifd != -1) { 3264c87aefeSPatrick Mooney error = mevent_enable(sc->mev); 3274c87aefeSPatrick Mooney assert(error == 0); 3284c87aefeSPatrick Mooney } 3294c87aefeSPatrick Mooney #endif /* __FreeBSD__ */ 3304c87aefeSPatrick Mooney } 331bf21cd93STycho Nightingale return (c); 332bf21cd93STycho Nightingale } else 333bf21cd93STycho Nightingale return (-1); 334bf21cd93STycho Nightingale } 335bf21cd93STycho Nightingale 336bf21cd93STycho Nightingale static int 3374c87aefeSPatrick Mooney rxfifo_numchars(struct uart_softc *sc) 338bf21cd93STycho Nightingale { 3394c87aefeSPatrick Mooney struct fifo *fifo = &sc->rxfifo; 340bf21cd93STycho Nightingale 341bf21cd93STycho Nightingale return (fifo->num); 342bf21cd93STycho Nightingale } 343bf21cd93STycho Nightingale 344bf21cd93STycho Nightingale static void 345bf21cd93STycho Nightingale uart_opentty(struct uart_softc *sc) 346bf21cd93STycho Nightingale { 347bf21cd93STycho Nightingale 3484c87aefeSPatrick Mooney ttyopen(&sc->tty); 3494c87aefeSPatrick Mooney sc->mev = mevent_add(sc->tty.rfd, EVF_READ, uart_drain, sc); 3504c87aefeSPatrick Mooney assert(sc->mev != NULL); 3514c87aefeSPatrick Mooney } 352bf21cd93STycho Nightingale 3534c87aefeSPatrick Mooney static uint8_t 3544c87aefeSPatrick Mooney modem_status(uint8_t mcr) 3554c87aefeSPatrick Mooney { 3564c87aefeSPatrick Mooney uint8_t msr; 3574c87aefeSPatrick Mooney 3584c87aefeSPatrick Mooney if (mcr & MCR_LOOPBACK) { 3594c87aefeSPatrick Mooney /* 3604c87aefeSPatrick Mooney * In the loopback mode certain bits from the MCR are 3614c87aefeSPatrick Mooney * reflected back into MSR. 3624c87aefeSPatrick Mooney */ 3634c87aefeSPatrick Mooney msr = 0; 3644c87aefeSPatrick Mooney if (mcr & MCR_RTS) 3654c87aefeSPatrick Mooney msr |= MSR_CTS; 3664c87aefeSPatrick Mooney if (mcr & MCR_DTR) 3674c87aefeSPatrick Mooney msr |= MSR_DSR; 3684c87aefeSPatrick Mooney if (mcr & MCR_OUT1) 3694c87aefeSPatrick Mooney msr |= MSR_RI; 3704c87aefeSPatrick Mooney if (mcr & MCR_OUT2) 3714c87aefeSPatrick Mooney msr |= MSR_DCD; 3724c87aefeSPatrick Mooney } else { 3734c87aefeSPatrick Mooney /* 3744c87aefeSPatrick Mooney * Always assert DCD and DSR so tty open doesn't block 3754c87aefeSPatrick Mooney * even if CLOCAL is turned off. 3764c87aefeSPatrick Mooney */ 3774c87aefeSPatrick Mooney msr = MSR_DCD | MSR_DSR; 3784c87aefeSPatrick Mooney } 3794c87aefeSPatrick Mooney assert((msr & MSR_DELTA_MASK) == 0); 3804c87aefeSPatrick Mooney 3814c87aefeSPatrick Mooney return (msr); 382bf21cd93STycho Nightingale } 383bf21cd93STycho Nightingale 384bf21cd93STycho Nightingale /* 385bf21cd93STycho Nightingale * The IIR returns a prioritized interrupt reason: 386bf21cd93STycho Nightingale * - receive data available 387bf21cd93STycho Nightingale * - transmit holding register empty 388bf21cd93STycho Nightingale * - modem status change 389bf21cd93STycho Nightingale * 390bf21cd93STycho Nightingale * Return an interrupt reason if one is available. 391bf21cd93STycho Nightingale */ 392bf21cd93STycho Nightingale static int 393bf21cd93STycho Nightingale uart_intr_reason(struct uart_softc *sc) 394bf21cd93STycho Nightingale { 395bf21cd93STycho Nightingale 396bf21cd93STycho Nightingale if ((sc->lsr & LSR_OE) != 0 && (sc->ier & IER_ERLS) != 0) 397bf21cd93STycho Nightingale return (IIR_RLS); 3984c87aefeSPatrick Mooney else if (rxfifo_numchars(sc) > 0 && (sc->ier & IER_ERXRDY) != 0) 399bf21cd93STycho Nightingale return (IIR_RXTOUT); 400bf21cd93STycho Nightingale else if (sc->thre_int_pending && (sc->ier & IER_ETXRDY) != 0) 401bf21cd93STycho Nightingale return (IIR_TXRDY); 402bf21cd93STycho Nightingale else if ((sc->msr & MSR_DELTA_MASK) != 0 && (sc->ier & IER_EMSC) != 0) 403bf21cd93STycho Nightingale return (IIR_MLSC); 404bf21cd93STycho Nightingale else 405bf21cd93STycho Nightingale return (IIR_NOPEND); 406bf21cd93STycho Nightingale } 407bf21cd93STycho Nightingale 408bf21cd93STycho Nightingale static void 409bf21cd93STycho Nightingale uart_reset(struct uart_softc *sc) 410bf21cd93STycho Nightingale { 411bf21cd93STycho Nightingale uint16_t divisor; 412bf21cd93STycho Nightingale 413bf21cd93STycho Nightingale divisor = DEFAULT_RCLK / DEFAULT_BAUD / 16; 414bf21cd93STycho Nightingale sc->dll = divisor; 4154c87aefeSPatrick Mooney #ifndef __FreeBSD__ 4164c87aefeSPatrick Mooney sc->dlh = 0; 4174c87aefeSPatrick Mooney #else 418bf21cd93STycho Nightingale sc->dlh = divisor >> 16; 4194c87aefeSPatrick Mooney #endif 4204c87aefeSPatrick Mooney sc->msr = modem_status(sc->mcr); 421bf21cd93STycho Nightingale 4224c87aefeSPatrick Mooney rxfifo_reset(sc, 1); /* no fifo until enabled by software */ 423bf21cd93STycho Nightingale } 424bf21cd93STycho Nightingale 425bf21cd93STycho Nightingale /* 426bf21cd93STycho Nightingale * Toggle the COM port's intr pin depending on whether or not we have an 427bf21cd93STycho Nightingale * interrupt condition to report to the processor. 428bf21cd93STycho Nightingale */ 429bf21cd93STycho Nightingale static void 430bf21cd93STycho Nightingale uart_toggle_intr(struct uart_softc *sc) 431bf21cd93STycho Nightingale { 432bf21cd93STycho Nightingale uint8_t intr_reason; 433bf21cd93STycho Nightingale 434bf21cd93STycho Nightingale intr_reason = uart_intr_reason(sc); 435bf21cd93STycho Nightingale 436bf21cd93STycho Nightingale if (intr_reason == IIR_NOPEND) 437bf21cd93STycho Nightingale (*sc->intr_deassert)(sc->arg); 438bf21cd93STycho Nightingale else 439bf21cd93STycho Nightingale (*sc->intr_assert)(sc->arg); 440bf21cd93STycho Nightingale } 441bf21cd93STycho Nightingale 442bf21cd93STycho Nightingale static void 443bf21cd93STycho Nightingale uart_drain(int fd, enum ev_type ev, void *arg) 444bf21cd93STycho Nightingale { 445bf21cd93STycho Nightingale struct uart_softc *sc; 446bf21cd93STycho Nightingale int ch; 447bf21cd93STycho Nightingale 448bf21cd93STycho Nightingale sc = arg; 449bf21cd93STycho Nightingale 4504c87aefeSPatrick Mooney assert(fd == sc->tty.rfd); 451bf21cd93STycho Nightingale assert(ev == EVF_READ); 452bf21cd93STycho Nightingale 453bf21cd93STycho Nightingale /* 454bf21cd93STycho Nightingale * This routine is called in the context of the mevent thread 455bf21cd93STycho Nightingale * to take out the softc lock to protect against concurrent 456bf21cd93STycho Nightingale * access from a vCPU i/o exit 457bf21cd93STycho Nightingale */ 458bf21cd93STycho Nightingale pthread_mutex_lock(&sc->mtx); 459bf21cd93STycho Nightingale 460bf21cd93STycho Nightingale if ((sc->mcr & MCR_LOOPBACK) != 0) { 4614c87aefeSPatrick Mooney (void) ttyread(&sc->tty); 462bf21cd93STycho Nightingale } else { 4634c87aefeSPatrick Mooney while (rxfifo_available(sc) && 4644c87aefeSPatrick Mooney ((ch = ttyread(&sc->tty)) != -1)) { 4654c87aefeSPatrick Mooney rxfifo_putchar(sc, ch); 466bf21cd93STycho Nightingale } 467bf21cd93STycho Nightingale uart_toggle_intr(sc); 468bf21cd93STycho Nightingale } 469bf21cd93STycho Nightingale 470bf21cd93STycho Nightingale pthread_mutex_unlock(&sc->mtx); 471bf21cd93STycho Nightingale } 472bf21cd93STycho Nightingale 473bf21cd93STycho Nightingale void 474bf21cd93STycho Nightingale uart_write(struct uart_softc *sc, int offset, uint8_t value) 475bf21cd93STycho Nightingale { 476bf21cd93STycho Nightingale int fifosz; 477bf21cd93STycho Nightingale uint8_t msr; 478bf21cd93STycho Nightingale 479bf21cd93STycho Nightingale pthread_mutex_lock(&sc->mtx); 480bf21cd93STycho Nightingale 481bf21cd93STycho Nightingale /* 482bf21cd93STycho Nightingale * Take care of the special case DLAB accesses first 483bf21cd93STycho Nightingale */ 484bf21cd93STycho Nightingale if ((sc->lcr & LCR_DLAB) != 0) { 485bf21cd93STycho Nightingale if (offset == REG_DLL) { 486bf21cd93STycho Nightingale sc->dll = value; 487bf21cd93STycho Nightingale goto done; 488bf21cd93STycho Nightingale } 489bf21cd93STycho Nightingale 490bf21cd93STycho Nightingale if (offset == REG_DLH) { 491bf21cd93STycho Nightingale sc->dlh = value; 492bf21cd93STycho Nightingale goto done; 493bf21cd93STycho Nightingale } 494bf21cd93STycho Nightingale } 495bf21cd93STycho Nightingale 496bf21cd93STycho Nightingale switch (offset) { 497bf21cd93STycho Nightingale case REG_DATA: 498bf21cd93STycho Nightingale if (sc->mcr & MCR_LOOPBACK) { 4994c87aefeSPatrick Mooney if (rxfifo_putchar(sc, value) != 0) 500bf21cd93STycho Nightingale sc->lsr |= LSR_OE; 5014c87aefeSPatrick Mooney } else if (sc->tty.opened) { 5024c87aefeSPatrick Mooney ttywrite(&sc->tty, value); 503bf21cd93STycho Nightingale #ifndef __FreeBSD__ 5044c87aefeSPatrick Mooney } else if (sc->sock) { 5054c87aefeSPatrick Mooney sockwrite(sc, value); 506bf21cd93STycho Nightingale #endif 507bf21cd93STycho Nightingale } /* else drop on floor */ 508bf21cd93STycho Nightingale sc->thre_int_pending = true; 509bf21cd93STycho Nightingale break; 510bf21cd93STycho Nightingale case REG_IER: 5114c87aefeSPatrick Mooney /* Set pending when IER_ETXRDY is raised (edge-triggered). */ 5124c87aefeSPatrick Mooney if ((sc->ier & IER_ETXRDY) == 0 && (value & IER_ETXRDY) != 0) 5134c87aefeSPatrick Mooney sc->thre_int_pending = true; 514bf21cd93STycho Nightingale /* 515bf21cd93STycho Nightingale * Apply mask so that bits 4-7 are 0 516bf21cd93STycho Nightingale * Also enables bits 0-3 only if they're 1 517bf21cd93STycho Nightingale */ 518bf21cd93STycho Nightingale sc->ier = value & 0x0F; 519bf21cd93STycho Nightingale break; 520bf21cd93STycho Nightingale case REG_FCR: 521bf21cd93STycho Nightingale /* 522bf21cd93STycho Nightingale * When moving from FIFO and 16450 mode and vice versa, 523bf21cd93STycho Nightingale * the FIFO contents are reset. 524bf21cd93STycho Nightingale */ 525bf21cd93STycho Nightingale if ((sc->fcr & FCR_ENABLE) ^ (value & FCR_ENABLE)) { 526bf21cd93STycho Nightingale fifosz = (value & FCR_ENABLE) ? FIFOSZ : 1; 5274c87aefeSPatrick Mooney rxfifo_reset(sc, fifosz); 528bf21cd93STycho Nightingale } 529bf21cd93STycho Nightingale 530bf21cd93STycho Nightingale /* 531bf21cd93STycho Nightingale * The FCR_ENABLE bit must be '1' for the programming 532bf21cd93STycho Nightingale * of other FCR bits to be effective. 533bf21cd93STycho Nightingale */ 534bf21cd93STycho Nightingale if ((value & FCR_ENABLE) == 0) { 535bf21cd93STycho Nightingale sc->fcr = 0; 536bf21cd93STycho Nightingale } else { 537bf21cd93STycho Nightingale if ((value & FCR_RCV_RST) != 0) 5384c87aefeSPatrick Mooney rxfifo_reset(sc, FIFOSZ); 539bf21cd93STycho Nightingale 540bf21cd93STycho Nightingale sc->fcr = value & 541bf21cd93STycho Nightingale (FCR_ENABLE | FCR_DMA | FCR_RX_MASK); 542bf21cd93STycho Nightingale } 543bf21cd93STycho Nightingale break; 544bf21cd93STycho Nightingale case REG_LCR: 545bf21cd93STycho Nightingale sc->lcr = value; 546bf21cd93STycho Nightingale break; 547bf21cd93STycho Nightingale case REG_MCR: 548bf21cd93STycho Nightingale /* Apply mask so that bits 5-7 are 0 */ 549bf21cd93STycho Nightingale sc->mcr = value & 0x1F; 5504c87aefeSPatrick Mooney msr = modem_status(sc->mcr); 551bf21cd93STycho Nightingale 552bf21cd93STycho Nightingale /* 553bf21cd93STycho Nightingale * Detect if there has been any change between the 554bf21cd93STycho Nightingale * previous and the new value of MSR. If there is 555bf21cd93STycho Nightingale * then assert the appropriate MSR delta bit. 556bf21cd93STycho Nightingale */ 557bf21cd93STycho Nightingale if ((msr & MSR_CTS) ^ (sc->msr & MSR_CTS)) 558bf21cd93STycho Nightingale sc->msr |= MSR_DCTS; 559bf21cd93STycho Nightingale if ((msr & MSR_DSR) ^ (sc->msr & MSR_DSR)) 560bf21cd93STycho Nightingale sc->msr |= MSR_DDSR; 561bf21cd93STycho Nightingale if ((msr & MSR_DCD) ^ (sc->msr & MSR_DCD)) 562bf21cd93STycho Nightingale sc->msr |= MSR_DDCD; 563bf21cd93STycho Nightingale if ((sc->msr & MSR_RI) != 0 && (msr & MSR_RI) == 0) 564bf21cd93STycho Nightingale sc->msr |= MSR_TERI; 565bf21cd93STycho Nightingale 566bf21cd93STycho Nightingale /* 567bf21cd93STycho Nightingale * Update the value of MSR while retaining the delta 568bf21cd93STycho Nightingale * bits. 569bf21cd93STycho Nightingale */ 570bf21cd93STycho Nightingale sc->msr &= MSR_DELTA_MASK; 571bf21cd93STycho Nightingale sc->msr |= msr; 572bf21cd93STycho Nightingale break; 573bf21cd93STycho Nightingale case REG_LSR: 574bf21cd93STycho Nightingale /* 575bf21cd93STycho Nightingale * Line status register is not meant to be written to 576bf21cd93STycho Nightingale * during normal operation. 577bf21cd93STycho Nightingale */ 578bf21cd93STycho Nightingale break; 579bf21cd93STycho Nightingale case REG_MSR: 580bf21cd93STycho Nightingale /* 581bf21cd93STycho Nightingale * As far as I can tell MSR is a read-only register. 582bf21cd93STycho Nightingale */ 583bf21cd93STycho Nightingale break; 584bf21cd93STycho Nightingale case REG_SCR: 585bf21cd93STycho Nightingale sc->scr = value; 586bf21cd93STycho Nightingale break; 587bf21cd93STycho Nightingale default: 588bf21cd93STycho Nightingale break; 589bf21cd93STycho Nightingale } 590bf21cd93STycho Nightingale 591bf21cd93STycho Nightingale done: 592bf21cd93STycho Nightingale uart_toggle_intr(sc); 593bf21cd93STycho Nightingale pthread_mutex_unlock(&sc->mtx); 594bf21cd93STycho Nightingale } 595bf21cd93STycho Nightingale 596bf21cd93STycho Nightingale uint8_t 597bf21cd93STycho Nightingale uart_read(struct uart_softc *sc, int offset) 598bf21cd93STycho Nightingale { 599bf21cd93STycho Nightingale uint8_t iir, intr_reason, reg; 600bf21cd93STycho Nightingale 601bf21cd93STycho Nightingale pthread_mutex_lock(&sc->mtx); 602bf21cd93STycho Nightingale 603bf21cd93STycho Nightingale /* 604bf21cd93STycho Nightingale * Take care of the special case DLAB accesses first 605bf21cd93STycho Nightingale */ 606bf21cd93STycho Nightingale if ((sc->lcr & LCR_DLAB) != 0) { 607bf21cd93STycho Nightingale if (offset == REG_DLL) { 608bf21cd93STycho Nightingale reg = sc->dll; 609bf21cd93STycho Nightingale goto done; 610bf21cd93STycho Nightingale } 611bf21cd93STycho Nightingale 612bf21cd93STycho Nightingale if (offset == REG_DLH) { 613bf21cd93STycho Nightingale reg = sc->dlh; 614bf21cd93STycho Nightingale goto done; 615bf21cd93STycho Nightingale } 616bf21cd93STycho Nightingale } 617bf21cd93STycho Nightingale 618bf21cd93STycho Nightingale switch (offset) { 619bf21cd93STycho Nightingale case REG_DATA: 6204c87aefeSPatrick Mooney reg = rxfifo_getchar(sc); 621bf21cd93STycho Nightingale break; 622bf21cd93STycho Nightingale case REG_IER: 623bf21cd93STycho Nightingale reg = sc->ier; 624bf21cd93STycho Nightingale break; 625bf21cd93STycho Nightingale case REG_IIR: 626bf21cd93STycho Nightingale iir = (sc->fcr & FCR_ENABLE) ? IIR_FIFO_MASK : 0; 627bf21cd93STycho Nightingale 628bf21cd93STycho Nightingale intr_reason = uart_intr_reason(sc); 629bf21cd93STycho Nightingale 630bf21cd93STycho Nightingale /* 631bf21cd93STycho Nightingale * Deal with side effects of reading the IIR register 632bf21cd93STycho Nightingale */ 633bf21cd93STycho Nightingale if (intr_reason == IIR_TXRDY) 634bf21cd93STycho Nightingale sc->thre_int_pending = false; 635bf21cd93STycho Nightingale 636bf21cd93STycho Nightingale iir |= intr_reason; 637bf21cd93STycho Nightingale 638bf21cd93STycho Nightingale reg = iir; 639bf21cd93STycho Nightingale break; 640bf21cd93STycho Nightingale case REG_LCR: 641bf21cd93STycho Nightingale reg = sc->lcr; 642bf21cd93STycho Nightingale break; 643bf21cd93STycho Nightingale case REG_MCR: 644bf21cd93STycho Nightingale reg = sc->mcr; 645bf21cd93STycho Nightingale break; 646bf21cd93STycho Nightingale case REG_LSR: 647bf21cd93STycho Nightingale /* Transmitter is always ready for more data */ 648bf21cd93STycho Nightingale sc->lsr |= LSR_TEMT | LSR_THRE; 649bf21cd93STycho Nightingale 650bf21cd93STycho Nightingale /* Check for new receive data */ 6514c87aefeSPatrick Mooney if (rxfifo_numchars(sc) > 0) 652bf21cd93STycho Nightingale sc->lsr |= LSR_RXRDY; 653bf21cd93STycho Nightingale else 654bf21cd93STycho Nightingale sc->lsr &= ~LSR_RXRDY; 655bf21cd93STycho Nightingale 656bf21cd93STycho Nightingale reg = sc->lsr; 657bf21cd93STycho Nightingale 658bf21cd93STycho Nightingale /* The LSR_OE bit is cleared on LSR read */ 659bf21cd93STycho Nightingale sc->lsr &= ~LSR_OE; 660bf21cd93STycho Nightingale break; 661bf21cd93STycho Nightingale case REG_MSR: 662bf21cd93STycho Nightingale /* 663bf21cd93STycho Nightingale * MSR delta bits are cleared on read 664bf21cd93STycho Nightingale */ 665bf21cd93STycho Nightingale reg = sc->msr; 666bf21cd93STycho Nightingale sc->msr &= ~MSR_DELTA_MASK; 667bf21cd93STycho Nightingale break; 668bf21cd93STycho Nightingale case REG_SCR: 669bf21cd93STycho Nightingale reg = sc->scr; 670bf21cd93STycho Nightingale break; 671bf21cd93STycho Nightingale default: 672bf21cd93STycho Nightingale reg = 0xFF; 673bf21cd93STycho Nightingale break; 674bf21cd93STycho Nightingale } 675bf21cd93STycho Nightingale 676bf21cd93STycho Nightingale done: 677bf21cd93STycho Nightingale uart_toggle_intr(sc); 678bf21cd93STycho Nightingale pthread_mutex_unlock(&sc->mtx); 679bf21cd93STycho Nightingale 680bf21cd93STycho Nightingale return (reg); 681bf21cd93STycho Nightingale } 682bf21cd93STycho Nightingale 683bf21cd93STycho Nightingale #ifndef __FreeBSD__ 684bf21cd93STycho Nightingale static void 6854c87aefeSPatrick Mooney uart_sock_drain(int fd, enum ev_type ev, void *arg) 686bf21cd93STycho Nightingale { 6874c87aefeSPatrick Mooney struct uart_softc *sc = arg; 6884c87aefeSPatrick Mooney char ch; 689bf21cd93STycho Nightingale 690bf21cd93STycho Nightingale /* 6914c87aefeSPatrick Mooney * Take the softc lock to protect against concurrent 6924c87aefeSPatrick Mooney * access from a vCPU i/o exit 693bf21cd93STycho Nightingale */ 6944c87aefeSPatrick Mooney pthread_mutex_lock(&sc->mtx); 695bf21cd93STycho Nightingale 6964c87aefeSPatrick Mooney if ((sc->mcr & MCR_LOOPBACK) != 0) { 6974c87aefeSPatrick Mooney (void) read(sc->usc_sock.clifd, &ch, 1); 6984c87aefeSPatrick Mooney } else { 6994c87aefeSPatrick Mooney bool err_close = false; 7004c87aefeSPatrick Mooney 7014c87aefeSPatrick Mooney while (rxfifo_available(sc)) { 702bf21cd93STycho Nightingale int res; 703bf21cd93STycho Nightingale 7044c87aefeSPatrick Mooney res = read(sc->usc_sock.clifd, &ch, 1); 7054c87aefeSPatrick Mooney if (res == 0) { 7064c87aefeSPatrick Mooney err_close = true; 7074c87aefeSPatrick Mooney break; 7084c87aefeSPatrick Mooney } else if (res == -1) { 7094c87aefeSPatrick Mooney if (errno != EAGAIN && errno != EINTR) { 7104c87aefeSPatrick Mooney err_close = true; 7114c87aefeSPatrick Mooney } 7124c87aefeSPatrick Mooney break; 713bf21cd93STycho Nightingale } 714bf21cd93STycho Nightingale 7154c87aefeSPatrick Mooney rxfifo_putchar(sc, ch); 7164c87aefeSPatrick Mooney } 7174c87aefeSPatrick Mooney uart_toggle_intr(sc); 7184c87aefeSPatrick Mooney 7194c87aefeSPatrick Mooney if (err_close) { 7204c87aefeSPatrick Mooney (void) fprintf(stderr, "uart: closing client conn\n"); 7214c87aefeSPatrick Mooney (void) shutdown(sc->usc_sock.clifd, SHUT_RDWR); 7224c87aefeSPatrick Mooney mevent_delete_close(sc->mev); 7234c87aefeSPatrick Mooney sc->mev = NULL; 7244c87aefeSPatrick Mooney sc->usc_sock.clifd = -1; 7254c87aefeSPatrick Mooney } 7264c87aefeSPatrick Mooney } 7274c87aefeSPatrick Mooney 7284c87aefeSPatrick Mooney pthread_mutex_unlock(&sc->mtx); 729bf21cd93STycho Nightingale } 730bf21cd93STycho Nightingale 731bf21cd93STycho Nightingale static void 7324c87aefeSPatrick Mooney uart_sock_accept(int fd, enum ev_type ev, void *arg) 733bf21cd93STycho Nightingale { 7344c87aefeSPatrick Mooney struct uart_softc *sc = arg; 7354c87aefeSPatrick Mooney int connfd; 736bf21cd93STycho Nightingale 7374c87aefeSPatrick Mooney connfd = accept(sc->usc_sock.servfd, NULL, NULL); 7384c87aefeSPatrick Mooney if (connfd == -1) { 739bf21cd93STycho Nightingale return; 740bf21cd93STycho Nightingale } 741bf21cd93STycho Nightingale 7424c87aefeSPatrick Mooney /* 7434c87aefeSPatrick Mooney * Do client connection management under protection of the softc lock 7444c87aefeSPatrick Mooney * to avoid racing with concurrent UART events. 7454c87aefeSPatrick Mooney */ 7464c87aefeSPatrick Mooney pthread_mutex_lock(&sc->mtx); 747bf21cd93STycho Nightingale 7484c87aefeSPatrick Mooney if (sc->usc_sock.clifd != -1) { 7494c87aefeSPatrick Mooney /* we're already handling a client */ 7504c87aefeSPatrick Mooney (void) fprintf(stderr, "uart: unexpected client conn\n"); 7514c87aefeSPatrick Mooney (void) shutdown(connfd, SHUT_RDWR); 7524c87aefeSPatrick Mooney (void) close(connfd); 753bf21cd93STycho Nightingale } else { 7544c87aefeSPatrick Mooney if (fcntl(connfd, F_SETFL, O_NONBLOCK) < 0) { 7554c87aefeSPatrick Mooney perror("uart: fcntl(O_NONBLOCK)"); 7564c87aefeSPatrick Mooney (void) shutdown(connfd, SHUT_RDWR); 7574c87aefeSPatrick Mooney (void) close(connfd); 758bf21cd93STycho Nightingale } else { 7594c87aefeSPatrick Mooney sc->usc_sock.clifd = connfd; 7604c87aefeSPatrick Mooney sc->mev = mevent_add(sc->usc_sock.clifd, EVF_READ, 7614c87aefeSPatrick Mooney uart_sock_drain, sc); 762bf21cd93STycho Nightingale } 763bf21cd93STycho Nightingale } 764bf21cd93STycho Nightingale 7654c87aefeSPatrick Mooney pthread_mutex_unlock(&sc->mtx); 766bf21cd93STycho Nightingale } 767bf21cd93STycho Nightingale 768bf21cd93STycho Nightingale static int 7694c87aefeSPatrick Mooney init_sock(const char *path) 770bf21cd93STycho Nightingale { 771bf21cd93STycho Nightingale int servfd; 772bf21cd93STycho Nightingale struct sockaddr_un servaddr; 773bf21cd93STycho Nightingale 7744c87aefeSPatrick Mooney bzero(&servaddr, sizeof (servaddr)); 7754c87aefeSPatrick Mooney servaddr.sun_family = AF_UNIX; 7764c87aefeSPatrick Mooney 7774c87aefeSPatrick Mooney if (strlcpy(servaddr.sun_path, path, sizeof (servaddr.sun_path)) >= 7784c87aefeSPatrick Mooney sizeof (servaddr.sun_path)) { 7794c87aefeSPatrick Mooney (void) fprintf(stderr, "uart: path '%s' too long\n", 7804c87aefeSPatrick Mooney path); 781bf21cd93STycho Nightingale return (-1); 782bf21cd93STycho Nightingale } 783bf21cd93STycho Nightingale 784bf21cd93STycho Nightingale if ((servfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { 7854c87aefeSPatrick Mooney (void) fprintf(stderr, "uart: socket() error - %s\n", 7864c87aefeSPatrick Mooney strerror(errno)); 787bf21cd93STycho Nightingale return (-1); 788bf21cd93STycho Nightingale } 789bf21cd93STycho Nightingale (void) unlink(servaddr.sun_path); 790bf21cd93STycho Nightingale 791bf21cd93STycho Nightingale if (bind(servfd, (struct sockaddr *)&servaddr, 792bf21cd93STycho Nightingale sizeof (servaddr)) == -1) { 7934c87aefeSPatrick Mooney (void) fprintf(stderr, "uart: bind() error - %s\n", 7944c87aefeSPatrick Mooney strerror(errno)); 795bf21cd93STycho Nightingale goto out; 796bf21cd93STycho Nightingale } 797bf21cd93STycho Nightingale 7984c87aefeSPatrick Mooney if (listen(servfd, 1) == -1) { 7994c87aefeSPatrick Mooney (void) fprintf(stderr, "uart: listen() error - %s\n", 8004c87aefeSPatrick Mooney strerror(errno)); 801bf21cd93STycho Nightingale goto out; 802bf21cd93STycho Nightingale } 803bf21cd93STycho Nightingale return (servfd); 804bf21cd93STycho Nightingale 805bf21cd93STycho Nightingale out: 806bf21cd93STycho Nightingale (void) unlink(servaddr.sun_path); 807bf21cd93STycho Nightingale (void) close(servfd); 808bf21cd93STycho Nightingale return (-1); 809bf21cd93STycho Nightingale } 8104c87aefeSPatrick Mooney #endif /* not __FreeBSD__ */ 811bf21cd93STycho Nightingale 812bf21cd93STycho Nightingale int 813bf21cd93STycho Nightingale uart_legacy_alloc(int which, int *baseaddr, int *irq) 814bf21cd93STycho Nightingale { 815bf21cd93STycho Nightingale 816bf21cd93STycho Nightingale if (which < 0 || which >= UART_NLDEVS || uart_lres[which].inuse) 817bf21cd93STycho Nightingale return (-1); 818bf21cd93STycho Nightingale 819bf21cd93STycho Nightingale uart_lres[which].inuse = true; 820bf21cd93STycho Nightingale *baseaddr = uart_lres[which].baseaddr; 821bf21cd93STycho Nightingale *irq = uart_lres[which].irq; 822bf21cd93STycho Nightingale 823bf21cd93STycho Nightingale return (0); 824bf21cd93STycho Nightingale } 825bf21cd93STycho Nightingale 826bf21cd93STycho Nightingale struct uart_softc * 827bf21cd93STycho Nightingale uart_init(uart_intr_func_t intr_assert, uart_intr_func_t intr_deassert, 828bf21cd93STycho Nightingale void *arg) 829bf21cd93STycho Nightingale { 830bf21cd93STycho Nightingale struct uart_softc *sc; 831bf21cd93STycho Nightingale 8324c87aefeSPatrick Mooney sc = calloc(1, sizeof(struct uart_softc)); 833bf21cd93STycho Nightingale 834bf21cd93STycho Nightingale sc->arg = arg; 835bf21cd93STycho Nightingale sc->intr_assert = intr_assert; 836bf21cd93STycho Nightingale sc->intr_deassert = intr_deassert; 837bf21cd93STycho Nightingale 838bf21cd93STycho Nightingale pthread_mutex_init(&sc->mtx, NULL); 839bf21cd93STycho Nightingale 840bf21cd93STycho Nightingale uart_reset(sc); 841bf21cd93STycho Nightingale 842bf21cd93STycho Nightingale return (sc); 843bf21cd93STycho Nightingale } 844bf21cd93STycho Nightingale 8454c87aefeSPatrick Mooney #ifndef __FreeBSD__ 8464c87aefeSPatrick Mooney static int 8474c87aefeSPatrick Mooney uart_sock_backend(struct uart_softc *sc, const char *inopts) 8484c87aefeSPatrick Mooney { 849*d7b72f7bSAndy Fiddaman char *opts, *tofree; 8504c87aefeSPatrick Mooney char *opt; 8514c87aefeSPatrick Mooney char *nextopt; 8524c87aefeSPatrick Mooney char *path = NULL; 8534c87aefeSPatrick Mooney 8544c87aefeSPatrick Mooney if (strncmp(inopts, "socket,", 7) != 0) { 8554c87aefeSPatrick Mooney return (-1); 8564c87aefeSPatrick Mooney } 8574c87aefeSPatrick Mooney if ((opts = strdup(inopts + 7)) == NULL) { 8584c87aefeSPatrick Mooney return (-1); 8594c87aefeSPatrick Mooney } 8604c87aefeSPatrick Mooney 861*d7b72f7bSAndy Fiddaman tofree = nextopt = opts; 8624c87aefeSPatrick Mooney for (opt = strsep(&nextopt, ","); opt != NULL; 8634c87aefeSPatrick Mooney opt = strsep(&nextopt, ",")) { 8644c87aefeSPatrick Mooney if (path == NULL && *opt == '/') { 8654c87aefeSPatrick Mooney path = opt; 8664c87aefeSPatrick Mooney continue; 8674c87aefeSPatrick Mooney } 8684c87aefeSPatrick Mooney /* 8694c87aefeSPatrick Mooney * XXX check for server and client options here. For now, 8704c87aefeSPatrick Mooney * everything is a server 8714c87aefeSPatrick Mooney */ 872*d7b72f7bSAndy Fiddaman free(tofree); 8734c87aefeSPatrick Mooney return (-1); 8744c87aefeSPatrick Mooney } 8754c87aefeSPatrick Mooney 8764c87aefeSPatrick Mooney sc->usc_sock.clifd = -1; 8774c87aefeSPatrick Mooney if ((sc->usc_sock.servfd = init_sock(path)) == -1) { 878*d7b72f7bSAndy Fiddaman free(tofree); 8794c87aefeSPatrick Mooney return (-1); 8804c87aefeSPatrick Mooney } 8814c87aefeSPatrick Mooney sc->sock = true; 8824c87aefeSPatrick Mooney sc->tty.rfd = sc->tty.wfd = -1; 8834c87aefeSPatrick Mooney sc->usc_sock.servmev = mevent_add(sc->usc_sock.servfd, EVF_READ, 8844c87aefeSPatrick Mooney uart_sock_accept, sc); 8854c87aefeSPatrick Mooney assert(sc->usc_sock.servmev != NULL); 8864c87aefeSPatrick Mooney 887*d7b72f7bSAndy Fiddaman free(tofree); 8884c87aefeSPatrick Mooney return (0); 8894c87aefeSPatrick Mooney } 8904c87aefeSPatrick Mooney #endif /* not __FreeBSD__ */ 8914c87aefeSPatrick Mooney 8924c87aefeSPatrick Mooney static int 8934c87aefeSPatrick Mooney uart_stdio_backend(struct uart_softc *sc) 8944c87aefeSPatrick Mooney { 8954c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM 8964c87aefeSPatrick Mooney cap_rights_t rights; 8974c87aefeSPatrick Mooney cap_ioctl_t cmds[] = { TIOCGETA, TIOCSETA, TIOCGWINSZ }; 8984c87aefeSPatrick Mooney #endif 8994c87aefeSPatrick Mooney 9004c87aefeSPatrick Mooney if (uart_stdio) 9014c87aefeSPatrick Mooney return (-1); 9024c87aefeSPatrick Mooney 9034c87aefeSPatrick Mooney sc->tty.rfd = STDIN_FILENO; 9044c87aefeSPatrick Mooney sc->tty.wfd = STDOUT_FILENO; 9054c87aefeSPatrick Mooney sc->tty.opened = true; 9064c87aefeSPatrick Mooney 9074c87aefeSPatrick Mooney if (fcntl(sc->tty.rfd, F_SETFL, O_NONBLOCK) != 0) 9084c87aefeSPatrick Mooney return (-1); 9094c87aefeSPatrick Mooney if (fcntl(sc->tty.wfd, F_SETFL, O_NONBLOCK) != 0) 9104c87aefeSPatrick Mooney return (-1); 9114c87aefeSPatrick Mooney 9124c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM 9134c87aefeSPatrick Mooney cap_rights_init(&rights, CAP_EVENT, CAP_IOCTL, CAP_READ); 9144c87aefeSPatrick Mooney if (caph_rights_limit(sc->tty.rfd, &rights) == -1) 9154c87aefeSPatrick Mooney errx(EX_OSERR, "Unable to apply rights for sandbox"); 9164c87aefeSPatrick Mooney if (caph_ioctls_limit(sc->tty.rfd, cmds, nitems(cmds)) == -1) 9174c87aefeSPatrick Mooney errx(EX_OSERR, "Unable to apply rights for sandbox"); 9184c87aefeSPatrick Mooney #endif 9194c87aefeSPatrick Mooney 9204c87aefeSPatrick Mooney uart_stdio = true; 9214c87aefeSPatrick Mooney 9224c87aefeSPatrick Mooney return (0); 9234c87aefeSPatrick Mooney } 9244c87aefeSPatrick Mooney 9254c87aefeSPatrick Mooney static int 9262b948146SAndy Fiddaman uart_tty_backend(struct uart_softc *sc, const char *path) 9274c87aefeSPatrick Mooney { 9284c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM 9294c87aefeSPatrick Mooney cap_rights_t rights; 9304c87aefeSPatrick Mooney cap_ioctl_t cmds[] = { TIOCGETA, TIOCSETA, TIOCGWINSZ }; 9314c87aefeSPatrick Mooney #endif 9324c87aefeSPatrick Mooney int fd; 9334c87aefeSPatrick Mooney 9342b948146SAndy Fiddaman fd = open(path, O_RDWR | O_NONBLOCK); 93584659b24SMichael Zeller if (fd < 0) 9364c87aefeSPatrick Mooney return (-1); 9374c87aefeSPatrick Mooney 93884659b24SMichael Zeller if (!isatty(fd)) { 93984659b24SMichael Zeller close(fd); 94084659b24SMichael Zeller return (-1); 94184659b24SMichael Zeller } 94284659b24SMichael Zeller 9434c87aefeSPatrick Mooney sc->tty.rfd = sc->tty.wfd = fd; 9444c87aefeSPatrick Mooney sc->tty.opened = true; 9454c87aefeSPatrick Mooney 9464c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM 9474c87aefeSPatrick Mooney cap_rights_init(&rights, CAP_EVENT, CAP_IOCTL, CAP_READ, CAP_WRITE); 9484c87aefeSPatrick Mooney if (caph_rights_limit(fd, &rights) == -1) 9494c87aefeSPatrick Mooney errx(EX_OSERR, "Unable to apply rights for sandbox"); 9504c87aefeSPatrick Mooney if (caph_ioctls_limit(fd, cmds, nitems(cmds)) == -1) 9514c87aefeSPatrick Mooney errx(EX_OSERR, "Unable to apply rights for sandbox"); 9524c87aefeSPatrick Mooney #endif 9534c87aefeSPatrick Mooney 9544c87aefeSPatrick Mooney return (0); 9554c87aefeSPatrick Mooney } 9564c87aefeSPatrick Mooney 957bf21cd93STycho Nightingale int 9582b948146SAndy Fiddaman uart_set_backend(struct uart_softc *sc, const char *device) 959bf21cd93STycho Nightingale { 9604c87aefeSPatrick Mooney int retval; 9614c87aefeSPatrick Mooney 9622b948146SAndy Fiddaman if (device == NULL) 963bf21cd93STycho Nightingale return (0); 964bf21cd93STycho Nightingale 9654c87aefeSPatrick Mooney #ifndef __FreeBSD__ 9662b948146SAndy Fiddaman if (strncmp("socket,", device, 7) == 0) 9672b948146SAndy Fiddaman return (uart_sock_backend(sc, device)); 968bf21cd93STycho Nightingale #endif 9692b948146SAndy Fiddaman if (strcmp("stdio", device) == 0) 9704c87aefeSPatrick Mooney retval = uart_stdio_backend(sc); 9714c87aefeSPatrick Mooney else 9722b948146SAndy Fiddaman retval = uart_tty_backend(sc, device); 9734c87aefeSPatrick Mooney if (retval == 0) 9744c87aefeSPatrick Mooney uart_opentty(sc); 9754c87aefeSPatrick Mooney 9764c87aefeSPatrick Mooney return (retval); 977bf21cd93STycho Nightingale } 978