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" 74bf21cd93STycho Nightingale 75bf21cd93STycho Nightingale #define COM1_BASE 0x3F8 76bf21cd93STycho Nightingale #define COM1_IRQ 4 77bf21cd93STycho Nightingale #define COM2_BASE 0x2F8 78bf21cd93STycho Nightingale #define COM2_IRQ 3 79bf21cd93STycho Nightingale 80bf21cd93STycho Nightingale #define DEFAULT_RCLK 1843200 81bf21cd93STycho Nightingale #define DEFAULT_BAUD 9600 82bf21cd93STycho Nightingale 83bf21cd93STycho Nightingale #define FCR_RX_MASK 0xC0 84bf21cd93STycho Nightingale 85bf21cd93STycho Nightingale #define MCR_OUT1 0x04 86bf21cd93STycho Nightingale #define MCR_OUT2 0x08 87bf21cd93STycho Nightingale 88bf21cd93STycho Nightingale #define MSR_DELTA_MASK 0x0f 89bf21cd93STycho Nightingale 90bf21cd93STycho Nightingale #ifndef REG_SCR 91bf21cd93STycho Nightingale #define REG_SCR com_scr 92bf21cd93STycho Nightingale #endif 93bf21cd93STycho Nightingale 94bf21cd93STycho Nightingale #define FIFOSZ 16 95bf21cd93STycho Nightingale 96bf21cd93STycho Nightingale static bool uart_stdio; /* stdio in use for i/o */ 974c87aefeSPatrick Mooney static struct termios tio_stdio_orig; 98bf21cd93STycho Nightingale 99bf21cd93STycho Nightingale static struct { 100bf21cd93STycho Nightingale int baseaddr; 101bf21cd93STycho Nightingale int irq; 102bf21cd93STycho Nightingale bool inuse; 103bf21cd93STycho Nightingale } uart_lres[] = { 104bf21cd93STycho Nightingale { COM1_BASE, COM1_IRQ, false}, 105bf21cd93STycho Nightingale { COM2_BASE, COM2_IRQ, false}, 106bf21cd93STycho Nightingale }; 107bf21cd93STycho Nightingale 108bf21cd93STycho Nightingale #define UART_NLDEVS (sizeof(uart_lres) / sizeof(uart_lres[0])) 109bf21cd93STycho Nightingale 110bf21cd93STycho Nightingale struct fifo { 111bf21cd93STycho Nightingale uint8_t buf[FIFOSZ]; 112bf21cd93STycho Nightingale int rindex; /* index to read from */ 113bf21cd93STycho Nightingale int windex; /* index to write to */ 114bf21cd93STycho Nightingale int num; /* number of characters in the fifo */ 115bf21cd93STycho Nightingale int size; /* size of the fifo */ 116bf21cd93STycho Nightingale }; 117bf21cd93STycho Nightingale 1184c87aefeSPatrick Mooney struct ttyfd { 1194c87aefeSPatrick Mooney bool opened; 1204c87aefeSPatrick Mooney int rfd; /* fd for reading */ 1214c87aefeSPatrick Mooney int wfd; /* fd for writing, may be == rfd */ 1224c87aefeSPatrick Mooney }; 1234c87aefeSPatrick Mooney 124bf21cd93STycho Nightingale struct uart_softc { 125bf21cd93STycho Nightingale pthread_mutex_t mtx; /* protects all softc elements */ 126bf21cd93STycho Nightingale uint8_t data; /* Data register (R/W) */ 127bf21cd93STycho Nightingale uint8_t ier; /* Interrupt enable register (R/W) */ 128bf21cd93STycho Nightingale uint8_t lcr; /* Line control register (R/W) */ 129bf21cd93STycho Nightingale uint8_t mcr; /* Modem control register (R/W) */ 130bf21cd93STycho Nightingale uint8_t lsr; /* Line status register (R/W) */ 131bf21cd93STycho Nightingale uint8_t msr; /* Modem status register (R/W) */ 132bf21cd93STycho Nightingale uint8_t fcr; /* FIFO control register (W) */ 133bf21cd93STycho Nightingale uint8_t scr; /* Scratch register (R/W) */ 134bf21cd93STycho Nightingale 135bf21cd93STycho Nightingale uint8_t dll; /* Baudrate divisor latch LSB */ 136bf21cd93STycho Nightingale uint8_t dlh; /* Baudrate divisor latch MSB */ 137bf21cd93STycho Nightingale 138bf21cd93STycho Nightingale struct fifo rxfifo; 1394c87aefeSPatrick Mooney struct mevent *mev; 140bf21cd93STycho Nightingale 1414c87aefeSPatrick Mooney struct ttyfd tty; 142bf21cd93STycho Nightingale #ifndef __FreeBSD__ 1434c87aefeSPatrick Mooney bool sock; 144bf21cd93STycho Nightingale struct { 145bf21cd93STycho Nightingale int clifd; /* console client unix domain socket */ 146bf21cd93STycho Nightingale int servfd; /* console server unix domain socket */ 1474c87aefeSPatrick Mooney struct mevent *servmev; /* mevent for server socket */ 1484c87aefeSPatrick Mooney } usc_sock; 149bf21cd93STycho Nightingale #endif 150bf21cd93STycho Nightingale 151bf21cd93STycho Nightingale bool thre_int_pending; /* THRE interrupt pending */ 152bf21cd93STycho Nightingale 153bf21cd93STycho Nightingale void *arg; 154bf21cd93STycho Nightingale uart_intr_func_t intr_assert; 155bf21cd93STycho Nightingale uart_intr_func_t intr_deassert; 156bf21cd93STycho Nightingale }; 157bf21cd93STycho Nightingale 158bf21cd93STycho Nightingale static void uart_drain(int fd, enum ev_type ev, void *arg); 159bf21cd93STycho Nightingale 160bf21cd93STycho Nightingale static void 161bf21cd93STycho Nightingale ttyclose(void) 162bf21cd93STycho Nightingale { 163bf21cd93STycho Nightingale 1644c87aefeSPatrick Mooney tcsetattr(STDIN_FILENO, TCSANOW, &tio_stdio_orig); 165bf21cd93STycho Nightingale } 166bf21cd93STycho Nightingale 167bf21cd93STycho Nightingale static void 1684c87aefeSPatrick Mooney ttyopen(struct ttyfd *tf) 169bf21cd93STycho Nightingale { 1704c87aefeSPatrick Mooney struct termios orig, new; 171bf21cd93STycho Nightingale 1724c87aefeSPatrick Mooney tcgetattr(tf->rfd, &orig); 1734c87aefeSPatrick Mooney new = orig; 1744c87aefeSPatrick Mooney cfmakeraw(&new); 1754c87aefeSPatrick Mooney new.c_cflag |= CLOCAL; 1764c87aefeSPatrick Mooney tcsetattr(tf->rfd, TCSANOW, &new); 1774c87aefeSPatrick Mooney if (uart_stdio) { 1784c87aefeSPatrick Mooney tio_stdio_orig = orig; 179bf21cd93STycho Nightingale atexit(ttyclose); 180bf21cd93STycho Nightingale } 181bf21cd93STycho Nightingale } 182bf21cd93STycho Nightingale 183bf21cd93STycho Nightingale static int 1844c87aefeSPatrick Mooney ttyread(struct ttyfd *tf) 185bf21cd93STycho Nightingale { 1864c87aefeSPatrick Mooney unsigned char rb; 187bf21cd93STycho Nightingale 1884c87aefeSPatrick Mooney if (read(tf->rfd, &rb, 1) == 1) 1894c87aefeSPatrick Mooney return (rb); 1904c87aefeSPatrick Mooney else 191bf21cd93STycho Nightingale return (-1); 192bf21cd93STycho Nightingale } 193bf21cd93STycho Nightingale 194bf21cd93STycho Nightingale static void 1954c87aefeSPatrick Mooney ttywrite(struct ttyfd *tf, unsigned char wb) 196bf21cd93STycho Nightingale { 197bf21cd93STycho Nightingale 1984c87aefeSPatrick Mooney (void)write(tf->wfd, &wb, 1); 199bf21cd93STycho Nightingale } 200bf21cd93STycho Nightingale 201bf21cd93STycho Nightingale #ifndef __FreeBSD__ 202bf21cd93STycho Nightingale static void 2034c87aefeSPatrick Mooney sockwrite(struct uart_softc *sc, unsigned char wb) 204bf21cd93STycho Nightingale { 2054c87aefeSPatrick Mooney (void) write(sc->usc_sock.clifd, &wb, 1); 206bf21cd93STycho Nightingale } 207bf21cd93STycho Nightingale #endif 208bf21cd93STycho Nightingale 209bf21cd93STycho Nightingale static void 2104c87aefeSPatrick Mooney rxfifo_reset(struct uart_softc *sc, int size) 211bf21cd93STycho Nightingale { 2124c87aefeSPatrick Mooney char flushbuf[32]; 2134c87aefeSPatrick Mooney struct fifo *fifo; 2144c87aefeSPatrick Mooney ssize_t nread; 2154c87aefeSPatrick Mooney int error; 2164c87aefeSPatrick Mooney 2174c87aefeSPatrick Mooney fifo = &sc->rxfifo; 218bf21cd93STycho Nightingale bzero(fifo, sizeof(struct fifo)); 219bf21cd93STycho Nightingale fifo->size = size; 2204c87aefeSPatrick Mooney 2214c87aefeSPatrick Mooney if (sc->tty.opened) { 2224c87aefeSPatrick Mooney /* 2234c87aefeSPatrick Mooney * Flush any unread input from the tty buffer. 2244c87aefeSPatrick Mooney */ 2254c87aefeSPatrick Mooney while (1) { 2264c87aefeSPatrick Mooney nread = read(sc->tty.rfd, flushbuf, sizeof(flushbuf)); 2274c87aefeSPatrick Mooney if (nread != sizeof(flushbuf)) 2284c87aefeSPatrick Mooney break; 2294c87aefeSPatrick Mooney } 2304c87aefeSPatrick Mooney 2314c87aefeSPatrick Mooney /* 2324c87aefeSPatrick Mooney * Enable mevent to trigger when new characters are available 2334c87aefeSPatrick Mooney * on the tty fd. 2344c87aefeSPatrick Mooney */ 2354c87aefeSPatrick Mooney error = mevent_enable(sc->mev); 2364c87aefeSPatrick Mooney assert(error == 0); 2374c87aefeSPatrick Mooney } 2384c87aefeSPatrick Mooney #ifndef __FreeBSD__ 2394c87aefeSPatrick Mooney if (sc->sock && sc->usc_sock.clifd != -1) { 2404c87aefeSPatrick Mooney /* Flush any unread input from the socket buffer. */ 2414c87aefeSPatrick Mooney do { 2424c87aefeSPatrick Mooney nread = read(sc->usc_sock.clifd, flushbuf, 2434c87aefeSPatrick Mooney sizeof (flushbuf)); 2444c87aefeSPatrick Mooney } while (nread == sizeof (flushbuf)); 2454c87aefeSPatrick Mooney 2464c87aefeSPatrick Mooney /* Enable mevent to trigger when new data available on sock */ 2474c87aefeSPatrick Mooney error = mevent_enable(sc->mev); 2484c87aefeSPatrick Mooney assert(error == 0); 2494c87aefeSPatrick Mooney } 2504c87aefeSPatrick Mooney #endif /* __FreeBSD__ */ 251bf21cd93STycho Nightingale } 252bf21cd93STycho Nightingale 253bf21cd93STycho Nightingale static int 2544c87aefeSPatrick Mooney rxfifo_available(struct uart_softc *sc) 255bf21cd93STycho Nightingale { 2564c87aefeSPatrick Mooney struct fifo *fifo; 2574c87aefeSPatrick Mooney 2584c87aefeSPatrick Mooney fifo = &sc->rxfifo; 2594c87aefeSPatrick Mooney return (fifo->num < fifo->size); 2604c87aefeSPatrick Mooney } 2614c87aefeSPatrick Mooney 2624c87aefeSPatrick Mooney static int 2634c87aefeSPatrick Mooney rxfifo_putchar(struct uart_softc *sc, uint8_t ch) 2644c87aefeSPatrick Mooney { 2654c87aefeSPatrick Mooney struct fifo *fifo; 2664c87aefeSPatrick Mooney int error; 2674c87aefeSPatrick Mooney 2684c87aefeSPatrick Mooney fifo = &sc->rxfifo; 269bf21cd93STycho Nightingale 270bf21cd93STycho Nightingale if (fifo->num < fifo->size) { 271bf21cd93STycho Nightingale fifo->buf[fifo->windex] = ch; 272bf21cd93STycho Nightingale fifo->windex = (fifo->windex + 1) % fifo->size; 273bf21cd93STycho Nightingale fifo->num++; 2744c87aefeSPatrick Mooney if (!rxfifo_available(sc)) { 2754c87aefeSPatrick Mooney if (sc->tty.opened) { 2764c87aefeSPatrick Mooney /* 2774c87aefeSPatrick Mooney * Disable mevent callback if the FIFO is full. 2784c87aefeSPatrick Mooney */ 2794c87aefeSPatrick Mooney error = mevent_disable(sc->mev); 2804c87aefeSPatrick Mooney assert(error == 0); 2814c87aefeSPatrick Mooney } 2824c87aefeSPatrick Mooney #ifndef __FreeBSD__ 2834c87aefeSPatrick Mooney if (sc->sock && sc->usc_sock.clifd != -1) { 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 #endif /* __FreeBSD__ */ 2914c87aefeSPatrick Mooney } 292bf21cd93STycho Nightingale return (0); 293bf21cd93STycho Nightingale } else 294bf21cd93STycho Nightingale return (-1); 295bf21cd93STycho Nightingale } 296bf21cd93STycho Nightingale 297bf21cd93STycho Nightingale static int 2984c87aefeSPatrick Mooney rxfifo_getchar(struct uart_softc *sc) 299bf21cd93STycho Nightingale { 3004c87aefeSPatrick Mooney struct fifo *fifo; 3014c87aefeSPatrick Mooney int c, error, wasfull; 302bf21cd93STycho Nightingale 3034c87aefeSPatrick Mooney wasfull = 0; 3044c87aefeSPatrick Mooney fifo = &sc->rxfifo; 305bf21cd93STycho Nightingale if (fifo->num > 0) { 3064c87aefeSPatrick Mooney if (!rxfifo_available(sc)) 3074c87aefeSPatrick Mooney wasfull = 1; 308bf21cd93STycho Nightingale c = fifo->buf[fifo->rindex]; 309bf21cd93STycho Nightingale fifo->rindex = (fifo->rindex + 1) % fifo->size; 310bf21cd93STycho Nightingale fifo->num--; 3114c87aefeSPatrick Mooney if (wasfull) { 3124c87aefeSPatrick Mooney if (sc->tty.opened) { 3134c87aefeSPatrick Mooney error = mevent_enable(sc->mev); 3144c87aefeSPatrick Mooney assert(error == 0); 3154c87aefeSPatrick Mooney } 3164c87aefeSPatrick Mooney #ifndef __FreeBSD__ 3174c87aefeSPatrick Mooney if (sc->sock && sc->usc_sock.clifd != -1) { 3184c87aefeSPatrick Mooney error = mevent_enable(sc->mev); 3194c87aefeSPatrick Mooney assert(error == 0); 3204c87aefeSPatrick Mooney } 3214c87aefeSPatrick Mooney #endif /* __FreeBSD__ */ 3224c87aefeSPatrick Mooney } 323bf21cd93STycho Nightingale return (c); 324bf21cd93STycho Nightingale } else 325bf21cd93STycho Nightingale return (-1); 326bf21cd93STycho Nightingale } 327bf21cd93STycho Nightingale 328bf21cd93STycho Nightingale static int 3294c87aefeSPatrick Mooney rxfifo_numchars(struct uart_softc *sc) 330bf21cd93STycho Nightingale { 3314c87aefeSPatrick Mooney struct fifo *fifo = &sc->rxfifo; 332bf21cd93STycho Nightingale 333bf21cd93STycho Nightingale return (fifo->num); 334bf21cd93STycho Nightingale } 335bf21cd93STycho Nightingale 336bf21cd93STycho Nightingale static void 337bf21cd93STycho Nightingale uart_opentty(struct uart_softc *sc) 338bf21cd93STycho Nightingale { 339bf21cd93STycho Nightingale 3404c87aefeSPatrick Mooney ttyopen(&sc->tty); 3414c87aefeSPatrick Mooney sc->mev = mevent_add(sc->tty.rfd, EVF_READ, uart_drain, sc); 3424c87aefeSPatrick Mooney assert(sc->mev != NULL); 3434c87aefeSPatrick Mooney } 344bf21cd93STycho Nightingale 3454c87aefeSPatrick Mooney static uint8_t 3464c87aefeSPatrick Mooney modem_status(uint8_t mcr) 3474c87aefeSPatrick Mooney { 3484c87aefeSPatrick Mooney uint8_t msr; 3494c87aefeSPatrick Mooney 3504c87aefeSPatrick Mooney if (mcr & MCR_LOOPBACK) { 3514c87aefeSPatrick Mooney /* 3524c87aefeSPatrick Mooney * In the loopback mode certain bits from the MCR are 3534c87aefeSPatrick Mooney * reflected back into MSR. 3544c87aefeSPatrick Mooney */ 3554c87aefeSPatrick Mooney msr = 0; 3564c87aefeSPatrick Mooney if (mcr & MCR_RTS) 3574c87aefeSPatrick Mooney msr |= MSR_CTS; 3584c87aefeSPatrick Mooney if (mcr & MCR_DTR) 3594c87aefeSPatrick Mooney msr |= MSR_DSR; 3604c87aefeSPatrick Mooney if (mcr & MCR_OUT1) 3614c87aefeSPatrick Mooney msr |= MSR_RI; 3624c87aefeSPatrick Mooney if (mcr & MCR_OUT2) 3634c87aefeSPatrick Mooney msr |= MSR_DCD; 3644c87aefeSPatrick Mooney } else { 3654c87aefeSPatrick Mooney /* 3664c87aefeSPatrick Mooney * Always assert DCD and DSR so tty open doesn't block 3674c87aefeSPatrick Mooney * even if CLOCAL is turned off. 3684c87aefeSPatrick Mooney */ 3694c87aefeSPatrick Mooney msr = MSR_DCD | MSR_DSR; 3704c87aefeSPatrick Mooney } 3714c87aefeSPatrick Mooney assert((msr & MSR_DELTA_MASK) == 0); 3724c87aefeSPatrick Mooney 3734c87aefeSPatrick Mooney return (msr); 374bf21cd93STycho Nightingale } 375bf21cd93STycho Nightingale 376bf21cd93STycho Nightingale /* 377bf21cd93STycho Nightingale * The IIR returns a prioritized interrupt reason: 378bf21cd93STycho Nightingale * - receive data available 379bf21cd93STycho Nightingale * - transmit holding register empty 380bf21cd93STycho Nightingale * - modem status change 381bf21cd93STycho Nightingale * 382bf21cd93STycho Nightingale * Return an interrupt reason if one is available. 383bf21cd93STycho Nightingale */ 384bf21cd93STycho Nightingale static int 385bf21cd93STycho Nightingale uart_intr_reason(struct uart_softc *sc) 386bf21cd93STycho Nightingale { 387bf21cd93STycho Nightingale 388bf21cd93STycho Nightingale if ((sc->lsr & LSR_OE) != 0 && (sc->ier & IER_ERLS) != 0) 389bf21cd93STycho Nightingale return (IIR_RLS); 3904c87aefeSPatrick Mooney else if (rxfifo_numchars(sc) > 0 && (sc->ier & IER_ERXRDY) != 0) 391bf21cd93STycho Nightingale return (IIR_RXTOUT); 392bf21cd93STycho Nightingale else if (sc->thre_int_pending && (sc->ier & IER_ETXRDY) != 0) 393bf21cd93STycho Nightingale return (IIR_TXRDY); 394bf21cd93STycho Nightingale else if ((sc->msr & MSR_DELTA_MASK) != 0 && (sc->ier & IER_EMSC) != 0) 395bf21cd93STycho Nightingale return (IIR_MLSC); 396bf21cd93STycho Nightingale else 397bf21cd93STycho Nightingale return (IIR_NOPEND); 398bf21cd93STycho Nightingale } 399bf21cd93STycho Nightingale 400bf21cd93STycho Nightingale static void 401bf21cd93STycho Nightingale uart_reset(struct uart_softc *sc) 402bf21cd93STycho Nightingale { 403bf21cd93STycho Nightingale uint16_t divisor; 404bf21cd93STycho Nightingale 405bf21cd93STycho Nightingale divisor = DEFAULT_RCLK / DEFAULT_BAUD / 16; 406bf21cd93STycho Nightingale sc->dll = divisor; 4074c87aefeSPatrick Mooney #ifndef __FreeBSD__ 4084c87aefeSPatrick Mooney sc->dlh = 0; 4094c87aefeSPatrick Mooney #else 410bf21cd93STycho Nightingale sc->dlh = divisor >> 16; 4114c87aefeSPatrick Mooney #endif 4124c87aefeSPatrick Mooney sc->msr = modem_status(sc->mcr); 413bf21cd93STycho Nightingale 4144c87aefeSPatrick Mooney rxfifo_reset(sc, 1); /* no fifo until enabled by software */ 415bf21cd93STycho Nightingale } 416bf21cd93STycho Nightingale 417bf21cd93STycho Nightingale /* 418bf21cd93STycho Nightingale * Toggle the COM port's intr pin depending on whether or not we have an 419bf21cd93STycho Nightingale * interrupt condition to report to the processor. 420bf21cd93STycho Nightingale */ 421bf21cd93STycho Nightingale static void 422bf21cd93STycho Nightingale uart_toggle_intr(struct uart_softc *sc) 423bf21cd93STycho Nightingale { 424bf21cd93STycho Nightingale uint8_t intr_reason; 425bf21cd93STycho Nightingale 426bf21cd93STycho Nightingale intr_reason = uart_intr_reason(sc); 427bf21cd93STycho Nightingale 428bf21cd93STycho Nightingale if (intr_reason == IIR_NOPEND) 429bf21cd93STycho Nightingale (*sc->intr_deassert)(sc->arg); 430bf21cd93STycho Nightingale else 431bf21cd93STycho Nightingale (*sc->intr_assert)(sc->arg); 432bf21cd93STycho Nightingale } 433bf21cd93STycho Nightingale 434bf21cd93STycho Nightingale static void 435bf21cd93STycho Nightingale uart_drain(int fd, enum ev_type ev, void *arg) 436bf21cd93STycho Nightingale { 437bf21cd93STycho Nightingale struct uart_softc *sc; 438bf21cd93STycho Nightingale int ch; 439bf21cd93STycho Nightingale 440bf21cd93STycho Nightingale sc = arg; 441bf21cd93STycho Nightingale 4424c87aefeSPatrick Mooney assert(fd == sc->tty.rfd); 443bf21cd93STycho Nightingale assert(ev == EVF_READ); 444bf21cd93STycho Nightingale 445bf21cd93STycho Nightingale /* 446bf21cd93STycho Nightingale * This routine is called in the context of the mevent thread 447bf21cd93STycho Nightingale * to take out the softc lock to protect against concurrent 448bf21cd93STycho Nightingale * access from a vCPU i/o exit 449bf21cd93STycho Nightingale */ 450bf21cd93STycho Nightingale pthread_mutex_lock(&sc->mtx); 451bf21cd93STycho Nightingale 452bf21cd93STycho Nightingale if ((sc->mcr & MCR_LOOPBACK) != 0) { 4534c87aefeSPatrick Mooney (void) ttyread(&sc->tty); 454bf21cd93STycho Nightingale } else { 4554c87aefeSPatrick Mooney while (rxfifo_available(sc) && 4564c87aefeSPatrick Mooney ((ch = ttyread(&sc->tty)) != -1)) { 4574c87aefeSPatrick Mooney rxfifo_putchar(sc, ch); 458bf21cd93STycho Nightingale } 459bf21cd93STycho Nightingale uart_toggle_intr(sc); 460bf21cd93STycho Nightingale } 461bf21cd93STycho Nightingale 462bf21cd93STycho Nightingale pthread_mutex_unlock(&sc->mtx); 463bf21cd93STycho Nightingale } 464bf21cd93STycho Nightingale 465bf21cd93STycho Nightingale void 466bf21cd93STycho Nightingale uart_write(struct uart_softc *sc, int offset, uint8_t value) 467bf21cd93STycho Nightingale { 468bf21cd93STycho Nightingale int fifosz; 469bf21cd93STycho Nightingale uint8_t msr; 470bf21cd93STycho Nightingale 471bf21cd93STycho Nightingale pthread_mutex_lock(&sc->mtx); 472bf21cd93STycho Nightingale 473bf21cd93STycho Nightingale /* 474bf21cd93STycho Nightingale * Take care of the special case DLAB accesses first 475bf21cd93STycho Nightingale */ 476bf21cd93STycho Nightingale if ((sc->lcr & LCR_DLAB) != 0) { 477bf21cd93STycho Nightingale if (offset == REG_DLL) { 478bf21cd93STycho Nightingale sc->dll = value; 479bf21cd93STycho Nightingale goto done; 480bf21cd93STycho Nightingale } 481bf21cd93STycho Nightingale 482bf21cd93STycho Nightingale if (offset == REG_DLH) { 483bf21cd93STycho Nightingale sc->dlh = value; 484bf21cd93STycho Nightingale goto done; 485bf21cd93STycho Nightingale } 486bf21cd93STycho Nightingale } 487bf21cd93STycho Nightingale 488bf21cd93STycho Nightingale switch (offset) { 489bf21cd93STycho Nightingale case REG_DATA: 490bf21cd93STycho Nightingale if (sc->mcr & MCR_LOOPBACK) { 4914c87aefeSPatrick Mooney if (rxfifo_putchar(sc, value) != 0) 492bf21cd93STycho Nightingale sc->lsr |= LSR_OE; 4934c87aefeSPatrick Mooney } else if (sc->tty.opened) { 4944c87aefeSPatrick Mooney ttywrite(&sc->tty, value); 495bf21cd93STycho Nightingale #ifndef __FreeBSD__ 4964c87aefeSPatrick Mooney } else if (sc->sock) { 4974c87aefeSPatrick Mooney sockwrite(sc, value); 498bf21cd93STycho Nightingale #endif 499bf21cd93STycho Nightingale } /* else drop on floor */ 500bf21cd93STycho Nightingale sc->thre_int_pending = true; 501bf21cd93STycho Nightingale break; 502bf21cd93STycho Nightingale case REG_IER: 5034c87aefeSPatrick Mooney /* Set pending when IER_ETXRDY is raised (edge-triggered). */ 5044c87aefeSPatrick Mooney if ((sc->ier & IER_ETXRDY) == 0 && (value & IER_ETXRDY) != 0) 5054c87aefeSPatrick Mooney sc->thre_int_pending = true; 506bf21cd93STycho Nightingale /* 507bf21cd93STycho Nightingale * Apply mask so that bits 4-7 are 0 508bf21cd93STycho Nightingale * Also enables bits 0-3 only if they're 1 509bf21cd93STycho Nightingale */ 510bf21cd93STycho Nightingale sc->ier = value & 0x0F; 511bf21cd93STycho Nightingale break; 512bf21cd93STycho Nightingale case REG_FCR: 513bf21cd93STycho Nightingale /* 514bf21cd93STycho Nightingale * When moving from FIFO and 16450 mode and vice versa, 515bf21cd93STycho Nightingale * the FIFO contents are reset. 516bf21cd93STycho Nightingale */ 517bf21cd93STycho Nightingale if ((sc->fcr & FCR_ENABLE) ^ (value & FCR_ENABLE)) { 518bf21cd93STycho Nightingale fifosz = (value & FCR_ENABLE) ? FIFOSZ : 1; 5194c87aefeSPatrick Mooney rxfifo_reset(sc, fifosz); 520bf21cd93STycho Nightingale } 521bf21cd93STycho Nightingale 522bf21cd93STycho Nightingale /* 523bf21cd93STycho Nightingale * The FCR_ENABLE bit must be '1' for the programming 524bf21cd93STycho Nightingale * of other FCR bits to be effective. 525bf21cd93STycho Nightingale */ 526bf21cd93STycho Nightingale if ((value & FCR_ENABLE) == 0) { 527bf21cd93STycho Nightingale sc->fcr = 0; 528bf21cd93STycho Nightingale } else { 529bf21cd93STycho Nightingale if ((value & FCR_RCV_RST) != 0) 5304c87aefeSPatrick Mooney rxfifo_reset(sc, FIFOSZ); 531bf21cd93STycho Nightingale 532bf21cd93STycho Nightingale sc->fcr = value & 533bf21cd93STycho Nightingale (FCR_ENABLE | FCR_DMA | FCR_RX_MASK); 534bf21cd93STycho Nightingale } 535bf21cd93STycho Nightingale break; 536bf21cd93STycho Nightingale case REG_LCR: 537bf21cd93STycho Nightingale sc->lcr = value; 538bf21cd93STycho Nightingale break; 539bf21cd93STycho Nightingale case REG_MCR: 540bf21cd93STycho Nightingale /* Apply mask so that bits 5-7 are 0 */ 541bf21cd93STycho Nightingale sc->mcr = value & 0x1F; 5424c87aefeSPatrick Mooney msr = modem_status(sc->mcr); 543bf21cd93STycho Nightingale 544bf21cd93STycho Nightingale /* 545bf21cd93STycho Nightingale * Detect if there has been any change between the 546bf21cd93STycho Nightingale * previous and the new value of MSR. If there is 547bf21cd93STycho Nightingale * then assert the appropriate MSR delta bit. 548bf21cd93STycho Nightingale */ 549bf21cd93STycho Nightingale if ((msr & MSR_CTS) ^ (sc->msr & MSR_CTS)) 550bf21cd93STycho Nightingale sc->msr |= MSR_DCTS; 551bf21cd93STycho Nightingale if ((msr & MSR_DSR) ^ (sc->msr & MSR_DSR)) 552bf21cd93STycho Nightingale sc->msr |= MSR_DDSR; 553bf21cd93STycho Nightingale if ((msr & MSR_DCD) ^ (sc->msr & MSR_DCD)) 554bf21cd93STycho Nightingale sc->msr |= MSR_DDCD; 555bf21cd93STycho Nightingale if ((sc->msr & MSR_RI) != 0 && (msr & MSR_RI) == 0) 556bf21cd93STycho Nightingale sc->msr |= MSR_TERI; 557bf21cd93STycho Nightingale 558bf21cd93STycho Nightingale /* 559bf21cd93STycho Nightingale * Update the value of MSR while retaining the delta 560bf21cd93STycho Nightingale * bits. 561bf21cd93STycho Nightingale */ 562bf21cd93STycho Nightingale sc->msr &= MSR_DELTA_MASK; 563bf21cd93STycho Nightingale sc->msr |= msr; 564bf21cd93STycho Nightingale break; 565bf21cd93STycho Nightingale case REG_LSR: 566bf21cd93STycho Nightingale /* 567bf21cd93STycho Nightingale * Line status register is not meant to be written to 568bf21cd93STycho Nightingale * during normal operation. 569bf21cd93STycho Nightingale */ 570bf21cd93STycho Nightingale break; 571bf21cd93STycho Nightingale case REG_MSR: 572bf21cd93STycho Nightingale /* 573bf21cd93STycho Nightingale * As far as I can tell MSR is a read-only register. 574bf21cd93STycho Nightingale */ 575bf21cd93STycho Nightingale break; 576bf21cd93STycho Nightingale case REG_SCR: 577bf21cd93STycho Nightingale sc->scr = value; 578bf21cd93STycho Nightingale break; 579bf21cd93STycho Nightingale default: 580bf21cd93STycho Nightingale break; 581bf21cd93STycho Nightingale } 582bf21cd93STycho Nightingale 583bf21cd93STycho Nightingale done: 584bf21cd93STycho Nightingale uart_toggle_intr(sc); 585bf21cd93STycho Nightingale pthread_mutex_unlock(&sc->mtx); 586bf21cd93STycho Nightingale } 587bf21cd93STycho Nightingale 588bf21cd93STycho Nightingale uint8_t 589bf21cd93STycho Nightingale uart_read(struct uart_softc *sc, int offset) 590bf21cd93STycho Nightingale { 591bf21cd93STycho Nightingale uint8_t iir, intr_reason, reg; 592bf21cd93STycho Nightingale 593bf21cd93STycho Nightingale pthread_mutex_lock(&sc->mtx); 594bf21cd93STycho Nightingale 595bf21cd93STycho Nightingale /* 596bf21cd93STycho Nightingale * Take care of the special case DLAB accesses first 597bf21cd93STycho Nightingale */ 598bf21cd93STycho Nightingale if ((sc->lcr & LCR_DLAB) != 0) { 599bf21cd93STycho Nightingale if (offset == REG_DLL) { 600bf21cd93STycho Nightingale reg = sc->dll; 601bf21cd93STycho Nightingale goto done; 602bf21cd93STycho Nightingale } 603bf21cd93STycho Nightingale 604bf21cd93STycho Nightingale if (offset == REG_DLH) { 605bf21cd93STycho Nightingale reg = sc->dlh; 606bf21cd93STycho Nightingale goto done; 607bf21cd93STycho Nightingale } 608bf21cd93STycho Nightingale } 609bf21cd93STycho Nightingale 610bf21cd93STycho Nightingale switch (offset) { 611bf21cd93STycho Nightingale case REG_DATA: 6124c87aefeSPatrick Mooney reg = rxfifo_getchar(sc); 613bf21cd93STycho Nightingale break; 614bf21cd93STycho Nightingale case REG_IER: 615bf21cd93STycho Nightingale reg = sc->ier; 616bf21cd93STycho Nightingale break; 617bf21cd93STycho Nightingale case REG_IIR: 618bf21cd93STycho Nightingale iir = (sc->fcr & FCR_ENABLE) ? IIR_FIFO_MASK : 0; 619bf21cd93STycho Nightingale 620bf21cd93STycho Nightingale intr_reason = uart_intr_reason(sc); 621bf21cd93STycho Nightingale 622bf21cd93STycho Nightingale /* 623bf21cd93STycho Nightingale * Deal with side effects of reading the IIR register 624bf21cd93STycho Nightingale */ 625bf21cd93STycho Nightingale if (intr_reason == IIR_TXRDY) 626bf21cd93STycho Nightingale sc->thre_int_pending = false; 627bf21cd93STycho Nightingale 628bf21cd93STycho Nightingale iir |= intr_reason; 629bf21cd93STycho Nightingale 630bf21cd93STycho Nightingale reg = iir; 631bf21cd93STycho Nightingale break; 632bf21cd93STycho Nightingale case REG_LCR: 633bf21cd93STycho Nightingale reg = sc->lcr; 634bf21cd93STycho Nightingale break; 635bf21cd93STycho Nightingale case REG_MCR: 636bf21cd93STycho Nightingale reg = sc->mcr; 637bf21cd93STycho Nightingale break; 638bf21cd93STycho Nightingale case REG_LSR: 639bf21cd93STycho Nightingale /* Transmitter is always ready for more data */ 640bf21cd93STycho Nightingale sc->lsr |= LSR_TEMT | LSR_THRE; 641bf21cd93STycho Nightingale 642bf21cd93STycho Nightingale /* Check for new receive data */ 6434c87aefeSPatrick Mooney if (rxfifo_numchars(sc) > 0) 644bf21cd93STycho Nightingale sc->lsr |= LSR_RXRDY; 645bf21cd93STycho Nightingale else 646bf21cd93STycho Nightingale sc->lsr &= ~LSR_RXRDY; 647bf21cd93STycho Nightingale 648bf21cd93STycho Nightingale reg = sc->lsr; 649bf21cd93STycho Nightingale 650bf21cd93STycho Nightingale /* The LSR_OE bit is cleared on LSR read */ 651bf21cd93STycho Nightingale sc->lsr &= ~LSR_OE; 652bf21cd93STycho Nightingale break; 653bf21cd93STycho Nightingale case REG_MSR: 654bf21cd93STycho Nightingale /* 655bf21cd93STycho Nightingale * MSR delta bits are cleared on read 656bf21cd93STycho Nightingale */ 657bf21cd93STycho Nightingale reg = sc->msr; 658bf21cd93STycho Nightingale sc->msr &= ~MSR_DELTA_MASK; 659bf21cd93STycho Nightingale break; 660bf21cd93STycho Nightingale case REG_SCR: 661bf21cd93STycho Nightingale reg = sc->scr; 662bf21cd93STycho Nightingale break; 663bf21cd93STycho Nightingale default: 664bf21cd93STycho Nightingale reg = 0xFF; 665bf21cd93STycho Nightingale break; 666bf21cd93STycho Nightingale } 667bf21cd93STycho Nightingale 668bf21cd93STycho Nightingale done: 669bf21cd93STycho Nightingale uart_toggle_intr(sc); 670bf21cd93STycho Nightingale pthread_mutex_unlock(&sc->mtx); 671bf21cd93STycho Nightingale 672bf21cd93STycho Nightingale return (reg); 673bf21cd93STycho Nightingale } 674bf21cd93STycho Nightingale 675bf21cd93STycho Nightingale #ifndef __FreeBSD__ 676bf21cd93STycho Nightingale static void 6774c87aefeSPatrick Mooney uart_sock_drain(int fd, enum ev_type ev, void *arg) 678bf21cd93STycho Nightingale { 6794c87aefeSPatrick Mooney struct uart_softc *sc = arg; 6804c87aefeSPatrick Mooney char ch; 681bf21cd93STycho Nightingale 682bf21cd93STycho Nightingale /* 6834c87aefeSPatrick Mooney * Take the softc lock to protect against concurrent 6844c87aefeSPatrick Mooney * access from a vCPU i/o exit 685bf21cd93STycho Nightingale */ 6864c87aefeSPatrick Mooney pthread_mutex_lock(&sc->mtx); 687bf21cd93STycho Nightingale 6884c87aefeSPatrick Mooney if ((sc->mcr & MCR_LOOPBACK) != 0) { 6894c87aefeSPatrick Mooney (void) read(sc->usc_sock.clifd, &ch, 1); 6904c87aefeSPatrick Mooney } else { 6914c87aefeSPatrick Mooney bool err_close = false; 6924c87aefeSPatrick Mooney 6934c87aefeSPatrick Mooney while (rxfifo_available(sc)) { 694bf21cd93STycho Nightingale int res; 695bf21cd93STycho Nightingale 6964c87aefeSPatrick Mooney res = read(sc->usc_sock.clifd, &ch, 1); 6974c87aefeSPatrick Mooney if (res == 0) { 6984c87aefeSPatrick Mooney err_close = true; 6994c87aefeSPatrick Mooney break; 7004c87aefeSPatrick Mooney } else if (res == -1) { 7014c87aefeSPatrick Mooney if (errno != EAGAIN && errno != EINTR) { 7024c87aefeSPatrick Mooney err_close = true; 7034c87aefeSPatrick Mooney } 7044c87aefeSPatrick Mooney break; 705bf21cd93STycho Nightingale } 706bf21cd93STycho Nightingale 7074c87aefeSPatrick Mooney rxfifo_putchar(sc, ch); 7084c87aefeSPatrick Mooney } 7094c87aefeSPatrick Mooney uart_toggle_intr(sc); 7104c87aefeSPatrick Mooney 7114c87aefeSPatrick Mooney if (err_close) { 7124c87aefeSPatrick Mooney (void) fprintf(stderr, "uart: closing client conn\n"); 7134c87aefeSPatrick Mooney (void) shutdown(sc->usc_sock.clifd, SHUT_RDWR); 7144c87aefeSPatrick Mooney mevent_delete_close(sc->mev); 7154c87aefeSPatrick Mooney sc->mev = NULL; 7164c87aefeSPatrick Mooney sc->usc_sock.clifd = -1; 7174c87aefeSPatrick Mooney } 7184c87aefeSPatrick Mooney } 7194c87aefeSPatrick Mooney 7204c87aefeSPatrick Mooney pthread_mutex_unlock(&sc->mtx); 721bf21cd93STycho Nightingale } 722bf21cd93STycho Nightingale 723bf21cd93STycho Nightingale static void 7244c87aefeSPatrick Mooney uart_sock_accept(int fd, enum ev_type ev, void *arg) 725bf21cd93STycho Nightingale { 7264c87aefeSPatrick Mooney struct uart_softc *sc = arg; 7274c87aefeSPatrick Mooney int connfd; 728bf21cd93STycho Nightingale 7294c87aefeSPatrick Mooney connfd = accept(sc->usc_sock.servfd, NULL, NULL); 7304c87aefeSPatrick Mooney if (connfd == -1) { 731bf21cd93STycho Nightingale return; 732bf21cd93STycho Nightingale } 733bf21cd93STycho Nightingale 7344c87aefeSPatrick Mooney /* 7354c87aefeSPatrick Mooney * Do client connection management under protection of the softc lock 7364c87aefeSPatrick Mooney * to avoid racing with concurrent UART events. 7374c87aefeSPatrick Mooney */ 7384c87aefeSPatrick Mooney pthread_mutex_lock(&sc->mtx); 739bf21cd93STycho Nightingale 7404c87aefeSPatrick Mooney if (sc->usc_sock.clifd != -1) { 7414c87aefeSPatrick Mooney /* we're already handling a client */ 7424c87aefeSPatrick Mooney (void) fprintf(stderr, "uart: unexpected client conn\n"); 7434c87aefeSPatrick Mooney (void) shutdown(connfd, SHUT_RDWR); 7444c87aefeSPatrick Mooney (void) close(connfd); 745bf21cd93STycho Nightingale } else { 7464c87aefeSPatrick Mooney if (fcntl(connfd, F_SETFL, O_NONBLOCK) < 0) { 7474c87aefeSPatrick Mooney perror("uart: fcntl(O_NONBLOCK)"); 7484c87aefeSPatrick Mooney (void) shutdown(connfd, SHUT_RDWR); 7494c87aefeSPatrick Mooney (void) close(connfd); 750bf21cd93STycho Nightingale } else { 7514c87aefeSPatrick Mooney sc->usc_sock.clifd = connfd; 7524c87aefeSPatrick Mooney sc->mev = mevent_add(sc->usc_sock.clifd, EVF_READ, 7534c87aefeSPatrick Mooney uart_sock_drain, sc); 754bf21cd93STycho Nightingale } 755bf21cd93STycho Nightingale } 756bf21cd93STycho Nightingale 7574c87aefeSPatrick Mooney pthread_mutex_unlock(&sc->mtx); 758bf21cd93STycho Nightingale } 759bf21cd93STycho Nightingale 760bf21cd93STycho Nightingale static int 7614c87aefeSPatrick Mooney init_sock(const char *path) 762bf21cd93STycho Nightingale { 763bf21cd93STycho Nightingale int servfd; 764bf21cd93STycho Nightingale struct sockaddr_un servaddr; 765bf21cd93STycho Nightingale 7664c87aefeSPatrick Mooney bzero(&servaddr, sizeof (servaddr)); 7674c87aefeSPatrick Mooney servaddr.sun_family = AF_UNIX; 7684c87aefeSPatrick Mooney 7694c87aefeSPatrick Mooney if (strlcpy(servaddr.sun_path, path, sizeof (servaddr.sun_path)) >= 7704c87aefeSPatrick Mooney sizeof (servaddr.sun_path)) { 7714c87aefeSPatrick Mooney (void) fprintf(stderr, "uart: path '%s' too long\n", 7724c87aefeSPatrick Mooney path); 773bf21cd93STycho Nightingale return (-1); 774bf21cd93STycho Nightingale } 775bf21cd93STycho Nightingale 776bf21cd93STycho Nightingale if ((servfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { 7774c87aefeSPatrick Mooney (void) fprintf(stderr, "uart: socket() error - %s\n", 7784c87aefeSPatrick Mooney strerror(errno)); 779bf21cd93STycho Nightingale return (-1); 780bf21cd93STycho Nightingale } 781bf21cd93STycho Nightingale (void) unlink(servaddr.sun_path); 782bf21cd93STycho Nightingale 783bf21cd93STycho Nightingale if (bind(servfd, (struct sockaddr *)&servaddr, 784bf21cd93STycho Nightingale sizeof (servaddr)) == -1) { 7854c87aefeSPatrick Mooney (void) fprintf(stderr, "uart: bind() error - %s\n", 7864c87aefeSPatrick Mooney strerror(errno)); 787bf21cd93STycho Nightingale goto out; 788bf21cd93STycho Nightingale } 789bf21cd93STycho Nightingale 7904c87aefeSPatrick Mooney if (listen(servfd, 1) == -1) { 7914c87aefeSPatrick Mooney (void) fprintf(stderr, "uart: listen() error - %s\n", 7924c87aefeSPatrick Mooney strerror(errno)); 793bf21cd93STycho Nightingale goto out; 794bf21cd93STycho Nightingale } 795bf21cd93STycho Nightingale return (servfd); 796bf21cd93STycho Nightingale 797bf21cd93STycho Nightingale out: 798bf21cd93STycho Nightingale (void) unlink(servaddr.sun_path); 799bf21cd93STycho Nightingale (void) close(servfd); 800bf21cd93STycho Nightingale return (-1); 801bf21cd93STycho Nightingale } 8024c87aefeSPatrick Mooney #endif /* not __FreeBSD__ */ 803bf21cd93STycho Nightingale 804bf21cd93STycho Nightingale int 805bf21cd93STycho Nightingale uart_legacy_alloc(int which, int *baseaddr, int *irq) 806bf21cd93STycho Nightingale { 807bf21cd93STycho Nightingale 808bf21cd93STycho Nightingale if (which < 0 || which >= UART_NLDEVS || uart_lres[which].inuse) 809bf21cd93STycho Nightingale return (-1); 810bf21cd93STycho Nightingale 811bf21cd93STycho Nightingale uart_lres[which].inuse = true; 812bf21cd93STycho Nightingale *baseaddr = uart_lres[which].baseaddr; 813bf21cd93STycho Nightingale *irq = uart_lres[which].irq; 814bf21cd93STycho Nightingale 815bf21cd93STycho Nightingale return (0); 816bf21cd93STycho Nightingale } 817bf21cd93STycho Nightingale 818bf21cd93STycho Nightingale struct uart_softc * 819bf21cd93STycho Nightingale uart_init(uart_intr_func_t intr_assert, uart_intr_func_t intr_deassert, 820bf21cd93STycho Nightingale void *arg) 821bf21cd93STycho Nightingale { 822bf21cd93STycho Nightingale struct uart_softc *sc; 823bf21cd93STycho Nightingale 8244c87aefeSPatrick Mooney sc = calloc(1, sizeof(struct uart_softc)); 825bf21cd93STycho Nightingale 826bf21cd93STycho Nightingale sc->arg = arg; 827bf21cd93STycho Nightingale sc->intr_assert = intr_assert; 828bf21cd93STycho Nightingale sc->intr_deassert = intr_deassert; 829bf21cd93STycho Nightingale 830bf21cd93STycho Nightingale pthread_mutex_init(&sc->mtx, NULL); 831bf21cd93STycho Nightingale 832bf21cd93STycho Nightingale uart_reset(sc); 833bf21cd93STycho Nightingale 834bf21cd93STycho Nightingale return (sc); 835bf21cd93STycho Nightingale } 836bf21cd93STycho Nightingale 8374c87aefeSPatrick Mooney #ifndef __FreeBSD__ 8384c87aefeSPatrick Mooney static int 8394c87aefeSPatrick Mooney uart_sock_backend(struct uart_softc *sc, const char *inopts) 8404c87aefeSPatrick Mooney { 8414c87aefeSPatrick Mooney char *opts; 8424c87aefeSPatrick Mooney char *opt; 8434c87aefeSPatrick Mooney char *nextopt; 8444c87aefeSPatrick Mooney char *path = NULL; 8454c87aefeSPatrick Mooney 8464c87aefeSPatrick Mooney if (strncmp(inopts, "socket,", 7) != 0) { 8474c87aefeSPatrick Mooney return (-1); 8484c87aefeSPatrick Mooney } 8494c87aefeSPatrick Mooney if ((opts = strdup(inopts + 7)) == NULL) { 8504c87aefeSPatrick Mooney return (-1); 8514c87aefeSPatrick Mooney } 8524c87aefeSPatrick Mooney 8534c87aefeSPatrick Mooney nextopt = opts; 8544c87aefeSPatrick Mooney for (opt = strsep(&nextopt, ","); opt != NULL; 8554c87aefeSPatrick Mooney opt = strsep(&nextopt, ",")) { 8564c87aefeSPatrick Mooney if (path == NULL && *opt == '/') { 8574c87aefeSPatrick Mooney path = opt; 8584c87aefeSPatrick Mooney continue; 8594c87aefeSPatrick Mooney } 8604c87aefeSPatrick Mooney /* 8614c87aefeSPatrick Mooney * XXX check for server and client options here. For now, 8624c87aefeSPatrick Mooney * everything is a server 8634c87aefeSPatrick Mooney */ 8644c87aefeSPatrick Mooney free(opts); 8654c87aefeSPatrick Mooney return (-1); 8664c87aefeSPatrick Mooney } 8674c87aefeSPatrick Mooney 8684c87aefeSPatrick Mooney sc->usc_sock.clifd = -1; 8694c87aefeSPatrick Mooney if ((sc->usc_sock.servfd = init_sock(path)) == -1) { 8704c87aefeSPatrick Mooney free(opts); 8714c87aefeSPatrick Mooney return (-1); 8724c87aefeSPatrick Mooney } 8734c87aefeSPatrick Mooney sc->sock = true; 8744c87aefeSPatrick Mooney sc->tty.rfd = sc->tty.wfd = -1; 8754c87aefeSPatrick Mooney sc->usc_sock.servmev = mevent_add(sc->usc_sock.servfd, EVF_READ, 8764c87aefeSPatrick Mooney uart_sock_accept, sc); 8774c87aefeSPatrick Mooney assert(sc->usc_sock.servmev != NULL); 8784c87aefeSPatrick Mooney 8794c87aefeSPatrick Mooney return (0); 8804c87aefeSPatrick Mooney } 8814c87aefeSPatrick Mooney #endif /* not __FreeBSD__ */ 8824c87aefeSPatrick Mooney 8834c87aefeSPatrick Mooney static int 8844c87aefeSPatrick Mooney uart_stdio_backend(struct uart_softc *sc) 8854c87aefeSPatrick Mooney { 8864c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM 8874c87aefeSPatrick Mooney cap_rights_t rights; 8884c87aefeSPatrick Mooney cap_ioctl_t cmds[] = { TIOCGETA, TIOCSETA, TIOCGWINSZ }; 8894c87aefeSPatrick Mooney #endif 8904c87aefeSPatrick Mooney 8914c87aefeSPatrick Mooney if (uart_stdio) 8924c87aefeSPatrick Mooney return (-1); 8934c87aefeSPatrick Mooney 8944c87aefeSPatrick Mooney sc->tty.rfd = STDIN_FILENO; 8954c87aefeSPatrick Mooney sc->tty.wfd = STDOUT_FILENO; 8964c87aefeSPatrick Mooney sc->tty.opened = true; 8974c87aefeSPatrick Mooney 8984c87aefeSPatrick Mooney if (fcntl(sc->tty.rfd, F_SETFL, O_NONBLOCK) != 0) 8994c87aefeSPatrick Mooney return (-1); 9004c87aefeSPatrick Mooney if (fcntl(sc->tty.wfd, F_SETFL, O_NONBLOCK) != 0) 9014c87aefeSPatrick Mooney return (-1); 9024c87aefeSPatrick Mooney 9034c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM 9044c87aefeSPatrick Mooney cap_rights_init(&rights, CAP_EVENT, CAP_IOCTL, CAP_READ); 9054c87aefeSPatrick Mooney if (caph_rights_limit(sc->tty.rfd, &rights) == -1) 9064c87aefeSPatrick Mooney errx(EX_OSERR, "Unable to apply rights for sandbox"); 9074c87aefeSPatrick Mooney if (caph_ioctls_limit(sc->tty.rfd, cmds, nitems(cmds)) == -1) 9084c87aefeSPatrick Mooney errx(EX_OSERR, "Unable to apply rights for sandbox"); 9094c87aefeSPatrick Mooney #endif 9104c87aefeSPatrick Mooney 9114c87aefeSPatrick Mooney uart_stdio = true; 9124c87aefeSPatrick Mooney 9134c87aefeSPatrick Mooney return (0); 9144c87aefeSPatrick Mooney } 9154c87aefeSPatrick Mooney 9164c87aefeSPatrick Mooney static int 9174c87aefeSPatrick Mooney uart_tty_backend(struct uart_softc *sc, const char *opts) 9184c87aefeSPatrick Mooney { 9194c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM 9204c87aefeSPatrick Mooney cap_rights_t rights; 9214c87aefeSPatrick Mooney cap_ioctl_t cmds[] = { TIOCGETA, TIOCSETA, TIOCGWINSZ }; 9224c87aefeSPatrick Mooney #endif 9234c87aefeSPatrick Mooney int fd; 9244c87aefeSPatrick Mooney 9254c87aefeSPatrick Mooney fd = open(opts, O_RDWR | O_NONBLOCK); 926*84659b24SMichael Zeller if (fd < 0) 9274c87aefeSPatrick Mooney return (-1); 9284c87aefeSPatrick Mooney 929*84659b24SMichael Zeller if (!isatty(fd)) { 930*84659b24SMichael Zeller close(fd); 931*84659b24SMichael Zeller return (-1); 932*84659b24SMichael Zeller } 933*84659b24SMichael Zeller 9344c87aefeSPatrick Mooney sc->tty.rfd = sc->tty.wfd = fd; 9354c87aefeSPatrick Mooney sc->tty.opened = true; 9364c87aefeSPatrick Mooney 9374c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM 9384c87aefeSPatrick Mooney cap_rights_init(&rights, CAP_EVENT, CAP_IOCTL, CAP_READ, CAP_WRITE); 9394c87aefeSPatrick Mooney if (caph_rights_limit(fd, &rights) == -1) 9404c87aefeSPatrick Mooney errx(EX_OSERR, "Unable to apply rights for sandbox"); 9414c87aefeSPatrick Mooney if (caph_ioctls_limit(fd, cmds, nitems(cmds)) == -1) 9424c87aefeSPatrick Mooney errx(EX_OSERR, "Unable to apply rights for sandbox"); 9434c87aefeSPatrick Mooney #endif 9444c87aefeSPatrick Mooney 9454c87aefeSPatrick Mooney return (0); 9464c87aefeSPatrick Mooney } 9474c87aefeSPatrick Mooney 948bf21cd93STycho Nightingale int 949bf21cd93STycho Nightingale uart_set_backend(struct uart_softc *sc, const char *opts) 950bf21cd93STycho Nightingale { 9514c87aefeSPatrick Mooney int retval; 9524c87aefeSPatrick Mooney 953bf21cd93STycho Nightingale if (opts == NULL) 954bf21cd93STycho Nightingale return (0); 955bf21cd93STycho Nightingale 9564c87aefeSPatrick Mooney #ifndef __FreeBSD__ 9574c87aefeSPatrick Mooney if (strncmp("socket,", opts, 7) == 0) 9584c87aefeSPatrick Mooney return (uart_sock_backend(sc, opts)); 959bf21cd93STycho Nightingale #endif 9604c87aefeSPatrick Mooney if (strcmp("stdio", opts) == 0) 9614c87aefeSPatrick Mooney retval = uart_stdio_backend(sc); 9624c87aefeSPatrick Mooney else 9634c87aefeSPatrick Mooney retval = uart_tty_backend(sc, opts); 9644c87aefeSPatrick Mooney if (retval == 0) 9654c87aefeSPatrick Mooney uart_opentty(sc); 9664c87aefeSPatrick Mooney 9674c87aefeSPatrick Mooney return (retval); 968bf21cd93STycho Nightingale } 969