1bf21cd93STycho Nightingale /*- 2*4c87aefeSPatrick Mooney * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3*4c87aefeSPatrick 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 * 29*4c87aefeSPatrick Mooney * $FreeBSD$ 30*4c87aefeSPatrick 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. 43*4c87aefeSPatrick Mooney * Copyright 2018 Joyent, Inc. 44bf21cd93STycho Nightingale */ 45bf21cd93STycho Nightingale 46bf21cd93STycho Nightingale #include <sys/cdefs.h> 47*4c87aefeSPatrick Mooney __FBSDID("$FreeBSD$"); 48bf21cd93STycho Nightingale 49bf21cd93STycho Nightingale #include <sys/types.h> 50bf21cd93STycho Nightingale #include <dev/ic/ns16550.h> 51*4c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM 52*4c87aefeSPatrick Mooney #include <sys/capsicum.h> 53*4c87aefeSPatrick Mooney #include <capsicum_helpers.h> 54bf21cd93STycho Nightingale #endif 55*4c87aefeSPatrick Mooney 56bf21cd93STycho Nightingale #include <stdio.h> 57bf21cd93STycho Nightingale #include <stdlib.h> 58bf21cd93STycho Nightingale #include <assert.h> 59*4c87aefeSPatrick Mooney #include <err.h> 60*4c87aefeSPatrick Mooney #include <errno.h> 61*4c87aefeSPatrick 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> 67*4c87aefeSPatrick Mooney #include <sysexits.h> 68bf21cd93STycho Nightingale #ifndef __FreeBSD__ 69*4c87aefeSPatrick 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 */ 97*4c87aefeSPatrick 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 118*4c87aefeSPatrick Mooney struct ttyfd { 119*4c87aefeSPatrick Mooney bool opened; 120*4c87aefeSPatrick Mooney int rfd; /* fd for reading */ 121*4c87aefeSPatrick Mooney int wfd; /* fd for writing, may be == rfd */ 122*4c87aefeSPatrick Mooney }; 123*4c87aefeSPatrick 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; 139*4c87aefeSPatrick Mooney struct mevent *mev; 140bf21cd93STycho Nightingale 141*4c87aefeSPatrick Mooney struct ttyfd tty; 142bf21cd93STycho Nightingale #ifndef __FreeBSD__ 143*4c87aefeSPatrick Mooney bool sock; 144bf21cd93STycho Nightingale struct { 145bf21cd93STycho Nightingale int clifd; /* console client unix domain socket */ 146bf21cd93STycho Nightingale int servfd; /* console server unix domain socket */ 147*4c87aefeSPatrick Mooney struct mevent *servmev; /* mevent for server socket */ 148*4c87aefeSPatrick 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 164*4c87aefeSPatrick Mooney tcsetattr(STDIN_FILENO, TCSANOW, &tio_stdio_orig); 165bf21cd93STycho Nightingale } 166bf21cd93STycho Nightingale 167bf21cd93STycho Nightingale static void 168*4c87aefeSPatrick Mooney ttyopen(struct ttyfd *tf) 169bf21cd93STycho Nightingale { 170*4c87aefeSPatrick Mooney struct termios orig, new; 171bf21cd93STycho Nightingale 172*4c87aefeSPatrick Mooney tcgetattr(tf->rfd, &orig); 173*4c87aefeSPatrick Mooney new = orig; 174*4c87aefeSPatrick Mooney cfmakeraw(&new); 175*4c87aefeSPatrick Mooney new.c_cflag |= CLOCAL; 176*4c87aefeSPatrick Mooney tcsetattr(tf->rfd, TCSANOW, &new); 177*4c87aefeSPatrick Mooney if (uart_stdio) { 178*4c87aefeSPatrick Mooney tio_stdio_orig = orig; 179bf21cd93STycho Nightingale atexit(ttyclose); 180bf21cd93STycho Nightingale } 181bf21cd93STycho Nightingale } 182bf21cd93STycho Nightingale 183bf21cd93STycho Nightingale static int 184*4c87aefeSPatrick Mooney ttyread(struct ttyfd *tf) 185bf21cd93STycho Nightingale { 186*4c87aefeSPatrick Mooney unsigned char rb; 187bf21cd93STycho Nightingale 188*4c87aefeSPatrick Mooney if (read(tf->rfd, &rb, 1) == 1) 189*4c87aefeSPatrick Mooney return (rb); 190*4c87aefeSPatrick Mooney else 191bf21cd93STycho Nightingale return (-1); 192bf21cd93STycho Nightingale } 193bf21cd93STycho Nightingale 194bf21cd93STycho Nightingale static void 195*4c87aefeSPatrick Mooney ttywrite(struct ttyfd *tf, unsigned char wb) 196bf21cd93STycho Nightingale { 197bf21cd93STycho Nightingale 198*4c87aefeSPatrick Mooney (void)write(tf->wfd, &wb, 1); 199bf21cd93STycho Nightingale } 200bf21cd93STycho Nightingale 201bf21cd93STycho Nightingale #ifndef __FreeBSD__ 202bf21cd93STycho Nightingale static void 203*4c87aefeSPatrick Mooney sockwrite(struct uart_softc *sc, unsigned char wb) 204bf21cd93STycho Nightingale { 205*4c87aefeSPatrick Mooney (void) write(sc->usc_sock.clifd, &wb, 1); 206bf21cd93STycho Nightingale } 207bf21cd93STycho Nightingale #endif 208bf21cd93STycho Nightingale 209bf21cd93STycho Nightingale static void 210*4c87aefeSPatrick Mooney rxfifo_reset(struct uart_softc *sc, int size) 211bf21cd93STycho Nightingale { 212*4c87aefeSPatrick Mooney char flushbuf[32]; 213*4c87aefeSPatrick Mooney struct fifo *fifo; 214*4c87aefeSPatrick Mooney ssize_t nread; 215*4c87aefeSPatrick Mooney int error; 216*4c87aefeSPatrick Mooney 217*4c87aefeSPatrick Mooney fifo = &sc->rxfifo; 218bf21cd93STycho Nightingale bzero(fifo, sizeof(struct fifo)); 219bf21cd93STycho Nightingale fifo->size = size; 220*4c87aefeSPatrick Mooney 221*4c87aefeSPatrick Mooney if (sc->tty.opened) { 222*4c87aefeSPatrick Mooney /* 223*4c87aefeSPatrick Mooney * Flush any unread input from the tty buffer. 224*4c87aefeSPatrick Mooney */ 225*4c87aefeSPatrick Mooney while (1) { 226*4c87aefeSPatrick Mooney nread = read(sc->tty.rfd, flushbuf, sizeof(flushbuf)); 227*4c87aefeSPatrick Mooney if (nread != sizeof(flushbuf)) 228*4c87aefeSPatrick Mooney break; 229*4c87aefeSPatrick Mooney } 230*4c87aefeSPatrick Mooney 231*4c87aefeSPatrick Mooney /* 232*4c87aefeSPatrick Mooney * Enable mevent to trigger when new characters are available 233*4c87aefeSPatrick Mooney * on the tty fd. 234*4c87aefeSPatrick Mooney */ 235*4c87aefeSPatrick Mooney error = mevent_enable(sc->mev); 236*4c87aefeSPatrick Mooney assert(error == 0); 237*4c87aefeSPatrick Mooney } 238*4c87aefeSPatrick Mooney #ifndef __FreeBSD__ 239*4c87aefeSPatrick Mooney if (sc->sock && sc->usc_sock.clifd != -1) { 240*4c87aefeSPatrick Mooney /* Flush any unread input from the socket buffer. */ 241*4c87aefeSPatrick Mooney do { 242*4c87aefeSPatrick Mooney nread = read(sc->usc_sock.clifd, flushbuf, 243*4c87aefeSPatrick Mooney sizeof (flushbuf)); 244*4c87aefeSPatrick Mooney } while (nread == sizeof (flushbuf)); 245*4c87aefeSPatrick Mooney 246*4c87aefeSPatrick Mooney /* Enable mevent to trigger when new data available on sock */ 247*4c87aefeSPatrick Mooney error = mevent_enable(sc->mev); 248*4c87aefeSPatrick Mooney assert(error == 0); 249*4c87aefeSPatrick Mooney } 250*4c87aefeSPatrick Mooney #endif /* __FreeBSD__ */ 251bf21cd93STycho Nightingale } 252bf21cd93STycho Nightingale 253bf21cd93STycho Nightingale static int 254*4c87aefeSPatrick Mooney rxfifo_available(struct uart_softc *sc) 255bf21cd93STycho Nightingale { 256*4c87aefeSPatrick Mooney struct fifo *fifo; 257*4c87aefeSPatrick Mooney 258*4c87aefeSPatrick Mooney fifo = &sc->rxfifo; 259*4c87aefeSPatrick Mooney return (fifo->num < fifo->size); 260*4c87aefeSPatrick Mooney } 261*4c87aefeSPatrick Mooney 262*4c87aefeSPatrick Mooney static int 263*4c87aefeSPatrick Mooney rxfifo_putchar(struct uart_softc *sc, uint8_t ch) 264*4c87aefeSPatrick Mooney { 265*4c87aefeSPatrick Mooney struct fifo *fifo; 266*4c87aefeSPatrick Mooney int error; 267*4c87aefeSPatrick Mooney 268*4c87aefeSPatrick 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++; 274*4c87aefeSPatrick Mooney if (!rxfifo_available(sc)) { 275*4c87aefeSPatrick Mooney if (sc->tty.opened) { 276*4c87aefeSPatrick Mooney /* 277*4c87aefeSPatrick Mooney * Disable mevent callback if the FIFO is full. 278*4c87aefeSPatrick Mooney */ 279*4c87aefeSPatrick Mooney error = mevent_disable(sc->mev); 280*4c87aefeSPatrick Mooney assert(error == 0); 281*4c87aefeSPatrick Mooney } 282*4c87aefeSPatrick Mooney #ifndef __FreeBSD__ 283*4c87aefeSPatrick Mooney if (sc->sock && sc->usc_sock.clifd != -1) { 284*4c87aefeSPatrick Mooney /* 285*4c87aefeSPatrick Mooney * Disable mevent callback if the FIFO is full. 286*4c87aefeSPatrick Mooney */ 287*4c87aefeSPatrick Mooney error = mevent_disable(sc->mev); 288*4c87aefeSPatrick Mooney assert(error == 0); 289*4c87aefeSPatrick Mooney } 290*4c87aefeSPatrick Mooney #endif /* __FreeBSD__ */ 291*4c87aefeSPatrick Mooney } 292bf21cd93STycho Nightingale return (0); 293bf21cd93STycho Nightingale } else 294bf21cd93STycho Nightingale return (-1); 295bf21cd93STycho Nightingale } 296bf21cd93STycho Nightingale 297bf21cd93STycho Nightingale static int 298*4c87aefeSPatrick Mooney rxfifo_getchar(struct uart_softc *sc) 299bf21cd93STycho Nightingale { 300*4c87aefeSPatrick Mooney struct fifo *fifo; 301*4c87aefeSPatrick Mooney int c, error, wasfull; 302bf21cd93STycho Nightingale 303*4c87aefeSPatrick Mooney wasfull = 0; 304*4c87aefeSPatrick Mooney fifo = &sc->rxfifo; 305bf21cd93STycho Nightingale if (fifo->num > 0) { 306*4c87aefeSPatrick Mooney if (!rxfifo_available(sc)) 307*4c87aefeSPatrick Mooney wasfull = 1; 308bf21cd93STycho Nightingale c = fifo->buf[fifo->rindex]; 309bf21cd93STycho Nightingale fifo->rindex = (fifo->rindex + 1) % fifo->size; 310bf21cd93STycho Nightingale fifo->num--; 311*4c87aefeSPatrick Mooney if (wasfull) { 312*4c87aefeSPatrick Mooney if (sc->tty.opened) { 313*4c87aefeSPatrick Mooney error = mevent_enable(sc->mev); 314*4c87aefeSPatrick Mooney assert(error == 0); 315*4c87aefeSPatrick Mooney } 316*4c87aefeSPatrick Mooney #ifndef __FreeBSD__ 317*4c87aefeSPatrick Mooney if (sc->sock && sc->usc_sock.clifd != -1) { 318*4c87aefeSPatrick Mooney error = mevent_enable(sc->mev); 319*4c87aefeSPatrick Mooney assert(error == 0); 320*4c87aefeSPatrick Mooney } 321*4c87aefeSPatrick Mooney #endif /* __FreeBSD__ */ 322*4c87aefeSPatrick Mooney } 323bf21cd93STycho Nightingale return (c); 324bf21cd93STycho Nightingale } else 325bf21cd93STycho Nightingale return (-1); 326bf21cd93STycho Nightingale } 327bf21cd93STycho Nightingale 328bf21cd93STycho Nightingale static int 329*4c87aefeSPatrick Mooney rxfifo_numchars(struct uart_softc *sc) 330bf21cd93STycho Nightingale { 331*4c87aefeSPatrick 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 340*4c87aefeSPatrick Mooney ttyopen(&sc->tty); 341*4c87aefeSPatrick Mooney sc->mev = mevent_add(sc->tty.rfd, EVF_READ, uart_drain, sc); 342*4c87aefeSPatrick Mooney assert(sc->mev != NULL); 343*4c87aefeSPatrick Mooney } 344bf21cd93STycho Nightingale 345*4c87aefeSPatrick Mooney static uint8_t 346*4c87aefeSPatrick Mooney modem_status(uint8_t mcr) 347*4c87aefeSPatrick Mooney { 348*4c87aefeSPatrick Mooney uint8_t msr; 349*4c87aefeSPatrick Mooney 350*4c87aefeSPatrick Mooney if (mcr & MCR_LOOPBACK) { 351*4c87aefeSPatrick Mooney /* 352*4c87aefeSPatrick Mooney * In the loopback mode certain bits from the MCR are 353*4c87aefeSPatrick Mooney * reflected back into MSR. 354*4c87aefeSPatrick Mooney */ 355*4c87aefeSPatrick Mooney msr = 0; 356*4c87aefeSPatrick Mooney if (mcr & MCR_RTS) 357*4c87aefeSPatrick Mooney msr |= MSR_CTS; 358*4c87aefeSPatrick Mooney if (mcr & MCR_DTR) 359*4c87aefeSPatrick Mooney msr |= MSR_DSR; 360*4c87aefeSPatrick Mooney if (mcr & MCR_OUT1) 361*4c87aefeSPatrick Mooney msr |= MSR_RI; 362*4c87aefeSPatrick Mooney if (mcr & MCR_OUT2) 363*4c87aefeSPatrick Mooney msr |= MSR_DCD; 364*4c87aefeSPatrick Mooney } else { 365*4c87aefeSPatrick Mooney /* 366*4c87aefeSPatrick Mooney * Always assert DCD and DSR so tty open doesn't block 367*4c87aefeSPatrick Mooney * even if CLOCAL is turned off. 368*4c87aefeSPatrick Mooney */ 369*4c87aefeSPatrick Mooney msr = MSR_DCD | MSR_DSR; 370*4c87aefeSPatrick Mooney } 371*4c87aefeSPatrick Mooney assert((msr & MSR_DELTA_MASK) == 0); 372*4c87aefeSPatrick Mooney 373*4c87aefeSPatrick 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); 390*4c87aefeSPatrick 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; 407*4c87aefeSPatrick Mooney #ifndef __FreeBSD__ 408*4c87aefeSPatrick Mooney sc->dlh = 0; 409*4c87aefeSPatrick Mooney #else 410bf21cd93STycho Nightingale sc->dlh = divisor >> 16; 411*4c87aefeSPatrick Mooney #endif 412*4c87aefeSPatrick Mooney sc->msr = modem_status(sc->mcr); 413bf21cd93STycho Nightingale 414*4c87aefeSPatrick 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 442*4c87aefeSPatrick 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) { 453*4c87aefeSPatrick Mooney (void) ttyread(&sc->tty); 454bf21cd93STycho Nightingale } else { 455*4c87aefeSPatrick Mooney while (rxfifo_available(sc) && 456*4c87aefeSPatrick Mooney ((ch = ttyread(&sc->tty)) != -1)) { 457*4c87aefeSPatrick 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) { 491*4c87aefeSPatrick Mooney if (rxfifo_putchar(sc, value) != 0) 492bf21cd93STycho Nightingale sc->lsr |= LSR_OE; 493*4c87aefeSPatrick Mooney } else if (sc->tty.opened) { 494*4c87aefeSPatrick Mooney ttywrite(&sc->tty, value); 495bf21cd93STycho Nightingale #ifndef __FreeBSD__ 496*4c87aefeSPatrick Mooney } else if (sc->sock) { 497*4c87aefeSPatrick 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: 503*4c87aefeSPatrick Mooney /* Set pending when IER_ETXRDY is raised (edge-triggered). */ 504*4c87aefeSPatrick Mooney if ((sc->ier & IER_ETXRDY) == 0 && (value & IER_ETXRDY) != 0) 505*4c87aefeSPatrick 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; 519*4c87aefeSPatrick 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) 530*4c87aefeSPatrick 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; 542*4c87aefeSPatrick 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: 612*4c87aefeSPatrick 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 */ 643*4c87aefeSPatrick 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 677*4c87aefeSPatrick Mooney uart_sock_drain(int fd, enum ev_type ev, void *arg) 678bf21cd93STycho Nightingale { 679*4c87aefeSPatrick Mooney struct uart_softc *sc = arg; 680*4c87aefeSPatrick Mooney char ch; 681bf21cd93STycho Nightingale 682bf21cd93STycho Nightingale /* 683*4c87aefeSPatrick Mooney * Take the softc lock to protect against concurrent 684*4c87aefeSPatrick Mooney * access from a vCPU i/o exit 685bf21cd93STycho Nightingale */ 686*4c87aefeSPatrick Mooney pthread_mutex_lock(&sc->mtx); 687bf21cd93STycho Nightingale 688*4c87aefeSPatrick Mooney if ((sc->mcr & MCR_LOOPBACK) != 0) { 689*4c87aefeSPatrick Mooney (void) read(sc->usc_sock.clifd, &ch, 1); 690*4c87aefeSPatrick Mooney } else { 691*4c87aefeSPatrick Mooney bool err_close = false; 692*4c87aefeSPatrick Mooney 693*4c87aefeSPatrick Mooney while (rxfifo_available(sc)) { 694bf21cd93STycho Nightingale int res; 695bf21cd93STycho Nightingale 696*4c87aefeSPatrick Mooney res = read(sc->usc_sock.clifd, &ch, 1); 697*4c87aefeSPatrick Mooney if (res == 0) { 698*4c87aefeSPatrick Mooney err_close = true; 699*4c87aefeSPatrick Mooney break; 700*4c87aefeSPatrick Mooney } else if (res == -1) { 701*4c87aefeSPatrick Mooney if (errno != EAGAIN && errno != EINTR) { 702*4c87aefeSPatrick Mooney err_close = true; 703*4c87aefeSPatrick Mooney } 704*4c87aefeSPatrick Mooney break; 705bf21cd93STycho Nightingale } 706bf21cd93STycho Nightingale 707*4c87aefeSPatrick Mooney rxfifo_putchar(sc, ch); 708*4c87aefeSPatrick Mooney } 709*4c87aefeSPatrick Mooney uart_toggle_intr(sc); 710*4c87aefeSPatrick Mooney 711*4c87aefeSPatrick Mooney if (err_close) { 712*4c87aefeSPatrick Mooney (void) fprintf(stderr, "uart: closing client conn\n"); 713*4c87aefeSPatrick Mooney (void) shutdown(sc->usc_sock.clifd, SHUT_RDWR); 714*4c87aefeSPatrick Mooney mevent_delete_close(sc->mev); 715*4c87aefeSPatrick Mooney sc->mev = NULL; 716*4c87aefeSPatrick Mooney sc->usc_sock.clifd = -1; 717*4c87aefeSPatrick Mooney } 718*4c87aefeSPatrick Mooney } 719*4c87aefeSPatrick Mooney 720*4c87aefeSPatrick Mooney pthread_mutex_unlock(&sc->mtx); 721bf21cd93STycho Nightingale } 722bf21cd93STycho Nightingale 723bf21cd93STycho Nightingale static void 724*4c87aefeSPatrick Mooney uart_sock_accept(int fd, enum ev_type ev, void *arg) 725bf21cd93STycho Nightingale { 726*4c87aefeSPatrick Mooney struct uart_softc *sc = arg; 727*4c87aefeSPatrick Mooney int connfd; 728bf21cd93STycho Nightingale 729*4c87aefeSPatrick Mooney connfd = accept(sc->usc_sock.servfd, NULL, NULL); 730*4c87aefeSPatrick Mooney if (connfd == -1) { 731bf21cd93STycho Nightingale return; 732bf21cd93STycho Nightingale } 733bf21cd93STycho Nightingale 734*4c87aefeSPatrick Mooney /* 735*4c87aefeSPatrick Mooney * Do client connection management under protection of the softc lock 736*4c87aefeSPatrick Mooney * to avoid racing with concurrent UART events. 737*4c87aefeSPatrick Mooney */ 738*4c87aefeSPatrick Mooney pthread_mutex_lock(&sc->mtx); 739bf21cd93STycho Nightingale 740*4c87aefeSPatrick Mooney if (sc->usc_sock.clifd != -1) { 741*4c87aefeSPatrick Mooney /* we're already handling a client */ 742*4c87aefeSPatrick Mooney (void) fprintf(stderr, "uart: unexpected client conn\n"); 743*4c87aefeSPatrick Mooney (void) shutdown(connfd, SHUT_RDWR); 744*4c87aefeSPatrick Mooney (void) close(connfd); 745bf21cd93STycho Nightingale } else { 746*4c87aefeSPatrick Mooney if (fcntl(connfd, F_SETFL, O_NONBLOCK) < 0) { 747*4c87aefeSPatrick Mooney perror("uart: fcntl(O_NONBLOCK)"); 748*4c87aefeSPatrick Mooney (void) shutdown(connfd, SHUT_RDWR); 749*4c87aefeSPatrick Mooney (void) close(connfd); 750bf21cd93STycho Nightingale } else { 751*4c87aefeSPatrick Mooney sc->usc_sock.clifd = connfd; 752*4c87aefeSPatrick Mooney sc->mev = mevent_add(sc->usc_sock.clifd, EVF_READ, 753*4c87aefeSPatrick Mooney uart_sock_drain, sc); 754bf21cd93STycho Nightingale } 755bf21cd93STycho Nightingale } 756bf21cd93STycho Nightingale 757*4c87aefeSPatrick Mooney pthread_mutex_unlock(&sc->mtx); 758bf21cd93STycho Nightingale } 759bf21cd93STycho Nightingale 760bf21cd93STycho Nightingale static int 761*4c87aefeSPatrick Mooney init_sock(const char *path) 762bf21cd93STycho Nightingale { 763bf21cd93STycho Nightingale int servfd; 764bf21cd93STycho Nightingale struct sockaddr_un servaddr; 765bf21cd93STycho Nightingale 766*4c87aefeSPatrick Mooney bzero(&servaddr, sizeof (servaddr)); 767*4c87aefeSPatrick Mooney servaddr.sun_family = AF_UNIX; 768*4c87aefeSPatrick Mooney 769*4c87aefeSPatrick Mooney if (strlcpy(servaddr.sun_path, path, sizeof (servaddr.sun_path)) >= 770*4c87aefeSPatrick Mooney sizeof (servaddr.sun_path)) { 771*4c87aefeSPatrick Mooney (void) fprintf(stderr, "uart: path '%s' too long\n", 772*4c87aefeSPatrick Mooney path); 773bf21cd93STycho Nightingale return (-1); 774bf21cd93STycho Nightingale } 775bf21cd93STycho Nightingale 776bf21cd93STycho Nightingale if ((servfd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { 777*4c87aefeSPatrick Mooney (void) fprintf(stderr, "uart: socket() error - %s\n", 778*4c87aefeSPatrick 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) { 785*4c87aefeSPatrick Mooney (void) fprintf(stderr, "uart: bind() error - %s\n", 786*4c87aefeSPatrick Mooney strerror(errno)); 787bf21cd93STycho Nightingale goto out; 788bf21cd93STycho Nightingale } 789bf21cd93STycho Nightingale 790*4c87aefeSPatrick Mooney if (listen(servfd, 1) == -1) { 791*4c87aefeSPatrick Mooney (void) fprintf(stderr, "uart: listen() error - %s\n", 792*4c87aefeSPatrick 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 } 802*4c87aefeSPatrick 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 824*4c87aefeSPatrick 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 837*4c87aefeSPatrick Mooney #ifndef __FreeBSD__ 838*4c87aefeSPatrick Mooney static int 839*4c87aefeSPatrick Mooney uart_sock_backend(struct uart_softc *sc, const char *inopts) 840*4c87aefeSPatrick Mooney { 841*4c87aefeSPatrick Mooney char *opts; 842*4c87aefeSPatrick Mooney char *opt; 843*4c87aefeSPatrick Mooney char *nextopt; 844*4c87aefeSPatrick Mooney char *path = NULL; 845*4c87aefeSPatrick Mooney 846*4c87aefeSPatrick Mooney if (strncmp(inopts, "socket,", 7) != 0) { 847*4c87aefeSPatrick Mooney return (-1); 848*4c87aefeSPatrick Mooney } 849*4c87aefeSPatrick Mooney if ((opts = strdup(inopts + 7)) == NULL) { 850*4c87aefeSPatrick Mooney return (-1); 851*4c87aefeSPatrick Mooney } 852*4c87aefeSPatrick Mooney 853*4c87aefeSPatrick Mooney nextopt = opts; 854*4c87aefeSPatrick Mooney for (opt = strsep(&nextopt, ","); opt != NULL; 855*4c87aefeSPatrick Mooney opt = strsep(&nextopt, ",")) { 856*4c87aefeSPatrick Mooney if (path == NULL && *opt == '/') { 857*4c87aefeSPatrick Mooney path = opt; 858*4c87aefeSPatrick Mooney continue; 859*4c87aefeSPatrick Mooney } 860*4c87aefeSPatrick Mooney /* 861*4c87aefeSPatrick Mooney * XXX check for server and client options here. For now, 862*4c87aefeSPatrick Mooney * everything is a server 863*4c87aefeSPatrick Mooney */ 864*4c87aefeSPatrick Mooney free(opts); 865*4c87aefeSPatrick Mooney return (-1); 866*4c87aefeSPatrick Mooney } 867*4c87aefeSPatrick Mooney 868*4c87aefeSPatrick Mooney sc->usc_sock.clifd = -1; 869*4c87aefeSPatrick Mooney if ((sc->usc_sock.servfd = init_sock(path)) == -1) { 870*4c87aefeSPatrick Mooney free(opts); 871*4c87aefeSPatrick Mooney return (-1); 872*4c87aefeSPatrick Mooney } 873*4c87aefeSPatrick Mooney sc->sock = true; 874*4c87aefeSPatrick Mooney sc->tty.rfd = sc->tty.wfd = -1; 875*4c87aefeSPatrick Mooney sc->usc_sock.servmev = mevent_add(sc->usc_sock.servfd, EVF_READ, 876*4c87aefeSPatrick Mooney uart_sock_accept, sc); 877*4c87aefeSPatrick Mooney assert(sc->usc_sock.servmev != NULL); 878*4c87aefeSPatrick Mooney 879*4c87aefeSPatrick Mooney return (0); 880*4c87aefeSPatrick Mooney } 881*4c87aefeSPatrick Mooney #endif /* not __FreeBSD__ */ 882*4c87aefeSPatrick Mooney 883*4c87aefeSPatrick Mooney static int 884*4c87aefeSPatrick Mooney uart_stdio_backend(struct uart_softc *sc) 885*4c87aefeSPatrick Mooney { 886*4c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM 887*4c87aefeSPatrick Mooney cap_rights_t rights; 888*4c87aefeSPatrick Mooney cap_ioctl_t cmds[] = { TIOCGETA, TIOCSETA, TIOCGWINSZ }; 889*4c87aefeSPatrick Mooney #endif 890*4c87aefeSPatrick Mooney 891*4c87aefeSPatrick Mooney if (uart_stdio) 892*4c87aefeSPatrick Mooney return (-1); 893*4c87aefeSPatrick Mooney 894*4c87aefeSPatrick Mooney sc->tty.rfd = STDIN_FILENO; 895*4c87aefeSPatrick Mooney sc->tty.wfd = STDOUT_FILENO; 896*4c87aefeSPatrick Mooney sc->tty.opened = true; 897*4c87aefeSPatrick Mooney 898*4c87aefeSPatrick Mooney if (fcntl(sc->tty.rfd, F_SETFL, O_NONBLOCK) != 0) 899*4c87aefeSPatrick Mooney return (-1); 900*4c87aefeSPatrick Mooney if (fcntl(sc->tty.wfd, F_SETFL, O_NONBLOCK) != 0) 901*4c87aefeSPatrick Mooney return (-1); 902*4c87aefeSPatrick Mooney 903*4c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM 904*4c87aefeSPatrick Mooney cap_rights_init(&rights, CAP_EVENT, CAP_IOCTL, CAP_READ); 905*4c87aefeSPatrick Mooney if (caph_rights_limit(sc->tty.rfd, &rights) == -1) 906*4c87aefeSPatrick Mooney errx(EX_OSERR, "Unable to apply rights for sandbox"); 907*4c87aefeSPatrick Mooney if (caph_ioctls_limit(sc->tty.rfd, cmds, nitems(cmds)) == -1) 908*4c87aefeSPatrick Mooney errx(EX_OSERR, "Unable to apply rights for sandbox"); 909*4c87aefeSPatrick Mooney #endif 910*4c87aefeSPatrick Mooney 911*4c87aefeSPatrick Mooney uart_stdio = true; 912*4c87aefeSPatrick Mooney 913*4c87aefeSPatrick Mooney return (0); 914*4c87aefeSPatrick Mooney } 915*4c87aefeSPatrick Mooney 916*4c87aefeSPatrick Mooney static int 917*4c87aefeSPatrick Mooney uart_tty_backend(struct uart_softc *sc, const char *opts) 918*4c87aefeSPatrick Mooney { 919*4c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM 920*4c87aefeSPatrick Mooney cap_rights_t rights; 921*4c87aefeSPatrick Mooney cap_ioctl_t cmds[] = { TIOCGETA, TIOCSETA, TIOCGWINSZ }; 922*4c87aefeSPatrick Mooney #endif 923*4c87aefeSPatrick Mooney int fd; 924*4c87aefeSPatrick Mooney 925*4c87aefeSPatrick Mooney fd = open(opts, O_RDWR | O_NONBLOCK); 926*4c87aefeSPatrick Mooney if (fd < 0 || !isatty(fd)) 927*4c87aefeSPatrick Mooney return (-1); 928*4c87aefeSPatrick Mooney 929*4c87aefeSPatrick Mooney sc->tty.rfd = sc->tty.wfd = fd; 930*4c87aefeSPatrick Mooney sc->tty.opened = true; 931*4c87aefeSPatrick Mooney 932*4c87aefeSPatrick Mooney #ifndef WITHOUT_CAPSICUM 933*4c87aefeSPatrick Mooney cap_rights_init(&rights, CAP_EVENT, CAP_IOCTL, CAP_READ, CAP_WRITE); 934*4c87aefeSPatrick Mooney if (caph_rights_limit(fd, &rights) == -1) 935*4c87aefeSPatrick Mooney errx(EX_OSERR, "Unable to apply rights for sandbox"); 936*4c87aefeSPatrick Mooney if (caph_ioctls_limit(fd, cmds, nitems(cmds)) == -1) 937*4c87aefeSPatrick Mooney errx(EX_OSERR, "Unable to apply rights for sandbox"); 938*4c87aefeSPatrick Mooney #endif 939*4c87aefeSPatrick Mooney 940*4c87aefeSPatrick Mooney return (0); 941*4c87aefeSPatrick Mooney } 942*4c87aefeSPatrick Mooney 943bf21cd93STycho Nightingale int 944bf21cd93STycho Nightingale uart_set_backend(struct uart_softc *sc, const char *opts) 945bf21cd93STycho Nightingale { 946*4c87aefeSPatrick Mooney int retval; 947*4c87aefeSPatrick Mooney 948bf21cd93STycho Nightingale if (opts == NULL) 949bf21cd93STycho Nightingale return (0); 950bf21cd93STycho Nightingale 951*4c87aefeSPatrick Mooney #ifndef __FreeBSD__ 952*4c87aefeSPatrick Mooney if (strncmp("socket,", opts, 7) == 0) 953*4c87aefeSPatrick Mooney return (uart_sock_backend(sc, opts)); 954bf21cd93STycho Nightingale #endif 955*4c87aefeSPatrick Mooney if (strcmp("stdio", opts) == 0) 956*4c87aefeSPatrick Mooney retval = uart_stdio_backend(sc); 957*4c87aefeSPatrick Mooney else 958*4c87aefeSPatrick Mooney retval = uart_tty_backend(sc, opts); 959*4c87aefeSPatrick Mooney if (retval == 0) 960*4c87aefeSPatrick Mooney uart_opentty(sc); 961*4c87aefeSPatrick Mooney 962*4c87aefeSPatrick Mooney return (retval); 963bf21cd93STycho Nightingale } 964