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" 74*154972afSPatrick 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 80bf21cd93STycho Nightingale 81bf21cd93STycho Nightingale #define DEFAULT_RCLK 1843200 82bf21cd93STycho Nightingale #define DEFAULT_BAUD 9600 83bf21cd93STycho Nightingale 84bf21cd93STycho Nightingale #define FCR_RX_MASK 0xC0 85bf21cd93STycho Nightingale 86bf21cd93STycho Nightingale #define MCR_OUT1 0x04 87bf21cd93STycho Nightingale #define MCR_OUT2 0x08 88bf21cd93STycho Nightingale 89bf21cd93STycho Nightingale #define MSR_DELTA_MASK 0x0f 90bf21cd93STycho Nightingale 91bf21cd93STycho Nightingale #ifndef REG_SCR 92bf21cd93STycho Nightingale #define REG_SCR com_scr 93bf21cd93STycho Nightingale #endif 94bf21cd93STycho Nightingale 95bf21cd93STycho Nightingale #define FIFOSZ 16 96bf21cd93STycho Nightingale 97bf21cd93STycho Nightingale static bool uart_stdio; /* stdio in use for i/o */ 984c87aefeSPatrick Mooney static struct termios tio_stdio_orig; 99bf21cd93STycho Nightingale 100bf21cd93STycho Nightingale static struct { 101bf21cd93STycho Nightingale int baseaddr; 102bf21cd93STycho Nightingale int irq; 103bf21cd93STycho Nightingale bool inuse; 104bf21cd93STycho Nightingale } uart_lres[] = { 105bf21cd93STycho Nightingale { COM1_BASE, COM1_IRQ, false}, 106bf21cd93STycho Nightingale { COM2_BASE, COM2_IRQ, false}, 107bf21cd93STycho Nightingale }; 108bf21cd93STycho Nightingale 109bf21cd93STycho Nightingale #define UART_NLDEVS (sizeof(uart_lres) / sizeof(uart_lres[0])) 110bf21cd93STycho Nightingale 111bf21cd93STycho Nightingale struct fifo { 112bf21cd93STycho Nightingale uint8_t buf[FIFOSZ]; 113bf21cd93STycho Nightingale int rindex; /* index to read from */ 114bf21cd93STycho Nightingale int windex; /* index to write to */ 115bf21cd93STycho Nightingale int num; /* number of characters in the fifo */ 116bf21cd93STycho Nightingale int size; /* size of the fifo */ 117bf21cd93STycho Nightingale }; 118bf21cd93STycho Nightingale 1194c87aefeSPatrick Mooney struct ttyfd { 1204c87aefeSPatrick Mooney bool opened; 1214c87aefeSPatrick Mooney int rfd; /* fd for reading */ 1224c87aefeSPatrick Mooney int wfd; /* fd for writing, may be == rfd */ 1234c87aefeSPatrick Mooney }; 1244c87aefeSPatrick Mooney 125bf21cd93STycho Nightingale struct uart_softc { 126bf21cd93STycho Nightingale pthread_mutex_t mtx; /* protects all softc elements */ 127bf21cd93STycho Nightingale uint8_t data; /* Data register (R/W) */ 128bf21cd93STycho Nightingale uint8_t ier; /* Interrupt enable register (R/W) */ 129bf21cd93STycho Nightingale uint8_t lcr; /* Line control register (R/W) */ 130bf21cd93STycho Nightingale uint8_t mcr; /* Modem control register (R/W) */ 131bf21cd93STycho Nightingale uint8_t lsr; /* Line status register (R/W) */ 132bf21cd93STycho Nightingale uint8_t msr; /* Modem status register (R/W) */ 133bf21cd93STycho Nightingale uint8_t fcr; /* FIFO control register (W) */ 134bf21cd93STycho Nightingale uint8_t scr; /* Scratch register (R/W) */ 135bf21cd93STycho Nightingale 136bf21cd93STycho Nightingale uint8_t dll; /* Baudrate divisor latch LSB */ 137bf21cd93STycho Nightingale uint8_t dlh; /* Baudrate divisor latch MSB */ 138bf21cd93STycho Nightingale 139bf21cd93STycho Nightingale struct fifo rxfifo; 1404c87aefeSPatrick Mooney struct mevent *mev; 141bf21cd93STycho Nightingale 1424c87aefeSPatrick Mooney struct ttyfd tty; 143bf21cd93STycho Nightingale #ifndef __FreeBSD__ 1444c87aefeSPatrick Mooney bool sock; 145bf21cd93STycho Nightingale struct { 146bf21cd93STycho Nightingale int clifd; /* console client unix domain socket */ 147bf21cd93STycho Nightingale int servfd; /* console server unix domain socket */ 1484c87aefeSPatrick Mooney struct mevent *servmev; /* mevent for server socket */ 1494c87aefeSPatrick Mooney } usc_sock; 150bf21cd93STycho Nightingale #endif 151bf21cd93STycho Nightingale 152bf21cd93STycho Nightingale bool thre_int_pending; /* THRE interrupt pending */ 153bf21cd93STycho Nightingale 154bf21cd93STycho Nightingale void *arg; 155bf21cd93STycho Nightingale uart_intr_func_t intr_assert; 156bf21cd93STycho Nightingale uart_intr_func_t intr_deassert; 157bf21cd93STycho Nightingale }; 158bf21cd93STycho Nightingale 159bf21cd93STycho Nightingale static void uart_drain(int fd, enum ev_type ev, void *arg); 160bf21cd93STycho Nightingale 161bf21cd93STycho Nightingale static void 162bf21cd93STycho Nightingale ttyclose(void) 163bf21cd93STycho Nightingale { 164bf21cd93STycho Nightingale 1654c87aefeSPatrick Mooney tcsetattr(STDIN_FILENO, TCSANOW, &tio_stdio_orig); 166bf21cd93STycho Nightingale } 167bf21cd93STycho Nightingale 168bf21cd93STycho Nightingale static void 1694c87aefeSPatrick Mooney ttyopen(struct ttyfd *tf) 170bf21cd93STycho Nightingale { 1714c87aefeSPatrick Mooney struct termios orig, new; 172bf21cd93STycho Nightingale 1734c87aefeSPatrick Mooney tcgetattr(tf->rfd, &orig); 1744c87aefeSPatrick Mooney new = orig; 1754c87aefeSPatrick Mooney cfmakeraw(&new); 1764c87aefeSPatrick Mooney new.c_cflag |= CLOCAL; 1774c87aefeSPatrick Mooney tcsetattr(tf->rfd, TCSANOW, &new); 1784c87aefeSPatrick Mooney if (uart_stdio) { 1794c87aefeSPatrick Mooney tio_stdio_orig = orig; 180bf21cd93STycho Nightingale atexit(ttyclose); 181bf21cd93STycho Nightingale } 182*154972afSPatrick Mooney raw_stdio = 1; 183bf21cd93STycho Nightingale } 184bf21cd93STycho Nightingale 185bf21cd93STycho Nightingale static int 1864c87aefeSPatrick Mooney ttyread(struct ttyfd *tf) 187bf21cd93STycho Nightingale { 1884c87aefeSPatrick Mooney unsigned char rb; 189bf21cd93STycho Nightingale 1904c87aefeSPatrick Mooney if (read(tf->rfd, &rb, 1) == 1) 1914c87aefeSPatrick Mooney return (rb); 1924c87aefeSPatrick Mooney else 193bf21cd93STycho Nightingale return (-1); 194bf21cd93STycho Nightingale } 195bf21cd93STycho Nightingale 196bf21cd93STycho Nightingale static void 1974c87aefeSPatrick Mooney ttywrite(struct ttyfd *tf, unsigned char wb) 198bf21cd93STycho Nightingale { 199bf21cd93STycho Nightingale 2004c87aefeSPatrick Mooney (void)write(tf->wfd, &wb, 1); 201bf21cd93STycho Nightingale } 202bf21cd93STycho Nightingale 203bf21cd93STycho Nightingale #ifndef __FreeBSD__ 204bf21cd93STycho Nightingale static void 2054c87aefeSPatrick Mooney sockwrite(struct uart_softc *sc, unsigned char wb) 206bf21cd93STycho Nightingale { 2074c87aefeSPatrick Mooney (void) write(sc->usc_sock.clifd, &wb, 1); 208bf21cd93STycho Nightingale } 209bf21cd93STycho Nightingale #endif 210bf21cd93STycho Nightingale 211bf21cd93STycho Nightingale static void 2124c87aefeSPatrick Mooney rxfifo_reset(struct uart_softc *sc, int size) 213bf21cd93STycho Nightingale { 2144c87aefeSPatrick Mooney char flushbuf[32]; 2154c87aefeSPatrick Mooney struct fifo *fifo; 2164c87aefeSPatrick Mooney ssize_t nread; 2174c87aefeSPatrick Mooney int error; 2184c87aefeSPatrick Mooney 2194c87aefeSPatrick Mooney fifo = &sc->rxfifo; 220bf21cd93STycho Nightingale bzero(fifo, sizeof(struct fifo)); 221bf21cd93STycho Nightingale fifo->size = size; 2224c87aefeSPatrick Mooney 2234c87aefeSPatrick Mooney if (sc->tty.opened) { 2244c87aefeSPatrick Mooney /* 2254c87aefeSPatrick Mooney * Flush any unread input from the tty buffer. 2264c87aefeSPatrick Mooney */ 2274c87aefeSPatrick Mooney while (1) { 2284c87aefeSPatrick Mooney nread = read(sc->tty.rfd, flushbuf, sizeof(flushbuf)); 2294c87aefeSPatrick Mooney if (nread != sizeof(flushbuf)) 2304c87aefeSPatrick Mooney break; 2314c87aefeSPatrick Mooney } 2324c87aefeSPatrick Mooney 2334c87aefeSPatrick Mooney /* 2344c87aefeSPatrick Mooney * Enable mevent to trigger when new characters are available 2354c87aefeSPatrick Mooney * on the tty fd. 2364c87aefeSPatrick Mooney */ 2374c87aefeSPatrick Mooney error = mevent_enable(sc->mev); 2384c87aefeSPatrick Mooney assert(error == 0); 2394c87aefeSPatrick Mooney } 2404c87aefeSPatrick Mooney #ifndef __FreeBSD__ 2414c87aefeSPatrick Mooney if (sc->sock && sc->usc_sock.clifd != -1) { 2424c87aefeSPatrick Mooney /* Flush any unread input from the socket buffer. */ 2434c87aefeSPatrick Mooney do { 2444c87aefeSPatrick Mooney nread = read(sc->usc_sock.clifd, flushbuf, 2454c87aefeSPatrick Mooney sizeof (flushbuf)); 2464c87aefeSPatrick Mooney } while (nread == sizeof (flushbuf)); 2474c87aefeSPatrick Mooney 2484c87aefeSPatrick Mooney /* Enable mevent to trigger when new data available on sock */ 2494c87aefeSPatrick Mooney error = mevent_enable(sc->mev); 2504c87aefeSPatrick Mooney assert(error == 0); 2514c87aefeSPatrick Mooney } 2524c87aefeSPatrick Mooney #endif /* __FreeBSD__ */ 253bf21cd93STycho Nightingale } 254bf21cd93STycho Nightingale 255bf21cd93STycho Nightingale static int 2564c87aefeSPatrick Mooney rxfifo_available(struct uart_softc *sc) 257bf21cd93STycho Nightingale { 2584c87aefeSPatrick Mooney struct fifo *fifo; 2594c87aefeSPatrick Mooney 2604c87aefeSPatrick Mooney fifo = &sc->rxfifo; 2614c87aefeSPatrick Mooney return (fifo->num < fifo->size); 2624c87aefeSPatrick Mooney } 2634c87aefeSPatrick Mooney 2644c87aefeSPatrick Mooney static int 2654c87aefeSPatrick Mooney rxfifo_putchar(struct uart_softc *sc, uint8_t ch) 2664c87aefeSPatrick Mooney { 2674c87aefeSPatrick Mooney struct fifo *fifo; 2684c87aefeSPatrick Mooney int error; 2694c87aefeSPatrick Mooney 2704c87aefeSPatrick Mooney fifo = &sc->rxfifo; 271bf21cd93STycho Nightingale 272bf21cd93STycho Nightingale if (fifo->num < fifo->size) { 273bf21cd93STycho Nightingale fifo->buf[fifo->windex] = ch; 274bf21cd93STycho Nightingale fifo->windex = (fifo->windex + 1) % fifo->size; 275bf21cd93STycho Nightingale fifo->num++; 2764c87aefeSPatrick Mooney if (!rxfifo_available(sc)) { 2774c87aefeSPatrick Mooney if (sc->tty.opened) { 2784c87aefeSPatrick Mooney /* 2794c87aefeSPatrick Mooney * Disable mevent callback if the FIFO is full. 2804c87aefeSPatrick Mooney */ 2814c87aefeSPatrick Mooney error = mevent_disable(sc->mev); 2824c87aefeSPatrick Mooney assert(error == 0); 2834c87aefeSPatrick Mooney } 2844c87aefeSPatrick Mooney #ifndef __FreeBSD__ 2854c87aefeSPatrick Mooney if (sc->sock && sc->usc_sock.clifd != -1) { 2864c87aefeSPatrick Mooney /* 2874c87aefeSPatrick Mooney * Disable mevent callback if the FIFO is full. 2884c87aefeSPatrick Mooney */ 2894c87aefeSPatrick Mooney error = mevent_disable(sc->mev); 2904c87aefeSPatrick Mooney assert(error == 0); 2914c87aefeSPatrick Mooney } 2924c87aefeSPatrick Mooney #endif /* __FreeBSD__ */ 2934c87aefeSPatrick Mooney } 294bf21cd93STycho Nightingale return (0); 295bf21cd93STycho Nightingale } else 296bf21cd93STycho Nightingale return (-1); 297bf21cd93STycho Nightingale } 298bf21cd93STycho Nightingale 299bf21cd93STycho Nightingale static int 3004c87aefeSPatrick Mooney rxfifo_getchar(struct uart_softc *sc) 301bf21cd93STycho Nightingale { 3024c87aefeSPatrick Mooney struct fifo *fifo; 3034c87aefeSPatrick Mooney int c, error, wasfull; 304bf21cd93STycho Nightingale 3054c87aefeSPatrick Mooney wasfull = 0; 3064c87aefeSPatrick Mooney fifo = &sc->rxfifo; 307bf21cd93STycho Nightingale if (fifo->num > 0) { 3084c87aefeSPatrick Mooney if (!rxfifo_available(sc)) 3094c87aefeSPatrick Mooney wasfull = 1; 310bf21cd93STycho Nightingale c = fifo->buf[fifo->rindex]; 311bf21cd93STycho Nightingale fifo->rindex = (fifo->rindex + 1) % fifo->size; 312bf21cd93STycho Nightingale fifo->num--; 3134c87aefeSPatrick Mooney if (wasfull) { 3144c87aefeSPatrick Mooney if (sc->tty.opened) { 3154c87aefeSPatrick Mooney error = mevent_enable(sc->mev); 3164c87aefeSPatrick Mooney assert(error == 0); 3174c87aefeSPatrick Mooney } 3184c87aefeSPatrick Mooney #ifndef __FreeBSD__ 3194c87aefeSPatrick Mooney if (sc->sock && sc->usc_sock.clifd != -1) { 3204c87aefeSPatrick Mooney error = mevent_enable(sc->mev); 3214c87aefeSPatrick Mooney assert(error == 0); 3224c87aefeSPatrick Mooney } 3234c87aefeSPatrick Mooney #endif /* __FreeBSD__ */ 3244c87aefeSPatrick Mooney } 325bf21cd93STycho Nightingale return (c); 326bf21cd93STycho Nightingale } else 327bf21cd93STycho Nightingale return (-1); 328bf21cd93STycho Nightingale } 329bf21cd93STycho Nightingale 330bf21cd93STycho Nightingale static int 3314c87aefeSPatrick Mooney rxfifo_numchars(struct uart_softc *sc) 332bf21cd93STycho Nightingale { 3334c87aefeSPatrick Mooney struct fifo *fifo = &sc->rxfifo; 334bf21cd93STycho Nightingale 335bf21cd93STycho Nightingale return (fifo->num); 336bf21cd93STycho Nightingale } 337bf21cd93STycho Nightingale 338bf21cd93STycho Nightingale static void 339bf21cd93STycho Nightingale uart_opentty(struct uart_softc *sc) 340bf21cd93STycho Nightingale { 341bf21cd93STycho Nightingale 3424c87aefeSPatrick Mooney ttyopen(&sc->tty); 3434c87aefeSPatrick Mooney sc->mev = mevent_add(sc->tty.rfd, EVF_READ, uart_drain, sc); 3444c87aefeSPatrick Mooney assert(sc->mev != NULL); 3454c87aefeSPatrick Mooney } 346bf21cd93STycho Nightingale 3474c87aefeSPatrick Mooney static uint8_t 3484c87aefeSPatrick Mooney modem_status(uint8_t mcr) 3494c87aefeSPatrick Mooney { 3504c87aefeSPatrick Mooney uint8_t msr; 3514c87aefeSPatrick Mooney 3524c87aefeSPatrick Mooney if (mcr & MCR_LOOPBACK) { 3534c87aefeSPatrick Mooney /* 3544c87aefeSPatrick Mooney * In the loopback mode certain bits from the MCR are 3554c87aefeSPatrick Mooney * reflected back into MSR. 3564c87aefeSPatrick Mooney */ 3574c87aefeSPatrick Mooney msr = 0; 3584c87aefeSPatrick Mooney if (mcr & MCR_RTS) 3594c87aefeSPatrick Mooney msr |= MSR_CTS; 3604c87aefeSPatrick Mooney if (mcr & MCR_DTR) 3614c87aefeSPatrick Mooney msr |= MSR_DSR; 3624c87aefeSPatrick Mooney if (mcr & MCR_OUT1) 3634c87aefeSPatrick Mooney msr |= MSR_RI; 3644c87aefeSPatrick Mooney if (mcr & MCR_OUT2) 3654c87aefeSPatrick Mooney msr |= MSR_DCD; 3664c87aefeSPatrick Mooney } else { 3674c87aefeSPatrick Mooney /* 3684c87aefeSPatrick Mooney * Always assert DCD and DSR so tty open doesn't block 3694c87aefeSPatrick Mooney * even if CLOCAL is turned off. 3704c87aefeSPatrick Mooney */ 3714c87aefeSPatrick Mooney msr = MSR_DCD | MSR_DSR; 3724c87aefeSPatrick Mooney } 3734c87aefeSPatrick Mooney assert((msr & MSR_DELTA_MASK) == 0); 3744c87aefeSPatrick Mooney 3754c87aefeSPatrick Mooney return (msr); 376bf21cd93STycho Nightingale } 377bf21cd93STycho Nightingale 378bf21cd93STycho Nightingale /* 379bf21cd93STycho Nightingale * The IIR returns a prioritized interrupt reason: 380bf21cd93STycho Nightingale * - receive data available 381bf21cd93STycho Nightingale * - transmit holding register empty 382bf21cd93STycho Nightingale * - modem status change 383bf21cd93STycho Nightingale * 384bf21cd93STycho Nightingale * Return an interrupt reason if one is available. 385bf21cd93STycho Nightingale */ 386bf21cd93STycho Nightingale static int 387bf21cd93STycho Nightingale uart_intr_reason(struct uart_softc *sc) 388bf21cd93STycho Nightingale { 389bf21cd93STycho Nightingale 390bf21cd93STycho Nightingale if ((sc->lsr & LSR_OE) != 0 && (sc->ier & IER_ERLS) != 0) 391bf21cd93STycho Nightingale return (IIR_RLS); 3924c87aefeSPatrick Mooney else if (rxfifo_numchars(sc) > 0 && (sc->ier & IER_ERXRDY) != 0) 393bf21cd93STycho Nightingale return (IIR_RXTOUT); 394bf21cd93STycho Nightingale else if (sc->thre_int_pending && (sc->ier & IER_ETXRDY) != 0) 395bf21cd93STycho Nightingale return (IIR_TXRDY); 396bf21cd93STycho Nightingale else if ((sc->msr & MSR_DELTA_MASK) != 0 && (sc->ier & IER_EMSC) != 0) 397bf21cd93STycho Nightingale return (IIR_MLSC); 398bf21cd93STycho Nightingale else 399bf21cd93STycho Nightingale return (IIR_NOPEND); 400bf21cd93STycho Nightingale } 401bf21cd93STycho Nightingale 402bf21cd93STycho Nightingale static void 403bf21cd93STycho Nightingale uart_reset(struct uart_softc *sc) 404bf21cd93STycho Nightingale { 405bf21cd93STycho Nightingale uint16_t divisor; 406bf21cd93STycho Nightingale 407bf21cd93STycho Nightingale divisor = DEFAULT_RCLK / DEFAULT_BAUD / 16; 408bf21cd93STycho Nightingale sc->dll = divisor; 4094c87aefeSPatrick Mooney #ifndef __FreeBSD__ 4104c87aefeSPatrick Mooney sc->dlh = 0; 4114c87aefeSPatrick Mooney #else 412bf21cd93STycho Nightingale sc->dlh = divisor >> 16; 4134c87aefeSPatrick Mooney #endif 4144c87aefeSPatrick Mooney sc->msr = modem_status(sc->mcr); 415bf21cd93STycho Nightingale 4164c87aefeSPatrick Mooney rxfifo_reset(sc, 1); /* no fifo until enabled by software */ 417bf21cd93STycho Nightingale } 418bf21cd93STycho Nightingale 419bf21cd93STycho Nightingale /* 420bf21cd93STycho Nightingale * Toggle the COM port's intr pin depending on whether or not we have an 421bf21cd93STycho Nightingale * interrupt condition to report to the processor. 422bf21cd93STycho Nightingale */ 423bf21cd93STycho Nightingale static void 424bf21cd93STycho Nightingale uart_toggle_intr(struct uart_softc *sc) 425bf21cd93STycho Nightingale { 426bf21cd93STycho Nightingale uint8_t intr_reason; 427bf21cd93STycho Nightingale 428bf21cd93STycho Nightingale intr_reason = uart_intr_reason(sc); 429bf21cd93STycho Nightingale 430bf21cd93STycho Nightingale if (intr_reason == IIR_NOPEND) 431bf21cd93STycho Nightingale (*sc->intr_deassert)(sc->arg); 432bf21cd93STycho Nightingale else 433bf21cd93STycho Nightingale (*sc->intr_assert)(sc->arg); 434bf21cd93STycho Nightingale } 435bf21cd93STycho Nightingale 436bf21cd93STycho Nightingale static void 437bf21cd93STycho Nightingale uart_drain(int fd, enum ev_type ev, void *arg) 438bf21cd93STycho Nightingale { 439bf21cd93STycho Nightingale struct uart_softc *sc; 440bf21cd93STycho Nightingale int ch; 441bf21cd93STycho Nightingale 442bf21cd93STycho Nightingale sc = arg; 443bf21cd93STycho Nightingale 4444c87aefeSPatrick Mooney assert(fd == sc->tty.rfd); 445bf21cd93STycho Nightingale assert(ev == EVF_READ); 446bf21cd93STycho Nightingale 447bf21cd93STycho Nightingale /* 448bf21cd93STycho Nightingale * This routine is called in the context of the mevent thread 449bf21cd93STycho Nightingale * to take out the softc lock to protect against concurrent 450bf21cd93STycho Nightingale * access from a vCPU i/o exit 451bf21cd93STycho Nightingale */ 452bf21cd93STycho Nightingale pthread_mutex_lock(&sc->mtx); 453bf21cd93STycho Nightingale 454bf21cd93STycho Nightingale if ((sc->mcr & MCR_LOOPBACK) != 0) { 4554c87aefeSPatrick Mooney (void) ttyread(&sc->tty); 456bf21cd93STycho Nightingale } else { 4574c87aefeSPatrick Mooney while (rxfifo_available(sc) && 4584c87aefeSPatrick Mooney ((ch = ttyread(&sc->tty)) != -1)) { 4594c87aefeSPatrick Mooney rxfifo_putchar(sc, ch); 460bf21cd93STycho Nightingale } 461bf21cd93STycho Nightingale uart_toggle_intr(sc); 462bf21cd93STycho Nightingale } 463bf21cd93STycho Nightingale 464bf21cd93STycho Nightingale pthread_mutex_unlock(&sc->mtx); 465bf21cd93STycho Nightingale } 466bf21cd93STycho Nightingale 467bf21cd93STycho Nightingale void 468bf21cd93STycho Nightingale uart_write(struct uart_softc *sc, int offset, uint8_t value) 469bf21cd93STycho Nightingale { 470bf21cd93STycho Nightingale int fifosz; 471bf21cd93STycho Nightingale uint8_t msr; 472bf21cd93STycho Nightingale 473bf21cd93STycho Nightingale pthread_mutex_lock(&sc->mtx); 474bf21cd93STycho Nightingale 475bf21cd93STycho Nightingale /* 476bf21cd93STycho Nightingale * Take care of the special case DLAB accesses first 477bf21cd93STycho Nightingale */ 478bf21cd93STycho Nightingale if ((sc->lcr & LCR_DLAB) != 0) { 479bf21cd93STycho Nightingale if (offset == REG_DLL) { 480bf21cd93STycho Nightingale sc->dll = value; 481bf21cd93STycho Nightingale goto done; 482bf21cd93STycho Nightingale } 483bf21cd93STycho Nightingale 484bf21cd93STycho Nightingale if (offset == REG_DLH) { 485bf21cd93STycho Nightingale sc->dlh = value; 486bf21cd93STycho Nightingale goto done; 487bf21cd93STycho Nightingale } 488bf21cd93STycho Nightingale } 489bf21cd93STycho Nightingale 490bf21cd93STycho Nightingale switch (offset) { 491bf21cd93STycho Nightingale case REG_DATA: 492bf21cd93STycho Nightingale if (sc->mcr & MCR_LOOPBACK) { 4934c87aefeSPatrick Mooney if (rxfifo_putchar(sc, value) != 0) 494bf21cd93STycho Nightingale sc->lsr |= LSR_OE; 4954c87aefeSPatrick Mooney } else if (sc->tty.opened) { 4964c87aefeSPatrick Mooney ttywrite(&sc->tty, value); 497bf21cd93STycho Nightingale #ifndef __FreeBSD__ 4984c87aefeSPatrick Mooney } else if (sc->sock) { 4994c87aefeSPatrick Mooney sockwrite(sc, value); 500bf21cd93STycho Nightingale #endif 501bf21cd93STycho Nightingale } /* else drop on floor */ 502bf21cd93STycho Nightingale sc->thre_int_pending = true; 503bf21cd93STycho Nightingale break; 504bf21cd93STycho Nightingale case REG_IER: 5054c87aefeSPatrick Mooney /* Set pending when IER_ETXRDY is raised (edge-triggered). */ 5064c87aefeSPatrick Mooney if ((sc->ier & IER_ETXRDY) == 0 && (value & IER_ETXRDY) != 0) 5074c87aefeSPatrick Mooney sc->thre_int_pending = true; 508bf21cd93STycho Nightingale /* 509bf21cd93STycho Nightingale * Apply mask so that bits 4-7 are 0 510bf21cd93STycho Nightingale * Also enables bits 0-3 only if they're 1 511bf21cd93STycho Nightingale */ 512bf21cd93STycho Nightingale sc->ier = value & 0x0F; 513bf21cd93STycho Nightingale break; 514bf21cd93STycho Nightingale case REG_FCR: 515bf21cd93STycho Nightingale /* 516bf21cd93STycho Nightingale * When moving from FIFO and 16450 mode and vice versa, 517bf21cd93STycho Nightingale * the FIFO contents are reset. 518bf21cd93STycho Nightingale */ 519bf21cd93STycho Nightingale if ((sc->fcr & FCR_ENABLE) ^ (value & FCR_ENABLE)) { 520bf21cd93STycho Nightingale fifosz = (value & FCR_ENABLE) ? FIFOSZ : 1; 5214c87aefeSPatrick Mooney rxfifo_reset(sc, fifosz); 522bf21cd93STycho Nightingale } 523bf21cd93STycho Nightingale 524bf21cd93STycho Nightingale /* 525bf21cd93STycho Nightingale * The FCR_ENABLE bit must be '1' for the programming 526bf21cd93STycho Nightingale * of other FCR bits to be effective. 527bf21cd93STycho Nightingale */ 528bf21cd93STycho Nightingale if ((value & FCR_ENABLE) == 0) { 529bf21cd93STycho Nightingale sc->fcr = 0; 530bf21cd93STycho Nightingale } else { 531bf21cd93STycho Nightingale if ((value & FCR_RCV_RST) != 0) 5324c87aefeSPatrick Mooney rxfifo_reset(sc, FIFOSZ); 533bf21cd93STycho Nightingale 534bf21cd93STycho Nightingale sc->fcr = value & 535bf21cd93STycho Nightingale (FCR_ENABLE | FCR_DMA | FCR_RX_MASK); 536bf21cd93STycho Nightingale } 537bf21cd93STycho Nightingale break; 538bf21cd93STycho Nightingale case REG_LCR: 539bf21cd93STycho Nightingale sc->lcr = value; 540bf21cd93STycho Nightingale break; 541bf21cd93STycho Nightingale case REG_MCR: 542bf21cd93STycho Nightingale /* Apply mask so that bits 5-7 are 0 */ 543bf21cd93STycho Nightingale sc->mcr = value & 0x1F; 5444c87aefeSPatrick Mooney msr = modem_status(sc->mcr); 545bf21cd93STycho Nightingale 546bf21cd93STycho Nightingale /* 547bf21cd93STycho Nightingale * Detect if there has been any change between the 548bf21cd93STycho Nightingale * previous and the new value of MSR. If there is 549bf21cd93STycho Nightingale * then assert the appropriate MSR delta bit. 550bf21cd93STycho Nightingale */ 551bf21cd93STycho Nightingale if ((msr & MSR_CTS) ^ (sc->msr & MSR_CTS)) 552bf21cd93STycho Nightingale sc->msr |= MSR_DCTS; 553bf21cd93STycho Nightingale if ((msr & MSR_DSR) ^ (sc->msr & MSR_DSR)) 554bf21cd93STycho Nightingale sc->msr |= MSR_DDSR; 555bf21cd93STycho Nightingale if ((msr & MSR_DCD) ^ (sc->msr & MSR_DCD)) 556bf21cd93STycho Nightingale sc->msr |= MSR_DDCD; 557bf21cd93STycho Nightingale if ((sc->msr & MSR_RI) != 0 && (msr & MSR_RI) == 0) 558bf21cd93STycho Nightingale sc->msr |= MSR_TERI; 559bf21cd93STycho Nightingale 560bf21cd93STycho Nightingale /* 561bf21cd93STycho Nightingale * Update the value of MSR while retaining the delta 562bf21cd93STycho Nightingale * bits. 563bf21cd93STycho Nightingale */ 564bf21cd93STycho Nightingale sc->msr &= MSR_DELTA_MASK; 565bf21cd93STycho Nightingale sc->msr |= msr; 566bf21cd93STycho Nightingale break; 567bf21cd93STycho Nightingale case REG_LSR: 568bf21cd93STycho Nightingale /* 569bf21cd93STycho Nightingale * Line status register is not meant to be written to 570bf21cd93STycho Nightingale * during normal operation. 571bf21cd93STycho Nightingale */ 572bf21cd93STycho Nightingale break; 573bf21cd93STycho Nightingale case REG_MSR: 574bf21cd93STycho Nightingale /* 575bf21cd93STycho Nightingale * As far as I can tell MSR is a read-only register. 576bf21cd93STycho Nightingale */ 577bf21cd93STycho Nightingale break; 578bf21cd93STycho Nightingale case REG_SCR: 579bf21cd93STycho Nightingale sc->scr = value; 580bf21cd93STycho Nightingale break; 581bf21cd93STycho Nightingale default: 582bf21cd93STycho Nightingale break; 583bf21cd93STycho Nightingale } 584bf21cd93STycho Nightingale 585bf21cd93STycho Nightingale done: 586bf21cd93STycho Nightingale uart_toggle_intr(sc); 587bf21cd93STycho Nightingale pthread_mutex_unlock(&sc->mtx); 588bf21cd93STycho Nightingale } 589bf21cd93STycho Nightingale 590bf21cd93STycho Nightingale uint8_t 591bf21cd93STycho Nightingale uart_read(struct uart_softc *sc, int offset) 592bf21cd93STycho Nightingale { 593bf21cd93STycho Nightingale uint8_t iir, intr_reason, reg; 594bf21cd93STycho Nightingale 595bf21cd93STycho Nightingale pthread_mutex_lock(&sc->mtx); 596bf21cd93STycho Nightingale 597bf21cd93STycho Nightingale /* 598bf21cd93STycho Nightingale * Take care of the special case DLAB accesses first 599bf21cd93STycho Nightingale */ 600bf21cd93STycho Nightingale if ((sc->lcr & LCR_DLAB) != 0) { 601bf21cd93STycho Nightingale if (offset == REG_DLL) { 602bf21cd93STycho Nightingale reg = sc->dll; 603bf21cd93STycho Nightingale goto done; 604bf21cd93STycho Nightingale } 605bf21cd93STycho Nightingale 606bf21cd93STycho Nightingale if (offset == REG_DLH) { 607bf21cd93STycho Nightingale reg = sc->dlh; 608bf21cd93STycho Nightingale goto done; 609bf21cd93STycho Nightingale } 610bf21cd93STycho Nightingale } 611bf21cd93STycho Nightingale 612bf21cd93STycho Nightingale switch (offset) { 613bf21cd93STycho Nightingale case REG_DATA: 6144c87aefeSPatrick Mooney reg = rxfifo_getchar(sc); 615bf21cd93STycho Nightingale break; 616bf21cd93STycho Nightingale case REG_IER: 617bf21cd93STycho Nightingale reg = sc->ier; 618bf21cd93STycho Nightingale break; 619bf21cd93STycho Nightingale case REG_IIR: 620bf21cd93STycho Nightingale iir = (sc->fcr & FCR_ENABLE) ? IIR_FIFO_MASK : 0; 621bf21cd93STycho Nightingale 622bf21cd93STycho Nightingale intr_reason = uart_intr_reason(sc); 623bf21cd93STycho Nightingale 624bf21cd93STycho Nightingale /* 625bf21cd93STycho Nightingale * Deal with side effects of reading the IIR register 626bf21cd93STycho Nightingale */ 627bf21cd93STycho Nightingale if (intr_reason == IIR_TXRDY) 628bf21cd93STycho Nightingale sc->thre_int_pending = false; 629bf21cd93STycho Nightingale 630bf21cd93STycho Nightingale iir |= intr_reason; 631bf21cd93STycho Nightingale 632bf21cd93STycho Nightingale reg = iir; 633bf21cd93STycho Nightingale break; 634bf21cd93STycho Nightingale case REG_LCR: 635bf21cd93STycho Nightingale reg = sc->lcr; 636bf21cd93STycho Nightingale break; 637bf21cd93STycho Nightingale case REG_MCR: 638bf21cd93STycho Nightingale reg = sc->mcr; 639bf21cd93STycho Nightingale break; 640bf21cd93STycho Nightingale case REG_LSR: 641bf21cd93STycho Nightingale /* Transmitter is always ready for more data */ 642bf21cd93STycho Nightingale sc->lsr |= LSR_TEMT | LSR_THRE; 643bf21cd93STycho Nightingale 644bf21cd93STycho Nightingale /* Check for new receive data */ 6454c87aefeSPatrick Mooney if (rxfifo_numchars(sc) > 0) 646bf21cd93STycho Nightingale sc->lsr |= LSR_RXRDY; 647bf21cd93STycho Nightingale else 648bf21cd93STycho Nightingale sc->lsr &= ~LSR_RXRDY; 649bf21cd93STycho Nightingale 650bf21cd93STycho Nightingale reg = sc->lsr; 651bf21cd93STycho Nightingale 652bf21cd93STycho Nightingale /* The LSR_OE bit is cleared on LSR read */ 653bf21cd93STycho Nightingale sc->lsr &= ~LSR_OE; 654bf21cd93STycho Nightingale break; 655bf21cd93STycho Nightingale case REG_MSR: 656bf21cd93STycho Nightingale /* 657bf21cd93STycho Nightingale * MSR delta bits are cleared on read 658bf21cd93STycho Nightingale */ 659bf21cd93STycho Nightingale reg = sc->msr; 660bf21cd93STycho Nightingale sc->msr &= ~MSR_DELTA_MASK; 661bf21cd93STycho Nightingale break; 662bf21cd93STycho Nightingale case REG_SCR: 663bf21cd93STycho Nightingale reg = sc->scr; 664bf21cd93STycho Nightingale break; 665bf21cd93STycho Nightingale default: 666bf21cd93STycho Nightingale reg = 0xFF; 667bf21cd93STycho Nightingale break; 668bf21cd93STycho Nightingale } 669bf21cd93STycho Nightingale 670bf21cd93STycho Nightingale done: 671bf21cd93STycho Nightingale uart_toggle_intr(sc); 672bf21cd93STycho Nightingale pthread_mutex_unlock(&sc->mtx); 673bf21cd93STycho Nightingale 674bf21cd93STycho Nightingale return (reg); 675bf21cd93STycho Nightingale } 676bf21cd93STycho Nightingale 677bf21cd93STycho Nightingale #ifndef __FreeBSD__ 678bf21cd93STycho Nightingale static void 6794c87aefeSPatrick Mooney uart_sock_drain(int fd, enum ev_type ev, void *arg) 680bf21cd93STycho Nightingale { 6814c87aefeSPatrick Mooney struct uart_softc *sc = arg; 6824c87aefeSPatrick Mooney char ch; 683bf21cd93STycho Nightingale 684bf21cd93STycho Nightingale /* 6854c87aefeSPatrick Mooney * Take the softc lock to protect against concurrent 6864c87aefeSPatrick Mooney * access from a vCPU i/o exit 687bf21cd93STycho Nightingale */ 6884c87aefeSPatrick Mooney pthread_mutex_lock(&sc->mtx); 689bf21cd93STycho Nightingale 6904c87aefeSPatrick Mooney if ((sc->mcr & MCR_LOOPBACK) != 0) { 6914c87aefeSPatrick Mooney (void) read(sc->usc_sock.clifd, &ch, 1); 6924c87aefeSPatrick Mooney } else { 6934c87aefeSPatrick Mooney bool err_close = false; 6944c87aefeSPatrick Mooney 6954c87aefeSPatrick Mooney while (rxfifo_available(sc)) { 696bf21cd93STycho Nightingale int res; 697bf21cd93STycho Nightingale 6984c87aefeSPatrick Mooney res = read(sc->usc_sock.clifd, &ch, 1); 6994c87aefeSPatrick Mooney if (res == 0) { 7004c87aefeSPatrick Mooney err_close = true; 7014c87aefeSPatrick Mooney break; 7024c87aefeSPatrick Mooney } else if (res == -1) { 7034c87aefeSPatrick Mooney if (errno != EAGAIN && errno != EINTR) { 7044c87aefeSPatrick Mooney err_close = true; 7054c87aefeSPatrick Mooney } 7064c87aefeSPatrick Mooney break; 707bf21cd93STycho Nightingale } 708bf21cd93STycho Nightingale 7094c87aefeSPatrick Mooney rxfifo_putchar(sc, ch); 7104c87aefeSPatrick Mooney } 7114c87aefeSPatrick Mooney uart_toggle_intr(sc); 7124c87aefeSPatrick Mooney 7134c87aefeSPatrick Mooney if (err_close) { 7144c87aefeSPatrick Mooney (void) fprintf(stderr, "uart: closing client conn\n"); 7154c87aefeSPatrick Mooney (void) shutdown(sc->usc_sock.clifd, SHUT_RDWR); 7164c87aefeSPatrick Mooney mevent_delete_close(sc->mev); 7174c87aefeSPatrick Mooney sc->mev = NULL; 7184c87aefeSPatrick Mooney sc->usc_sock.clifd = -1; 7194c87aefeSPatrick Mooney } 7204c87aefeSPatrick Mooney } 7214c87aefeSPatrick Mooney 7224c87aefeSPatrick Mooney pthread_mutex_unlock(&sc->mtx); 723bf21cd93STycho Nightingale } 724bf21cd93STycho Nightingale 725bf21cd93STycho Nightingale static void 7264c87aefeSPatrick Mooney uart_sock_accept(int fd, enum ev_type ev, void *arg) 727bf21cd93STycho Nightingale { 7284c87aefeSPatrick Mooney struct uart_softc *sc = arg; 7294c87aefeSPatrick Mooney int connfd; 730bf21cd93STycho Nightingale 7314c87aefeSPatrick Mooney connfd = accept(sc->usc_sock.servfd, NULL, NULL); 7324c87aefeSPatrick Mooney if (connfd == -1) { 733bf21cd93STycho Nightingale return; 734bf21cd93STycho Nightingale } 735bf21cd93STycho Nightingale 7364c87aefeSPatrick Mooney /* 7374c87aefeSPatrick Mooney * Do client connection management under protection of the softc lock 7384c87aefeSPatrick Mooney * to avoid racing with concurrent UART events. 7394c87aefeSPatrick Mooney */ 7404c87aefeSPatrick Mooney pthread_mutex_lock(&sc->mtx); 741bf21cd93STycho Nightingale 7424c87aefeSPatrick Mooney if (sc->usc_sock.clifd != -1) { 7434c87aefeSPatrick Mooney /* we're already handling a client */ 7444c87aefeSPatrick Mooney (void) fprintf(stderr, "uart: unexpected client conn\n"); 7454c87aefeSPatrick Mooney (void) shutdown(connfd, SHUT_RDWR); 7464c87aefeSPatrick Mooney (void) close(connfd); 747bf21cd93STycho Nightingale } else { 7484c87aefeSPatrick Mooney if (fcntl(connfd, F_SETFL, O_NONBLOCK) < 0) { 7494c87aefeSPatrick Mooney perror("uart: fcntl(O_NONBLOCK)"); 7504c87aefeSPatrick Mooney (void) shutdown(connfd, SHUT_RDWR); 7514c87aefeSPatrick Mooney (void) close(connfd); 752bf21cd93STycho Nightingale } else { 7534c87aefeSPatrick Mooney sc->usc_sock.clifd = connfd; 7544c87aefeSPatrick Mooney sc->mev = mevent_add(sc->usc_sock.clifd, EVF_READ, 7554c87aefeSPatrick Mooney uart_sock_drain, sc); 756bf21cd93STycho Nightingale } 757bf21cd93STycho Nightingale } 758bf21cd93STycho Nightingale 7594c87aefeSPatrick Mooney pthread_mutex_unlock(&sc->mtx); 760bf21cd93STycho Nightingale } 761bf21cd93STycho Nightingale 762bf21cd93STycho Nightingale static int 7634c87aefeSPatrick Mooney init_sock(const char *path) 764bf21cd93STycho Nightingale { 765bf21cd93STycho Nightingale int servfd; 766bf21cd93STycho Nightingale struct sockaddr_un servaddr; 767bf21cd93STycho Nightingale 7684c87aefeSPatrick Mooney bzero(&servaddr, sizeof (servaddr)); 7694c87aefeSPatrick Mooney servaddr.sun_family = AF_UNIX; 7704c87aefeSPatrick Mooney 7714c87aefeSPatrick Mooney if (strlcpy(servaddr.sun_path, path, sizeof (servaddr.sun_path)) >= 7724c87aefeSPatrick Mooney sizeof (servaddr.sun_path)) { 7734c87aefeSPatrick Mooney (void) fprintf(stderr, "uart: path '%s' too long\n", 7744c87aefeSPatrick Mooney path); 775bf21cd93STycho Nightingale return (-1); 776bf21cd93STycho Nightingale } 777bf21cd93STycho Nightingale 778bf21cd93STycho Nightingale if ((servfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { 7794c87aefeSPatrick Mooney (void) fprintf(stderr, "uart: socket() error - %s\n", 7804c87aefeSPatrick Mooney strerror(errno)); 781bf21cd93STycho Nightingale return (-1); 782bf21cd93STycho Nightingale } 783bf21cd93STycho Nightingale (void) unlink(servaddr.sun_path); 784bf21cd93STycho Nightingale 785bf21cd93STycho Nightingale if (bind(servfd, (struct sockaddr *)&servaddr, 786bf21cd93STycho Nightingale sizeof (servaddr)) == -1) { 7874c87aefeSPatrick Mooney (void) fprintf(stderr, "uart: bind() error - %s\n", 7884c87aefeSPatrick Mooney strerror(errno)); 789bf21cd93STycho Nightingale goto out; 790bf21cd93STycho Nightingale } 791bf21cd93STycho Nightingale 7924c87aefeSPatrick Mooney if (listen(servfd, 1) == -1) { 7934c87aefeSPatrick Mooney (void) fprintf(stderr, "uart: listen() error - %s\n", 7944c87aefeSPatrick Mooney strerror(errno)); 795bf21cd93STycho Nightingale goto out; 796bf21cd93STycho Nightingale } 797bf21cd93STycho Nightingale return (servfd); 798bf21cd93STycho Nightingale 799bf21cd93STycho Nightingale out: 800bf21cd93STycho Nightingale (void) unlink(servaddr.sun_path); 801bf21cd93STycho Nightingale (void) close(servfd); 802bf21cd93STycho Nightingale return (-1); 803bf21cd93STycho Nightingale } 8044c87aefeSPatrick Mooney #endif /* not __FreeBSD__ */ 805bf21cd93STycho Nightingale 806bf21cd93STycho Nightingale int 807bf21cd93STycho Nightingale uart_legacy_alloc(int which, int *baseaddr, int *irq) 808bf21cd93STycho Nightingale { 809bf21cd93STycho Nightingale 810bf21cd93STycho Nightingale if (which < 0 || which >= UART_NLDEVS || uart_lres[which].inuse) 811bf21cd93STycho Nightingale return (-1); 812bf21cd93STycho Nightingale 813bf21cd93STycho Nightingale uart_lres[which].inuse = true; 814bf21cd93STycho Nightingale *baseaddr = uart_lres[which].baseaddr; 815bf21cd93STycho Nightingale *irq = uart_lres[which].irq; 816bf21cd93STycho Nightingale 817bf21cd93STycho Nightingale return (0); 818bf21cd93STycho Nightingale } 819bf21cd93STycho Nightingale 820bf21cd93STycho Nightingale struct uart_softc * 821bf21cd93STycho Nightingale uart_init(uart_intr_func_t intr_assert, uart_intr_func_t intr_deassert, 822bf21cd93STycho Nightingale void *arg) 823bf21cd93STycho Nightingale { 824bf21cd93STycho Nightingale struct uart_softc *sc; 825bf21cd93STycho Nightingale 8264c87aefeSPatrick Mooney sc = calloc(1, sizeof(struct uart_softc)); 827bf21cd93STycho Nightingale 828bf21cd93STycho Nightingale sc->arg = arg; 829bf21cd93STycho Nightingale sc->intr_assert = intr_assert; 830bf21cd93STycho Nightingale sc->intr_deassert = intr_deassert; 831bf21cd93STycho Nightingale 832bf21cd93STycho Nightingale pthread_mutex_init(&sc->mtx, NULL); 833bf21cd93STycho Nightingale 834bf21cd93STycho Nightingale uart_reset(sc); 835bf21cd93STycho Nightingale 836bf21cd93STycho Nightingale return (sc); 837bf21cd93STycho Nightingale } 838bf21cd93STycho Nightingale 8394c87aefeSPatrick Mooney #ifndef __FreeBSD__ 8404c87aefeSPatrick Mooney static int 8414c87aefeSPatrick Mooney uart_sock_backend(struct uart_softc *sc, const char *inopts) 8424c87aefeSPatrick Mooney { 8434c87aefeSPatrick Mooney char *opts; 8444c87aefeSPatrick Mooney char *opt; 8454c87aefeSPatrick Mooney char *nextopt; 8464c87aefeSPatrick Mooney char *path = NULL; 8474c87aefeSPatrick Mooney 8484c87aefeSPatrick Mooney if (strncmp(inopts, "socket,", 7) != 0) { 8494c87aefeSPatrick Mooney return (-1); 8504c87aefeSPatrick Mooney } 8514c87aefeSPatrick Mooney if ((opts = strdup(inopts + 7)) == NULL) { 8524c87aefeSPatrick Mooney return (-1); 8534c87aefeSPatrick Mooney } 8544c87aefeSPatrick Mooney 8554c87aefeSPatrick Mooney nextopt = opts; 8564c87aefeSPatrick Mooney for (opt = strsep(&nextopt, ","); opt != NULL; 8574c87aefeSPatrick Mooney opt = strsep(&nextopt, ",")) { 8584c87aefeSPatrick Mooney if (path == NULL && *opt == '/') { 8594c87aefeSPatrick Mooney path = opt; 8604c87aefeSPatrick Mooney continue; 8614c87aefeSPatrick Mooney } 8624c87aefeSPatrick Mooney /* 8634c87aefeSPatrick Mooney * XXX check for server and client options here. For now, 8644c87aefeSPatrick Mooney * everything is a server 8654c87aefeSPatrick Mooney */ 8664c87aefeSPatrick Mooney free(opts); 8674c87aefeSPatrick Mooney return (-1); 8684c87aefeSPatrick Mooney } 8694c87aefeSPatrick Mooney 8704c87aefeSPatrick Mooney sc->usc_sock.clifd = -1; 8714c87aefeSPatrick Mooney if ((sc->usc_sock.servfd = init_sock(path)) == -1) { 8724c87aefeSPatrick Mooney free(opts); 8734c87aefeSPatrick Mooney return (-1); 8744c87aefeSPatrick Mooney } 8754c87aefeSPatrick Mooney sc->sock = true; 8764c87aefeSPatrick Mooney sc->tty.rfd = sc->tty.wfd = -1; 8774c87aefeSPatrick Mooney sc->usc_sock.servmev = mevent_add(sc->usc_sock.servfd, EVF_READ, 8784c87aefeSPatrick Mooney uart_sock_accept, sc); 8794c87aefeSPatrick Mooney assert(sc->usc_sock.servmev != NULL); 8804c87aefeSPatrick Mooney 8814c87aefeSPatrick Mooney return (0); 8824c87aefeSPatrick Mooney } 8834c87aefeSPatrick Mooney #endif /* not __FreeBSD__ */ 8844c87aefeSPatrick Mooney 8854c87aefeSPatrick Mooney static int 8864c87aefeSPatrick Mooney uart_stdio_backend(struct uart_softc *sc) 8874c87aefeSPatrick Mooney { 8884c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM 8894c87aefeSPatrick Mooney cap_rights_t rights; 8904c87aefeSPatrick Mooney cap_ioctl_t cmds[] = { TIOCGETA, TIOCSETA, TIOCGWINSZ }; 8914c87aefeSPatrick Mooney #endif 8924c87aefeSPatrick Mooney 8934c87aefeSPatrick Mooney if (uart_stdio) 8944c87aefeSPatrick Mooney return (-1); 8954c87aefeSPatrick Mooney 8964c87aefeSPatrick Mooney sc->tty.rfd = STDIN_FILENO; 8974c87aefeSPatrick Mooney sc->tty.wfd = STDOUT_FILENO; 8984c87aefeSPatrick Mooney sc->tty.opened = true; 8994c87aefeSPatrick Mooney 9004c87aefeSPatrick Mooney if (fcntl(sc->tty.rfd, F_SETFL, O_NONBLOCK) != 0) 9014c87aefeSPatrick Mooney return (-1); 9024c87aefeSPatrick Mooney if (fcntl(sc->tty.wfd, F_SETFL, O_NONBLOCK) != 0) 9034c87aefeSPatrick Mooney return (-1); 9044c87aefeSPatrick Mooney 9054c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM 9064c87aefeSPatrick Mooney cap_rights_init(&rights, CAP_EVENT, CAP_IOCTL, CAP_READ); 9074c87aefeSPatrick Mooney if (caph_rights_limit(sc->tty.rfd, &rights) == -1) 9084c87aefeSPatrick Mooney errx(EX_OSERR, "Unable to apply rights for sandbox"); 9094c87aefeSPatrick Mooney if (caph_ioctls_limit(sc->tty.rfd, cmds, nitems(cmds)) == -1) 9104c87aefeSPatrick Mooney errx(EX_OSERR, "Unable to apply rights for sandbox"); 9114c87aefeSPatrick Mooney #endif 9124c87aefeSPatrick Mooney 9134c87aefeSPatrick Mooney uart_stdio = true; 9144c87aefeSPatrick Mooney 9154c87aefeSPatrick Mooney return (0); 9164c87aefeSPatrick Mooney } 9174c87aefeSPatrick Mooney 9184c87aefeSPatrick Mooney static int 9194c87aefeSPatrick Mooney uart_tty_backend(struct uart_softc *sc, const char *opts) 9204c87aefeSPatrick Mooney { 9214c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM 9224c87aefeSPatrick Mooney cap_rights_t rights; 9234c87aefeSPatrick Mooney cap_ioctl_t cmds[] = { TIOCGETA, TIOCSETA, TIOCGWINSZ }; 9244c87aefeSPatrick Mooney #endif 9254c87aefeSPatrick Mooney int fd; 9264c87aefeSPatrick Mooney 9274c87aefeSPatrick Mooney fd = open(opts, O_RDWR | O_NONBLOCK); 92884659b24SMichael Zeller if (fd < 0) 9294c87aefeSPatrick Mooney return (-1); 9304c87aefeSPatrick Mooney 93184659b24SMichael Zeller if (!isatty(fd)) { 93284659b24SMichael Zeller close(fd); 93384659b24SMichael Zeller return (-1); 93484659b24SMichael Zeller } 93584659b24SMichael Zeller 9364c87aefeSPatrick Mooney sc->tty.rfd = sc->tty.wfd = fd; 9374c87aefeSPatrick Mooney sc->tty.opened = true; 9384c87aefeSPatrick Mooney 9394c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM 9404c87aefeSPatrick Mooney cap_rights_init(&rights, CAP_EVENT, CAP_IOCTL, CAP_READ, CAP_WRITE); 9414c87aefeSPatrick Mooney if (caph_rights_limit(fd, &rights) == -1) 9424c87aefeSPatrick Mooney errx(EX_OSERR, "Unable to apply rights for sandbox"); 9434c87aefeSPatrick Mooney if (caph_ioctls_limit(fd, cmds, nitems(cmds)) == -1) 9444c87aefeSPatrick Mooney errx(EX_OSERR, "Unable to apply rights for sandbox"); 9454c87aefeSPatrick Mooney #endif 9464c87aefeSPatrick Mooney 9474c87aefeSPatrick Mooney return (0); 9484c87aefeSPatrick Mooney } 9494c87aefeSPatrick Mooney 950bf21cd93STycho Nightingale int 951bf21cd93STycho Nightingale uart_set_backend(struct uart_softc *sc, const char *opts) 952bf21cd93STycho Nightingale { 9534c87aefeSPatrick Mooney int retval; 9544c87aefeSPatrick Mooney 955bf21cd93STycho Nightingale if (opts == NULL) 956bf21cd93STycho Nightingale return (0); 957bf21cd93STycho Nightingale 9584c87aefeSPatrick Mooney #ifndef __FreeBSD__ 9594c87aefeSPatrick Mooney if (strncmp("socket,", opts, 7) == 0) 9604c87aefeSPatrick Mooney return (uart_sock_backend(sc, opts)); 961bf21cd93STycho Nightingale #endif 9624c87aefeSPatrick Mooney if (strcmp("stdio", opts) == 0) 9634c87aefeSPatrick Mooney retval = uart_stdio_backend(sc); 9644c87aefeSPatrick Mooney else 9654c87aefeSPatrick Mooney retval = uart_tty_backend(sc, opts); 9664c87aefeSPatrick Mooney if (retval == 0) 9674c87aefeSPatrick Mooney uart_opentty(sc); 9684c87aefeSPatrick Mooney 9694c87aefeSPatrick Mooney return (retval); 970bf21cd93STycho Nightingale } 971